зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound on a CLOSED TREE
This commit is contained in:
Коммит
997a9dedca
|
@ -3017,7 +3017,6 @@ then
|
|||
esac
|
||||
LDFLAGS="${_PTHREAD_LDFLAGS} ${LDFLAGS}"
|
||||
AC_SUBST(MOZ_USE_PTHREADS)
|
||||
MOZ_CHECK_HEADERS(pthread.h)
|
||||
fi
|
||||
|
||||
|
||||
|
|
|
@ -262,14 +262,6 @@ DOMInterfaces = {
|
|||
'concrete': False
|
||||
},
|
||||
|
||||
'ChromeUtils': {
|
||||
# The codegen is dumb, and doesn't understand that this interface is only a
|
||||
# collection of static methods, so we have this `concrete: False` hack.
|
||||
'concrete': False,
|
||||
'nativeType': 'mozilla::devtools::ChromeUtils',
|
||||
'implicitJSContext': ['readHeapSnapshot', 'saveHeapSnapshot']
|
||||
},
|
||||
|
||||
'ChromeWindow': {
|
||||
'concrete': False,
|
||||
},
|
||||
|
@ -501,10 +493,6 @@ DOMInterfaces = {
|
|||
'headerFile': 'nsGeolocation.h'
|
||||
},
|
||||
|
||||
'HeapSnapshot': {
|
||||
'nativeType': 'mozilla::devtools::HeapSnapshot'
|
||||
},
|
||||
|
||||
'History': {
|
||||
'headerFile': 'nsHistory.h',
|
||||
'nativeType': 'nsHistory'
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A collection of static utility methods that are only exposed to Chrome.
|
||||
*/
|
||||
[ChromeOnly, Exposed=(Window,System)]
|
||||
interface ChromeUtils {
|
||||
/**
|
||||
* Serialize a snapshot of the heap graph, as seen by |JS::ubi::Node| and
|
||||
* restricted by |boundaries|, and write it to the provided file path.
|
||||
*
|
||||
* @param filePath The file path to write the heap snapshot to.
|
||||
*
|
||||
* @param boundaries The portion of the heap graph to write.
|
||||
*/
|
||||
[Throws]
|
||||
static void saveHeapSnapshot(DOMString filePath,
|
||||
optional HeapSnapshotBoundaries boundaries);
|
||||
|
||||
/**
|
||||
* Deserialize a core dump into a HeapSnapshot.
|
||||
*
|
||||
* @param filePath The file path to read the core dump from.
|
||||
*/
|
||||
[Throws, NewObject]
|
||||
static HeapSnapshot readHeapSnapshot(DOMString filePath);
|
||||
};
|
||||
|
||||
/**
|
||||
* A JS object whose properties specify what portion of the heap graph to
|
||||
* write. The recognized properties are:
|
||||
*
|
||||
* * globals: [ global, ... ]
|
||||
* Dump only nodes that either:
|
||||
* - belong in the compartment of one of the given globals;
|
||||
* - belong to no compartment, but do belong to a Zone that contains one of
|
||||
* the given globals;
|
||||
* - are referred to directly by one of the last two kinds of nodes; or
|
||||
* - is the fictional root node, described below.
|
||||
*
|
||||
* * debugger: Debugger object
|
||||
* Like "globals", but use the Debugger's debuggees as the globals.
|
||||
*
|
||||
* * runtime: true
|
||||
* Dump the entire heap graph, starting with the JSRuntime's roots.
|
||||
*
|
||||
* One, and only one, of these properties must exist on the boundaries object.
|
||||
*
|
||||
* The root of the dumped graph is a fictional node whose ubi::Node type name is
|
||||
* "CoreDumpRoot". If we are dumping the entire ubi::Node graph, this root node
|
||||
* has an edge for each of the JSRuntime's roots. If we are dumping a selected
|
||||
* set of globals, the root has an edge to each global, and an edge for each
|
||||
* incoming JS reference to the selected Zones.
|
||||
*/
|
||||
dictionary HeapSnapshotBoundaries {
|
||||
sequence<object> globals;
|
||||
object debugger;
|
||||
boolean runtime;
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A HeapSnapshot represents a snapshot of the heap graph
|
||||
*/
|
||||
[ChromeOnly, Exposed=(Window,System)]
|
||||
interface HeapSnapshot {
|
||||
};
|
|
@ -73,7 +73,6 @@ WEBIDL_FILES = [
|
|||
'CharacterData.webidl',
|
||||
'ChildNode.webidl',
|
||||
'ChromeNotifications.webidl',
|
||||
'ChromeUtils.webidl',
|
||||
'Client.webidl',
|
||||
'Clients.webidl',
|
||||
'ClipboardEvent.webidl',
|
||||
|
@ -158,7 +157,6 @@ WEBIDL_FILES = [
|
|||
'GetUserMediaRequest.webidl',
|
||||
'HDMIInputPort.webidl',
|
||||
'Headers.webidl',
|
||||
'HeapSnapshot.webidl',
|
||||
'History.webidl',
|
||||
'HTMLAllCollection.webidl',
|
||||
'HTMLAnchorElement.webidl',
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -262,13 +262,7 @@ class BuilderOrigin : public Builder {
|
|||
|
||||
// Tell Debuggers in |runtime| to use |mallocSizeOf| to find the size of
|
||||
// malloc'd blocks.
|
||||
JS_PUBLIC_API(void)
|
||||
SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
// Get the MallocSizeOf function that the given runtime is using to find the
|
||||
// size of malloc'd blocks.
|
||||
JS_PUBLIC_API(mozilla::MallocSizeOf)
|
||||
GetDebuggerMallocSizeOf(JSRuntime* runtime);
|
||||
void SetDebuggerMallocSizeOf(JSRuntime* runtime, mozilla::MallocSizeOf mallocSizeOf);
|
||||
|
||||
|
||||
|
||||
|
@ -322,12 +316,7 @@ onPromiseSettled(JSContext* cx, HandleObject promise);
|
|||
|
||||
// Return true if the given value is a Debugger object, false otherwise.
|
||||
JS_PUBLIC_API(bool)
|
||||
IsDebugger(const JSObject& obj);
|
||||
|
||||
// Append each of the debuggee global objects observed by the Debugger object
|
||||
// |dbgObj| to |vector|. Returns true on success, false on failure.
|
||||
JS_PUBLIC_API(bool)
|
||||
GetDebuggeeGlobals(JSContext* cx, const JSObject& dbgObj, AutoObjectVector& vector);
|
||||
IsDebugger(JS::Value val);
|
||||
|
||||
} // namespace dbg
|
||||
} // namespace JS
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "jspubtd.h"
|
||||
|
||||
|
@ -93,7 +92,7 @@
|
|||
// represented by a "rope", a structure that points to the two original
|
||||
// strings.
|
||||
//
|
||||
//
|
||||
|
||||
// We intend to use ubi::Node to write tools that report memory usage, so it's
|
||||
// important that ubi::Node accurately portray how much memory nodes consume.
|
||||
// Thus, for example, when data that apparently belongs to multiple nodes is
|
||||
|
@ -142,23 +141,11 @@
|
|||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
using mozilla::Maybe;
|
||||
|
||||
class Edge;
|
||||
class EdgeRange;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
template<>
|
||||
class DefaultDelete<JS::ubi::EdgeRange> : public JS::DeletePolicy<JS::ubi::EdgeRange> { };
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
namespace ubi {
|
||||
|
||||
using mozilla::Maybe;
|
||||
using mozilla::UniquePtr;
|
||||
|
||||
// The base class implemented by each ubi::Node referent type. Subclasses must
|
||||
// not add data members to this class.
|
||||
class Base {
|
||||
|
@ -187,26 +174,6 @@ class Base {
|
|||
}
|
||||
bool operator!=(const Base& rhs) const { return !(*this == rhs); }
|
||||
|
||||
// An identifier for this node, guaranteed to be stable and unique for as
|
||||
// long as this ubi::Node's referent is alive and at the same address.
|
||||
//
|
||||
// This is probably suitable for use in serializations, as it is an integral
|
||||
// type. It may also help save memory when constructing HashSets of
|
||||
// ubi::Nodes: since a uintptr_t will always be smaller than a ubi::Node, a
|
||||
// HashSet<ubi::Node::Id> will use less space per element than a
|
||||
// HashSet<ubi::Node>.
|
||||
//
|
||||
// (Note that 'unique' only means 'up to equality on ubi::Node'; see the
|
||||
// caveats about multiple objects allocated at the same address for
|
||||
// 'ubi::Node::operator=='.)
|
||||
typedef uintptr_t Id;
|
||||
virtual Id identifier() const { return reinterpret_cast<Id>(ptr); }
|
||||
|
||||
// Returns true if this node is pointing to something on the live heap, as
|
||||
// opposed to something from a deserialized core dump. Returns false,
|
||||
// otherwise.
|
||||
virtual bool isLive() const { return true; };
|
||||
|
||||
// Return a human-readable name for the referent's type. The result should
|
||||
// be statically allocated. (You can use MOZ_UTF16("strings") for this.)
|
||||
//
|
||||
|
@ -221,11 +188,13 @@ class Base {
|
|||
virtual size_t size(mozilla::MallocSizeOf mallocSizeof) const { return 0; }
|
||||
|
||||
// Return an EdgeRange that initially contains all the referent's outgoing
|
||||
// edges. The caller takes ownership of the EdgeRange.
|
||||
// edges. The EdgeRange should be freed with 'js_delete'. (You could use
|
||||
// ScopedDJSeletePtr<EdgeRange> to manage it.) On OOM, report an exception
|
||||
// on |cx| and return nullptr.
|
||||
//
|
||||
// If wantNames is true, compute names for edges. Doing so can be expensive
|
||||
// in time and memory.
|
||||
virtual UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const = 0;
|
||||
virtual EdgeRange* edges(JSContext* cx, bool wantNames) const = 0;
|
||||
|
||||
// Return the Zone to which this node's referent belongs, or nullptr if the
|
||||
// referent is not of a type allocated in SpiderMonkey Zones.
|
||||
|
@ -271,8 +240,8 @@ struct Concrete {
|
|||
static void construct(void* storage, Referent* referent);
|
||||
};
|
||||
|
||||
// A container for a Base instance; all members simply forward to the contained
|
||||
// instance. This container allows us to pass ubi::Node instances by value.
|
||||
// A container for a Base instance; all members simply forward to the contained instance.
|
||||
// This container allows us to pass ubi::Node instances by value.
|
||||
class Node {
|
||||
// Storage in which we allocate Base subclasses.
|
||||
mozilla::AlignedStorage2<Base> storage;
|
||||
|
@ -341,8 +310,6 @@ class Node {
|
|||
return base()->ptr != nullptr;
|
||||
}
|
||||
|
||||
bool isLive() const { return base()->isLive(); }
|
||||
|
||||
template<typename T>
|
||||
bool is() const {
|
||||
return base()->typeName() == Concrete<T>::concreteTypeName;
|
||||
|
@ -350,14 +317,12 @@ class Node {
|
|||
|
||||
template<typename T>
|
||||
T* as() const {
|
||||
MOZ_ASSERT(isLive());
|
||||
MOZ_ASSERT(is<T>());
|
||||
return static_cast<T*>(base()->ptr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* asOrNull() const {
|
||||
MOZ_ASSERT(isLive());
|
||||
return is<T>() ? static_cast<T*>(base()->ptr) : nullptr;
|
||||
}
|
||||
|
||||
|
@ -376,13 +341,10 @@ class Node {
|
|||
return base()->size(mallocSizeof);
|
||||
}
|
||||
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames = true) const {
|
||||
EdgeRange* edges(JSContext* cx, bool wantNames = true) const {
|
||||
return base()->edges(cx, wantNames);
|
||||
}
|
||||
|
||||
typedef Base::Id Id;
|
||||
Id identifier() const { return base()->identifier(); }
|
||||
|
||||
// A hash policy for ubi::Nodes.
|
||||
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
|
||||
// We specialize DefaultHasher below to make this the default.
|
||||
|
@ -502,33 +464,6 @@ class SimpleEdge : public Edge {
|
|||
|
||||
typedef mozilla::Vector<SimpleEdge, 8, js::TempAllocPolicy> SimpleEdgeVector;
|
||||
|
||||
// An EdgeRange concrete class that holds a pre-existing vector of
|
||||
// SimpleEdges. A PreComputedEdgeRange does not take ownership of its
|
||||
// SimpleEdgeVector; it is up to the PreComputedEdgeRange's consumer to manage
|
||||
// that lifetime.
|
||||
class PreComputedEdgeRange : public EdgeRange {
|
||||
SimpleEdgeVector& edges;
|
||||
size_t i;
|
||||
|
||||
void settle() {
|
||||
front_ = i < edges.length() ? &edges[i] : nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit PreComputedEdgeRange(JSContext* cx, SimpleEdgeVector& edges)
|
||||
: edges(edges),
|
||||
i(0)
|
||||
{
|
||||
settle();
|
||||
}
|
||||
|
||||
void popFront() override {
|
||||
MOZ_ASSERT(!empty());
|
||||
i++;
|
||||
settle();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// RootList is a class that can be pointed to by a |ubi::Node|, creating a
|
||||
// fictional root-of-roots which has edges to every GC root in the JS
|
||||
|
@ -575,10 +510,6 @@ class MOZ_STACK_CLASS RootList {
|
|||
// Find only GC roots in the given Debugger object's set of debuggee zones.
|
||||
bool init(HandleObject debuggees);
|
||||
|
||||
// Returns true if the RootList has been initialized successfully, false
|
||||
// otherwise.
|
||||
bool initialized() { return noGC.isSome(); }
|
||||
|
||||
// Explicitly add the given Node as a root in this RootList. If wantNames is
|
||||
// true, you must pass an edgeName. The RootList does not take ownership of
|
||||
// edgeName.
|
||||
|
@ -590,7 +521,7 @@ class MOZ_STACK_CLASS RootList {
|
|||
|
||||
template<>
|
||||
struct Concrete<RootList> : public Base {
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
|
||||
EdgeRange* edges(JSContext* cx, bool wantNames) const override;
|
||||
const char16_t* typeName() const override { return concreteTypeName; }
|
||||
|
||||
protected:
|
||||
|
@ -607,7 +538,7 @@ struct Concrete<RootList> : public Base {
|
|||
template<typename Referent>
|
||||
class TracerConcrete : public Base {
|
||||
const char16_t* typeName() const override { return concreteTypeName; }
|
||||
UniquePtr<EdgeRange> edges(JSContext*, bool wantNames) const override;
|
||||
EdgeRange* edges(JSContext*, bool wantNames) const override;
|
||||
JS::Zone* zone() const override;
|
||||
|
||||
protected:
|
||||
|
@ -660,7 +591,7 @@ template<>
|
|||
class Concrete<void> : public Base {
|
||||
const char16_t* typeName() const override;
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
|
||||
EdgeRange* edges(JSContext* cx, bool wantNames) const override;
|
||||
JS::Zone* zone() const override;
|
||||
JSCompartment* compartment() const override;
|
||||
|
||||
|
|
|
@ -120,13 +120,13 @@ struct BreadthFirst {
|
|||
MOZ_ASSERT(!traversalBegun);
|
||||
traversalBegun = true;
|
||||
|
||||
// While there are pending nodes, visit them.
|
||||
// While there are pending nodes, visit them, until we've found a path to the target.
|
||||
while (!pending.empty()) {
|
||||
Node origin = pending.front();
|
||||
pending.popFront();
|
||||
|
||||
// Get a range containing all origin's outgoing edges.
|
||||
auto range = origin.edges(cx, wantNames);
|
||||
js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx, wantNames));
|
||||
if (!range)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ var ignoreIndirectCalls = {
|
|||
"__conv" : true,
|
||||
"__convf" : true,
|
||||
"prerrortable.c:callback_newtable" : true,
|
||||
"mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
|
||||
"mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true
|
||||
};
|
||||
|
||||
function indirectCallCannotGC(fullCaller, fullVariable)
|
||||
|
@ -174,34 +174,8 @@ var ignoreFunctions = {
|
|||
// And these are workarounds to avoid even more analysis work,
|
||||
// which would sadly still be needed even with bug 898815.
|
||||
"void js::AutoCompartment::AutoCompartment(js::ExclusiveContext*, JSCompartment*)": true,
|
||||
|
||||
// Similar to heap snapshot mock classes, and GTests below. This posts a
|
||||
// synchronous runnable when a GTest fails, and we are pretty sure that the
|
||||
// particular runnable it posts can't even GC, but the analysis isn't
|
||||
// currently smart enough to determine that. In either case, this is (a)
|
||||
// only in GTests, and (b) only when the Gtest has already failed. We have
|
||||
// static and dynamic checks for no GC in the non-test code, and in the test
|
||||
// code we fall back to only the dynamic checks.
|
||||
"void test::RingbufferDumper::OnTestPartResult(testing::TestPartResult*)" : true,
|
||||
};
|
||||
|
||||
function isProtobuf(name)
|
||||
{
|
||||
return name.match(/\bgoogle::protobuf\b/) ||
|
||||
name.match(/\bmozilla::devtools::protobuf\b/);
|
||||
}
|
||||
|
||||
function isHeapSnapshotMockClass(name)
|
||||
{
|
||||
return name.match(/\bMockWriter\b/) ||
|
||||
name.match(/\bMockDeserializedNode\b/);
|
||||
}
|
||||
|
||||
function isGTest(name)
|
||||
{
|
||||
return name.match(/\btesting::/);
|
||||
}
|
||||
|
||||
function ignoreGCFunction(mangled)
|
||||
{
|
||||
assert(mangled in readableNames);
|
||||
|
@ -210,23 +184,6 @@ function ignoreGCFunction(mangled)
|
|||
if (fun in ignoreFunctions)
|
||||
return true;
|
||||
|
||||
// The protobuf library, and [de]serialization code generated by the
|
||||
// protobuf compiler, uses a _ton_ of function pointers but they are all
|
||||
// internal. Easiest to just ignore that mess here.
|
||||
if (isProtobuf(fun))
|
||||
return true;
|
||||
|
||||
// Ignore anything that goes through heap snapshot GTests or mocked classes
|
||||
// used in heap snapshot GTests. GTest and GMock expose a lot of virtual
|
||||
// methods and function pointers that could potentially GC after an
|
||||
// assertion has already failed (depending on user-provided code), but don't
|
||||
// exhibit that behavior currently. For non-test code, we have dynamic and
|
||||
// static checks that ensure we don't GC. However, for test code we opt out
|
||||
// of static checks here, because of the above stated GMock/GTest issues,
|
||||
// and rely on only the dynamic checks provided by AutoAssertCannotGC.
|
||||
if (isHeapSnapshotMockClass(fun) || isGTest(fun))
|
||||
return true;
|
||||
|
||||
// Templatized function
|
||||
if (fun.indexOf("void nsCOMPtr<T>::Assert_NoQueryNeeded()") >= 0)
|
||||
return true;
|
||||
|
|
|
@ -31,12 +31,6 @@ allocated, if:
|
|||
- <code><i>dbg</i>.memory.[trackingAllocationSites][tracking-allocs]</code> is
|
||||
set to `true`.
|
||||
|
||||
- A [Bernoulli trial][bernoulli-trial] succeeds, with probability equal to the
|
||||
maximum of
|
||||
[`d.memory.allocationSamplingProbability`][alloc-sampling-probability] of all
|
||||
`Debugger` instances `d` that are observing the global that this object is
|
||||
allocated within the scope of.
|
||||
|
||||
Given a [`Debugger.Object`][object] instance <i>dobj</i> referring to some
|
||||
object, <code><i>dobj</i>.[allocationSite][allocation-site]</code> returns a
|
||||
[saved call stack][saved-frame] indicating where <i>dobj</i>'s referent was
|
||||
|
@ -86,18 +80,6 @@ following accessor properties from its prototype:
|
|||
[`Debugger.Object.prototype.allocationSite`][allocation-site] accessor
|
||||
property.
|
||||
|
||||
<code id='alloc-sampling-probability'>allocationSamplingProbability</code>
|
||||
: A number between 0 and 1 that indicates the probability with which each new
|
||||
allocation should be entered into the allocations log. 0 is equivalent to
|
||||
"never", 1 is "always", and .05 would be "one out of twenty".
|
||||
|
||||
The default is 1, or logging every allocation.
|
||||
|
||||
Note that in the presence of multiple <code>Debugger</code> instances
|
||||
observing the same allocations within a global's scope, the maximum
|
||||
<code>allocationSamplingProbability</code> of all the
|
||||
<code>Debugger</code>s is used.
|
||||
|
||||
<code id='max-alloc-log'>maxAllocationsLogLength</code>
|
||||
: The maximum number of allocation sites to accumulate in the allocations log
|
||||
at a time. This accessor can be both fetched and stored to. Its default
|
||||
|
|
|
@ -39,12 +39,11 @@ markdown Debugger.Source.md Debugger-API/Debugger.Source
|
|||
label 'source' "Debugger.Source"
|
||||
|
||||
markdown Debugger.Memory.md Debugger-API/Debugger.Memory
|
||||
label 'memory' "Debugger.Memory"
|
||||
label 'tracking-allocs' '#trackingallocationsites' "Debugger.Memory: trackingAllocationSites"
|
||||
label 'drain-alloc-log' '#drain-alloc-log' "Debugger.Memory: drainAllocationsLog"
|
||||
label 'max-alloc-log' '#max-alloc-log' "Debugger.Memory: maxAllocationsLogLength"
|
||||
label 'alloc-sampling-probability' '#alloc-sampling-probability' "Debugger.Memory: allocationSamplingProbability"
|
||||
label 'take-census' '#take-census' "Debugger.Memory: takeCensus"
|
||||
label 'memory' "Debugger.Memory"
|
||||
label 'tracking-allocs' '#trackingallocationsites' "Debugger.Memory: trackingAllocationSites"
|
||||
label 'drain-alloc-log' '#drain-alloc-log' "Debugger.Memory: drainAllocationsLog"
|
||||
label 'max-alloc-log' '#max-alloc-log' "Debugger.Memory: maxAllocationsLogLength"
|
||||
label 'take-census' '#take-census' "Debugger.Memory: takeCensus"
|
||||
|
||||
markdown Tutorial-Debugger-Statement.md Debugger-API/Tutorial-Debugger-Statement
|
||||
label 'tut debugger' "Tutorial: the debugger; statement"
|
||||
|
@ -63,4 +62,3 @@ resource 'img-alloc-plot' alloc-plot-console.png $RBASE/8461
|
|||
# External links:
|
||||
absolute-label 'protocol' https://wiki.mozilla.org/Remote_Debugging_Protocol "Remote Debugging Protocol"
|
||||
absolute-label 'saved-frame' https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/SavedFrame "SavedFrame"
|
||||
absolute-label 'bernoulli-trial' https://en.wikipedia.org/wiki/Bernoulli_trial "Bernoulli Trial"
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
// Test that multiple Debuggers behave reasonably.
|
||||
// Test that multiple Debuggers behave reasonably. Since we're not keeping a
|
||||
// per-compartment count of how many Debuggers have requested allocation
|
||||
// tracking, assert that attempts to request allocation tracking from multiple
|
||||
// debuggers throws.
|
||||
|
||||
load(libdir + "asserts.js");
|
||||
|
||||
let dbg1, dbg2, root1, root2;
|
||||
let root1 = newGlobal();
|
||||
let root2 = newGlobal();
|
||||
|
||||
function FakeMetadata() {}
|
||||
let dbg1 = new Debugger();
|
||||
let dbg2 = new Debugger();
|
||||
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
let d2r1 = dbg2.addDebuggee(root1);
|
||||
|
||||
let wrappedObj, allocationSite;
|
||||
|
||||
function isTrackingAllocations(global, dbgObj) {
|
||||
const site = dbgObj.makeDebuggeeValue(global.eval("({})")).allocationSite;
|
||||
|
@ -14,94 +24,41 @@ function isTrackingAllocations(global, dbgObj) {
|
|||
return !!site;
|
||||
}
|
||||
|
||||
function test(name, fn) {
|
||||
print();
|
||||
print(name);
|
||||
// Can't track allocations if a different debugger is already tracking them.
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
assertThrowsInstanceOf(() => dbg2.memory.trackingAllocationSites = true,
|
||||
Error);
|
||||
|
||||
// Reset state.
|
||||
root1 = newGlobal();
|
||||
root2 = newGlobal();
|
||||
dbg1 = new Debugger;
|
||||
dbg2 = new Debugger;
|
||||
// Removing root as a debuggee from dbg1 should disable the allocation hook.
|
||||
dbg1.removeDebuggee(root1);
|
||||
assertEq(isTrackingAllocations(root1, d1r1), false);
|
||||
|
||||
// Run the test.
|
||||
fn();
|
||||
// Tracking allocations in dbg2 should work now that dbg1 isn't debugging root1.
|
||||
dbg2.memory.trackingAllocationSites = true;
|
||||
assertEq(isTrackingAllocations(root1, d2r1), true);
|
||||
|
||||
print(" OK");
|
||||
}
|
||||
// Adding root back as a debuggee in dbg1 should fail now because it will
|
||||
// attempt to track allocations in root, but dbg2 is already doing that.
|
||||
assertThrowsInstanceOf(() => dbg1.addDebuggee(root1),
|
||||
Error);
|
||||
assertEq(dbg1.hasDebuggee(root1), false);
|
||||
|
||||
test("Can track allocations even if a different debugger is already tracking " +
|
||||
"them.",
|
||||
() => {
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
let d2r1 = dbg2.addDebuggee(root1);
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
dbg2.memory.trackingAllocationSites = true;
|
||||
assertEq(isTrackingAllocations(root1, d1r1), true);
|
||||
assertEq(isTrackingAllocations(root1, d2r1), true);
|
||||
});
|
||||
// Adding a new debuggee to a debugger that is tracking allocations should
|
||||
// enable the hook for the new debuggee.
|
||||
dbg2.removeDebuggee(root1);
|
||||
d1r1 = dbg1.addDebuggee(root1);
|
||||
assertEq(isTrackingAllocations(root1, d1r1), true);
|
||||
|
||||
test("Removing root1 as a debuggee from all debuggers should disable the " +
|
||||
"allocation hook.",
|
||||
() => {
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
dbg1.removeAllDebuggees();
|
||||
assertEq(isTrackingAllocations(root1, d1r1), false);
|
||||
});
|
||||
// Setting trackingAllocationSites to true should throw if the debugger cannot
|
||||
// install the allocation hooks for *every* debuggee.
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
dbg1.addDebuggee(root1);
|
||||
dbg2.memory.trackingAllocationSites = false;
|
||||
let d2r2 = dbg2.addDebuggee(root2);
|
||||
dbg2.addDebuggee(root1);
|
||||
assertThrowsInstanceOf(() => dbg2.memory.trackingAllocationSites = true,
|
||||
Error);
|
||||
|
||||
test("Adding a new debuggee to a debugger that is tracking allocations should " +
|
||||
"enable the hook for the new debuggee.",
|
||||
() => {
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
assertEq(isTrackingAllocations(root1, d1r1), true);
|
||||
});
|
||||
|
||||
test("Setting trackingAllocationSites to true should throw if the debugger " +
|
||||
"cannot install the allocation hooks for *every* debuggee.",
|
||||
() => {
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
let d1r2 = dbg1.addDebuggee(root2);
|
||||
|
||||
// Can't install allocation hooks for root2 with this set.
|
||||
root2.setObjectMetadataCallback(function () { return new FakeMetadata; });
|
||||
|
||||
assertThrowsInstanceOf(() => dbg1.memory.trackingAllocationSites = true,
|
||||
Error);
|
||||
|
||||
// And after it throws, its trackingAllocationSites accessor should reflect that
|
||||
// allocation site tracking is still disabled in that Debugger.
|
||||
assertEq(dbg1.memory.trackingAllocationSites, false);
|
||||
assertEq(isTrackingAllocations(root1, d1r1), false);
|
||||
assertEq(isTrackingAllocations(root2, d1r2), false);
|
||||
});
|
||||
|
||||
test("A Debugger isn't tracking allocation sites when disabled.",
|
||||
() => {
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
|
||||
assertEq(isTrackingAllocations(root1, d1r1), true);
|
||||
dbg1.enabled = false;
|
||||
assertEq(isTrackingAllocations(root1, d1r1), false);
|
||||
});
|
||||
|
||||
test("Re-enabling throws an error if we can't reinstall allocations tracking " +
|
||||
"for all debuggees.",
|
||||
() => {
|
||||
dbg1.enabled = false
|
||||
dbg1.memory.trackingAllocationSites = true;
|
||||
let d1r1 = dbg1.addDebuggee(root1);
|
||||
let d1r2 = dbg1.addDebuggee(root2);
|
||||
|
||||
// Can't install allocation hooks for root2 with this set.
|
||||
root2.setObjectMetadataCallback(function () { return new FakeMetadata; });
|
||||
|
||||
assertThrowsInstanceOf(() => dbg1.enabled = true,
|
||||
Error);
|
||||
|
||||
assertEq(dbg1.enabled, false);
|
||||
assertEq(isTrackingAllocations(root1, d1r1), false);
|
||||
assertEq(isTrackingAllocations(root2, d1r2), false);
|
||||
});
|
||||
// And after it throws, its trackingAllocationSites accessor should reflect that
|
||||
// allocation site tracking is still disabled in that Debugger.
|
||||
assertEq(isTrackingAllocations(root2, d2r2), false);
|
||||
|
|
|
@ -435,7 +435,6 @@ struct JSCompartment
|
|||
void fixupGlobal();
|
||||
|
||||
bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
|
||||
js::ObjectMetadataCallback getObjectMetadataCallback() const { return objectMetadataCallback; }
|
||||
void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
|
||||
void forgetObjectMetadataCallback() {
|
||||
objectMetadataCallback = nullptr;
|
||||
|
|
|
@ -295,12 +295,6 @@ js::IsAtomsCompartment(JSCompartment* comp)
|
|||
return comp->runtimeFromAnyThread()->isAtomsCompartment(comp);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::IsAtomsZone(JS::Zone* zone)
|
||||
{
|
||||
return zone->runtimeFromAnyThread()->isAtomsZone(zone);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::IsInNonStrictPropertySet(JSContext* cx)
|
||||
{
|
||||
|
|
|
@ -473,9 +473,6 @@ IsSystemZone(JS::Zone* zone);
|
|||
extern JS_FRIEND_API(bool)
|
||||
IsAtomsCompartment(JSCompartment* comp);
|
||||
|
||||
extern JS_FRIEND_API(bool)
|
||||
IsAtomsZone(JS::Zone* zone);
|
||||
|
||||
/*
|
||||
* Returns whether we're in a non-strict property set (in that we're in a
|
||||
* non-strict script and the bytecode we're on is a property set). The return
|
||||
|
|
|
@ -27,7 +27,7 @@ js::Debugger::onLeaveFrame(JSContext* cx, AbstractFramePtr frame, bool ok)
|
|||
}
|
||||
|
||||
/* static */ inline js::Debugger*
|
||||
js::Debugger::fromJSObject(const JSObject* obj)
|
||||
js::Debugger::fromJSObject(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectClass(obj) == &jsclass);
|
||||
return (Debugger*) obj->as<NativeObject>().getPrivate();
|
||||
|
|
|
@ -1659,8 +1659,6 @@ bool
|
|||
Debugger::appendAllocationSite(JSContext* cx, HandleObject obj, HandleSavedFrame frame,
|
||||
int64_t when)
|
||||
{
|
||||
MOZ_ASSERT(trackingAllocationSites);
|
||||
|
||||
AutoCompartment ac(cx, object);
|
||||
RootedObject wrappedFrame(cx, frame);
|
||||
if (!cx->compartment()->wrap(cx, &wrappedFrame))
|
||||
|
@ -2130,96 +2128,6 @@ Debugger::updateObservesAsmJSOnDebuggees(IsObserving observing)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*** Allocations Tracking *************************************************************************/
|
||||
|
||||
/* static */ bool
|
||||
Debugger::cannotTrackAllocations(const GlobalObject& global)
|
||||
{
|
||||
auto existingCallback = global.compartment()->getObjectMetadataCallback();
|
||||
return existingCallback && existingCallback != SavedStacksMetadataCallback;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Debugger::isObservedByDebuggerTrackingAllocations(const GlobalObject& debuggee)
|
||||
{
|
||||
if (auto* v = debuggee.getDebuggers()) {
|
||||
Debugger** p;
|
||||
for (p = v->begin(); p != v->end(); p++) {
|
||||
if ((*p)->trackingAllocationSites) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Debugger::addAllocationsTracking(JSContext* cx, GlobalObject& debuggee)
|
||||
{
|
||||
// Precondition: the given global object is being observed by at least one
|
||||
// Debugger that is tracking allocations.
|
||||
MOZ_ASSERT(isObservedByDebuggerTrackingAllocations(debuggee));
|
||||
|
||||
if (Debugger::cannotTrackAllocations(debuggee)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
|
||||
return false;
|
||||
}
|
||||
|
||||
debuggee.compartment()->setObjectMetadataCallback(SavedStacksMetadataCallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
Debugger::removeAllocationsTracking(GlobalObject& global)
|
||||
{
|
||||
// If there are still Debuggers that are observing allocations, we cannot
|
||||
// remove the metadata callback yet.
|
||||
if (isObservedByDebuggerTrackingAllocations(global))
|
||||
return;
|
||||
|
||||
global.compartment()->forgetObjectMetadataCallback();
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::addAllocationsTrackingForAllDebuggees(JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(trackingAllocationSites);
|
||||
|
||||
// We don't want to end up in a state where we added allocations
|
||||
// tracking to some of our debuggees, but failed to do so for
|
||||
// others. Before attempting to start tracking allocations in *any* of
|
||||
// our debuggees, ensure that we will be able to track allocations for
|
||||
// *all* of our debuggees.
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
if (Debugger::cannotTrackAllocations(*r.front().get())) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
// This should always succeed, since we already checked for the
|
||||
// error case above.
|
||||
MOZ_ALWAYS_TRUE(Debugger::addAllocationsTracking(cx, *r.front().get()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::removeAllocationsTrackingForAllDebuggees()
|
||||
{
|
||||
for (WeakGlobalObjectSet::Range r = debuggees.all(); !r.empty(); r.popFront()) {
|
||||
Debugger::removeAllocationsTracking(*r.front().get());
|
||||
}
|
||||
emptyAllocationsLog();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*** Debugger JSObjects **************************************************************************/
|
||||
|
||||
|
@ -2557,17 +2465,6 @@ Debugger::setEnabled(JSContext* cx, unsigned argc, Value* vp)
|
|||
dbg->enabled = ToBoolean(args[0]);
|
||||
|
||||
if (wasEnabled != dbg->enabled) {
|
||||
if (dbg->trackingAllocationSites) {
|
||||
if (wasEnabled) {
|
||||
dbg->removeAllocationsTrackingForAllDebuggees();
|
||||
} else {
|
||||
if (!dbg->addAllocationsTrackingForAllDebuggees(cx)) {
|
||||
dbg->enabled = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Breakpoint* bp = dbg->firstBreakpoint(); bp; bp = bp->nextInDebugger()) {
|
||||
if (!wasEnabled)
|
||||
bp->site->inc(cx->runtime()->defaultFreeOp());
|
||||
|
@ -3155,14 +3052,28 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are tracking allocation sites, we need to add the object metadata
|
||||
* callback to this debuggee compartment.
|
||||
*/
|
||||
bool setMetadataCallback = false;
|
||||
if (trackingAllocationSites) {
|
||||
if (debuggeeCompartment->hasObjectMetadataCallback()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
|
||||
return false;
|
||||
}
|
||||
|
||||
debuggeeCompartment->setObjectMetadataCallback(SavedStacksMetadataCallback);
|
||||
setMetadataCallback = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* For global to become this js::Debugger's debuggee:
|
||||
* - global must be in this->debuggees,
|
||||
* - this js::Debugger must be in global->getDebuggers(), and
|
||||
* - JSCompartment::isDebuggee()'s bit must be set.
|
||||
* - If we are tracking allocations, the SavedStacksMetadataCallback must be
|
||||
* installed for this compartment.
|
||||
* All four indications must be kept consistent.
|
||||
* All three indications must be kept consistent.
|
||||
*/
|
||||
AutoCompartment ac(cx, global);
|
||||
GlobalObject::DebuggerVector* v = GlobalObject::getOrCreateDebuggers(cx, global);
|
||||
|
@ -3172,14 +3083,12 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
|||
if (!debuggees.put(global)) {
|
||||
ReportOutOfMemory(cx);
|
||||
} else {
|
||||
if (!trackingAllocationSites || Debugger::addAllocationsTracking(cx, *global)) {
|
||||
debuggeeCompartment->setIsDebuggee();
|
||||
debuggeeCompartment->updateDebuggerObservesAsmJS();
|
||||
if (!observesAllExecution())
|
||||
return true;
|
||||
if (ensureExecutionObservabilityOfCompartment(cx, debuggeeCompartment))
|
||||
return true;
|
||||
}
|
||||
debuggeeCompartment->setIsDebuggee();
|
||||
debuggeeCompartment->updateDebuggerObservesAsmJS();
|
||||
if (!observesAllExecution())
|
||||
return true;
|
||||
if (ensureExecutionObservabilityOfCompartment(cx, debuggeeCompartment))
|
||||
return true;
|
||||
|
||||
/* Maintain consistency on error. */
|
||||
debuggees.remove(global);
|
||||
|
@ -3189,6 +3098,10 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
|
|||
v->popBack();
|
||||
}
|
||||
|
||||
/* Don't leave the object metadata hook set if we OOM'd. */
|
||||
if (setMetadataCallback)
|
||||
debuggeeCompartment->forgetObjectMetadataCallback();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3255,7 +3168,10 @@ Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
|
|||
* metadata callback from this global's compartment.
|
||||
*/
|
||||
if (trackingAllocationSites)
|
||||
Debugger::removeAllocationsTracking(*global);
|
||||
global->compartment()->forgetObjectMetadataCallback();
|
||||
|
||||
// Clear out all object metadata in the compartment.
|
||||
global->compartment()->clearObjectMetadata();
|
||||
|
||||
if (global->getDebuggers()->empty()) {
|
||||
global->compartment()->unsetIsDebuggee();
|
||||
|
@ -3265,7 +3181,6 @@ Debugger::removeDebuggeeGlobal(FreeOp* fop, GlobalObject* global,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static inline ScriptSourceObject* GetSourceReferent(JSObject* obj);
|
||||
|
||||
/*
|
||||
|
@ -6772,29 +6687,15 @@ DebuggerObject_getGlobal(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
null(CallArgs& args)
|
||||
{
|
||||
args.rval().setNull();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DebuggerObject_getAllocationSite(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get allocationSite", args, obj);
|
||||
|
||||
RootedObject metadata(cx, GetObjectMetadata(obj));
|
||||
if (!metadata)
|
||||
return null(args);
|
||||
|
||||
metadata = CheckedUnwrap(metadata);
|
||||
if (!metadata || !SavedFrame::isSavedFrameAndNotProto(*metadata))
|
||||
return null(args);
|
||||
|
||||
if (!cx->compartment()->wrap(cx, &metadata))
|
||||
return false;
|
||||
args.rval().setObject(*metadata);
|
||||
args.rval().setObjectOrNull(metadata);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -7882,27 +7783,16 @@ JS::dbg::onPromiseSettled(JSContext* cx, HandleObject promise)
|
|||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::dbg::IsDebugger(const JSObject& obj)
|
||||
JS::dbg::IsDebugger(JS::Value val)
|
||||
{
|
||||
return js::GetObjectClass(&obj) == &Debugger::jsclass &&
|
||||
js::Debugger::fromJSObject(&obj) != nullptr;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::dbg::GetDebuggeeGlobals(JSContext* cx, const JSObject& dbgObj, AutoObjectVector& vector)
|
||||
{
|
||||
MOZ_ASSERT(IsDebugger(dbgObj));
|
||||
js::Debugger* dbg = js::Debugger::fromJSObject(&dbgObj);
|
||||
|
||||
if (!vector.reserve(vector.length() + dbg->debuggees.count())) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
if (!val.isObject())
|
||||
return false;
|
||||
}
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty(); r.popFront())
|
||||
vector.infallibleAppend(static_cast<JSObject*>(r.front()));
|
||||
JSObject& obj = val.toObject();
|
||||
if (obj.getClass() != &Debugger::jsclass)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return js::Debugger::fromJSObject(&obj) != nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -188,8 +188,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
friend class SavedStacks;
|
||||
friend class mozilla::LinkedListElement<Debugger>;
|
||||
friend bool (::JS_DefineDebuggerObject)(JSContext* cx, JS::HandleObject obj);
|
||||
friend bool (::JS::dbg::IsDebugger)(const JSObject&);
|
||||
friend bool (::JS::dbg::GetDebuggeeGlobals)(JSContext*, const JSObject&, AutoObjectVector&);
|
||||
friend bool (::JS::dbg::IsDebugger)(JS::Value val);
|
||||
friend JSObject* SavedStacksMetadataCallback(JSContext* cx);
|
||||
friend void JS::dbg::onNewPromise(JSContext* cx, HandleObject promise);
|
||||
friend void JS::dbg::onPromiseSettled(JSContext* cx, HandleObject promise);
|
||||
friend bool JS::dbg::FireOnGarbageCollectionHook(JSContext* cx,
|
||||
|
@ -299,39 +299,6 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
int64_t when);
|
||||
void emptyAllocationsLog();
|
||||
|
||||
/*
|
||||
* Return true if there is an existing object metadata callback for the
|
||||
* given global's compartment that will prevent our instrumentation of
|
||||
* allocations.
|
||||
*/
|
||||
static bool cannotTrackAllocations(const GlobalObject& global);
|
||||
|
||||
/*
|
||||
* Return true if the given global is being observed by at least one
|
||||
* Debugger that is tracking allocations.
|
||||
*/
|
||||
static bool isObservedByDebuggerTrackingAllocations(const GlobalObject& global);
|
||||
|
||||
/*
|
||||
* Add allocations tracking for objects allocated within the given
|
||||
* debuggee's compartment. The given debuggee global must be observed by at
|
||||
* least one Debugger that is enabled and tracking allocations.
|
||||
*/
|
||||
static bool addAllocationsTracking(JSContext* cx, GlobalObject& debuggee);
|
||||
|
||||
/*
|
||||
* Remove allocations tracking for objects allocated within the given
|
||||
* global's compartment. This is a no-op if there are still Debuggers
|
||||
* observing this global and who are tracking allocations.
|
||||
*/
|
||||
static void removeAllocationsTracking(GlobalObject& global);
|
||||
|
||||
/*
|
||||
* Add or remove allocations tracking for all debuggees.
|
||||
*/
|
||||
bool addAllocationsTrackingForAllDebuggees(JSContext* cx);
|
||||
void removeAllocationsTrackingForAllDebuggees();
|
||||
|
||||
/*
|
||||
* If this Debugger is enabled, and has a onNewGlobalObject handler, then
|
||||
* this link is inserted into the circular list headed by
|
||||
|
@ -597,7 +564,7 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
|
|||
bool init(JSContext* cx);
|
||||
inline const js::HeapPtrNativeObject& toJSObject() const;
|
||||
inline js::HeapPtrNativeObject& toJSObjectRef();
|
||||
static inline Debugger* fromJSObject(const JSObject* obj);
|
||||
static inline Debugger* fromJSObject(JSObject* obj);
|
||||
static Debugger* fromChildJSObject(JSObject* obj);
|
||||
|
||||
bool hasMemory() const;
|
||||
|
|
|
@ -117,17 +117,10 @@ DebuggerMemory::checkThis(JSContext* cx, CallArgs& args, const char* fnName)
|
|||
*/
|
||||
#define THIS_DEBUGGER_MEMORY(cx, argc, vp, fnName, args, memory) \
|
||||
CallArgs args = CallArgsFromVp(argc, vp); \
|
||||
Rooted<DebuggerMemory*> memory(cx, checkThis(cx, args, fnName)); \
|
||||
Rooted<DebuggerMemory*> memory(cx, checkThis(cx, args, fnName)); \
|
||||
if (!memory) \
|
||||
return false
|
||||
|
||||
static bool
|
||||
undefined(CallArgs& args)
|
||||
{
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
DebuggerMemory::setTrackingAllocationSites(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -138,24 +131,37 @@ DebuggerMemory::setTrackingAllocationSites(JSContext* cx, unsigned argc, Value*
|
|||
Debugger* dbg = memory->getDebugger();
|
||||
bool enabling = ToBoolean(args[0]);
|
||||
|
||||
if (enabling == dbg->trackingAllocationSites)
|
||||
return undefined(args);
|
||||
|
||||
dbg->trackingAllocationSites = enabling;
|
||||
|
||||
if (!dbg->enabled)
|
||||
return undefined(args);
|
||||
|
||||
if (enabling) {
|
||||
if (!dbg->addAllocationsTrackingForAllDebuggees(cx)) {
|
||||
dbg->trackingAllocationSites = false;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
dbg->removeAllocationsTrackingForAllDebuggees();
|
||||
if (enabling == dbg->trackingAllocationSites) {
|
||||
// Nothing to do here...
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
return undefined(args);
|
||||
if (enabling) {
|
||||
for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
|
||||
JSCompartment* compartment = r.front()->compartment();
|
||||
if (compartment->hasObjectMetadataCallback()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_OBJECT_METADATA_CALLBACK_ALREADY_SET);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (WeakGlobalObjectSet::Range r = dbg->debuggees.all(); !r.empty(); r.popFront()) {
|
||||
if (enabling) {
|
||||
r.front()->compartment()->setObjectMetadataCallback(SavedStacksMetadataCallback);
|
||||
} else {
|
||||
r.front()->compartment()->forgetObjectMetadataCallback();
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabling)
|
||||
dbg->emptyAllocationsLog();
|
||||
|
||||
dbg->trackingAllocationSites = enabling;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -319,18 +325,11 @@ DebuggerMemory::setOnGarbageCollection(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
/* Debugger.Memory.prototype.takeCensus */
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::dbg::SetDebuggerMallocSizeOf(JSRuntime* rt, mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
void
|
||||
JS::dbg::SetDebuggerMallocSizeOf(JSRuntime* rt, mozilla::MallocSizeOf mallocSizeOf) {
|
||||
rt->debuggerMallocSizeOf = mallocSizeOf;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(mozilla::MallocSizeOf)
|
||||
JS::dbg::GetDebuggerMallocSizeOf(JSRuntime* rt)
|
||||
{
|
||||
return rt->debuggerMallocSizeOf;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace dbg {
|
||||
|
||||
|
|
|
@ -511,7 +511,7 @@ GlobalDebuggees_class = {
|
|||
};
|
||||
|
||||
GlobalObject::DebuggerVector*
|
||||
GlobalObject::getDebuggers() const
|
||||
GlobalObject::getDebuggers()
|
||||
{
|
||||
Value debuggers = getReservedSlot(DEBUGGERS);
|
||||
if (debuggers.isUndefined())
|
||||
|
|
|
@ -690,7 +690,7 @@ class GlobalObject : public NativeObject
|
|||
* The collection of Debugger objects debugging this global. If this global
|
||||
* is not a debuggee, this returns either nullptr or an empty vector.
|
||||
*/
|
||||
DebuggerVector* getDebuggers() const;
|
||||
DebuggerVector* getDebuggers();
|
||||
|
||||
/*
|
||||
* The same, but create the empty vector if one does not already
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
#include "jsapi.h"
|
||||
|
@ -1162,19 +1161,22 @@ SavedStacks::chooseSamplingProbability(JSContext* cx)
|
|||
if (!dbgs || dbgs->empty())
|
||||
return;
|
||||
|
||||
Debugger* allocationTrackingDbg = nullptr;
|
||||
mozilla::DebugOnly<Debugger**> begin = dbgs->begin();
|
||||
|
||||
allocationSamplingProbability = 0;
|
||||
for (Debugger** dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
|
||||
// The set of debuggers had better not change while we're iterating,
|
||||
// such that the vector gets reallocated.
|
||||
MOZ_ASSERT(dbgs->begin() == begin);
|
||||
|
||||
if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled) {
|
||||
allocationSamplingProbability = std::max((*dbgp)->allocationSamplingProbability,
|
||||
allocationSamplingProbability);
|
||||
}
|
||||
if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled)
|
||||
allocationTrackingDbg = *dbgp;
|
||||
}
|
||||
|
||||
if (!allocationTrackingDbg)
|
||||
return;
|
||||
|
||||
allocationSamplingProbability = allocationTrackingDbg->allocationSamplingProbability;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Scoped.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h"
|
||||
|
@ -31,7 +32,6 @@
|
|||
#include "vm/Debugger-inl.h"
|
||||
|
||||
using mozilla::Some;
|
||||
using mozilla::UniquePtr;
|
||||
using JS::HandleValue;
|
||||
using JS::Value;
|
||||
using JS::ZoneSet;
|
||||
|
@ -46,14 +46,10 @@ using JS::ubi::TracerConcreteWithCompartment;
|
|||
|
||||
// All operations on null ubi::Nodes crash.
|
||||
const char16_t* Concrete<void>::typeName() const { MOZ_CRASH("null ubi::Node"); }
|
||||
EdgeRange* Concrete<void>::edges(JSContext*, bool) const { MOZ_CRASH("null ubi::Node"); }
|
||||
JS::Zone* Concrete<void>::zone() const { MOZ_CRASH("null ubi::Node"); }
|
||||
JSCompartment* Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
|
||||
|
||||
UniquePtr<EdgeRange>
|
||||
Concrete<void>::edges(JSContext*, bool) const {
|
||||
MOZ_CRASH("null ubi::Node");
|
||||
}
|
||||
|
||||
size_t
|
||||
Concrete<void>::size(mozilla::MallocSizeOf mallocSizeof) const
|
||||
{
|
||||
|
@ -207,17 +203,16 @@ TracerConcrete<Referent>::zone() const
|
|||
}
|
||||
|
||||
template<typename Referent>
|
||||
UniquePtr<EdgeRange>
|
||||
EdgeRange*
|
||||
TracerConcrete<Referent>::edges(JSContext* cx, bool wantNames) const {
|
||||
UniquePtr<SimpleEdgeRange, JS::DeletePolicy<SimpleEdgeRange>> range(
|
||||
cx->new_<SimpleEdgeRange>(cx));
|
||||
if (!range)
|
||||
js::ScopedJSDeletePtr<SimpleEdgeRange> r(js_new<SimpleEdgeRange>(cx));
|
||||
if (!r)
|
||||
return nullptr;
|
||||
|
||||
if (!range->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind, wantNames))
|
||||
if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind, wantNames))
|
||||
return nullptr;
|
||||
|
||||
return UniquePtr<EdgeRange>(range.release());
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
template<typename Referent>
|
||||
|
@ -319,8 +314,8 @@ RootList::init(ZoneSet& debuggees)
|
|||
bool
|
||||
RootList::init(HandleObject debuggees)
|
||||
{
|
||||
MOZ_ASSERT(debuggees && JS::dbg::IsDebugger(*debuggees));
|
||||
js::Debugger* dbg = js::Debugger::fromJSObject(debuggees.get());
|
||||
MOZ_ASSERT(debuggees && JS::dbg::IsDebugger(ObjectValue(*debuggees)));
|
||||
js::Debugger* dbg = js::Debugger::fromJSObject(debuggees);
|
||||
|
||||
ZoneSet debuggeeZones;
|
||||
if (!debuggeeZones.init())
|
||||
|
@ -352,7 +347,7 @@ RootList::addRoot(Node node, const char16_t* edgeName)
|
|||
MOZ_ASSERT(noGC.isSome());
|
||||
MOZ_ASSERT_IF(wantNames, edgeName);
|
||||
|
||||
UniquePtr<char16_t[], JS::FreePolicy> name;
|
||||
mozilla::UniquePtr<char16_t[], JS::FreePolicy> name;
|
||||
if (edgeName) {
|
||||
name = DuplicateString(cx, edgeName);
|
||||
if (!name)
|
||||
|
@ -362,12 +357,32 @@ RootList::addRoot(Node node, const char16_t* edgeName)
|
|||
return edges.append(mozilla::Move(SimpleEdge(name.release(), node)));
|
||||
}
|
||||
|
||||
// An EdgeRange concrete class that holds a pre-existing vector of SimpleEdges.
|
||||
class PreComputedEdgeRange : public EdgeRange {
|
||||
SimpleEdgeVector& edges;
|
||||
size_t i;
|
||||
|
||||
void settle() {
|
||||
front_ = i < edges.length() ? &edges[i] : nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit PreComputedEdgeRange(JSContext* cx, SimpleEdgeVector& edges)
|
||||
: edges(edges),
|
||||
i(0)
|
||||
{
|
||||
settle();
|
||||
}
|
||||
|
||||
void popFront() override { i++; settle(); }
|
||||
};
|
||||
|
||||
const char16_t Concrete<RootList>::concreteTypeName[] = MOZ_UTF16("RootList");
|
||||
|
||||
UniquePtr<EdgeRange>
|
||||
EdgeRange*
|
||||
Concrete<RootList>::edges(JSContext* cx, bool wantNames) const {
|
||||
MOZ_ASSERT_IF(wantNames, get().wantNames);
|
||||
return UniquePtr<EdgeRange>(cx->new_<PreComputedEdgeRange>(cx, get().edges));
|
||||
return js_new<PreComputedEdgeRange>(cx, get().edges);
|
||||
}
|
||||
|
||||
} // namespace ubi
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,487 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Client side phishing and malware detection request and response
|
||||
// protocol buffers. Those protocol messages should be kept in sync
|
||||
// with the server implementation.
|
||||
//
|
||||
// If you want to change this protocol definition or you have questions
|
||||
// regarding its format please contact chrome-anti-phishing@googlegroups.com.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
package safe_browsing;
|
||||
|
||||
message ClientPhishingRequest {
|
||||
// URL that the client visited. The CGI parameters are stripped by the
|
||||
// client.
|
||||
optional string url = 1;
|
||||
|
||||
// A 5-byte SHA-256 hash prefix of the URL. Before hashing the URL is
|
||||
// canonicalized, converted to a suffix-prefix expression and broadened
|
||||
// (www prefix is removed and everything past the last '/' is stripped).
|
||||
//
|
||||
// Marked OBSOLETE because the URL is sent for all users, making the hash
|
||||
// prefix unnecessary.
|
||||
optional bytes OBSOLETE_hash_prefix = 10;
|
||||
|
||||
// Score that was computed on the client. Value is between 0.0 and 1.0.
|
||||
// The larger the value the more likely the url is phishing.
|
||||
required float client_score = 2;
|
||||
|
||||
// Note: we're skipping tag 3 because it was previously used.
|
||||
|
||||
// Is true if the features for this URL were classified as phishing.
|
||||
// Currently, this will always be true for all client-phishing requests
|
||||
// that are sent to the server.
|
||||
optional bool is_phishing = 4;
|
||||
|
||||
message Feature {
|
||||
// Feature name. E.g., 'PageHasForms'.
|
||||
required string name = 1;
|
||||
|
||||
// Feature value is always in the range [0.0, 1.0]. Boolean features
|
||||
// have value 1.0.
|
||||
required double value = 2;
|
||||
}
|
||||
|
||||
// List of features that were extracted. Those are the features that were
|
||||
// sent to the scorer and which resulted in client_score being computed.
|
||||
repeated Feature feature_map = 5;
|
||||
|
||||
// The version number of the model that was used to compute the client-score.
|
||||
// Copied from ClientSideModel.version().
|
||||
optional int32 model_version = 6;
|
||||
|
||||
// Field 7 is only used on the server.
|
||||
|
||||
// List of features that are extracted in the client but are not used in the
|
||||
// machine learning model.
|
||||
repeated Feature non_model_feature_map = 8;
|
||||
|
||||
// The referrer URL. This field might not be set, for example, in the case
|
||||
// where the referrer uses HTTPs.
|
||||
// OBSOLETE: Use feature 'Referrer=<referrer>' instead.
|
||||
optional string OBSOLETE_referrer_url = 9;
|
||||
|
||||
// Field 11 is only used on the server.
|
||||
|
||||
// List of shingle hashes we extracted.
|
||||
repeated uint32 shingle_hashes = 12 [packed = true];
|
||||
}
|
||||
|
||||
message ClientPhishingResponse {
|
||||
required bool phishy = 1;
|
||||
|
||||
// A list of SafeBrowsing host-suffix / path-prefix expressions that
|
||||
// are whitelisted. The client must match the current top-level URL
|
||||
// against these whitelisted expressions and only apply a positive
|
||||
// phishing verdict above if the URL does not match any expression
|
||||
// on this whitelist. The client must not cache these whitelisted
|
||||
// expressions. This whitelist will be empty for the vast majority
|
||||
// of the responses but might contain up to 100 entries in emergency
|
||||
// situations.
|
||||
//
|
||||
// Marked OBSOLETE because the URL is sent for all users, so the server
|
||||
// can do whitelist matching.
|
||||
repeated string OBSOLETE_whitelist_expression = 2;
|
||||
}
|
||||
|
||||
message ClientMalwareRequest {
|
||||
// URL that the client visited. The CGI parameters are stripped by the
|
||||
// client.
|
||||
required string url = 1;
|
||||
|
||||
// Field 2 is deleted and no longer in use.
|
||||
|
||||
// Field 3 is only used on the server.
|
||||
|
||||
// The referrer URL. This field might not be set, for example, in the case
|
||||
// where the referrer uses HTTPS.
|
||||
optional string referrer_url = 4;
|
||||
|
||||
// Field 5 and 6 are only used on the server.
|
||||
|
||||
message UrlInfo {
|
||||
required string ip = 1;
|
||||
required string url = 2;
|
||||
optional string method = 3;
|
||||
optional string referrer = 4;
|
||||
// Resource type, the int value is a direct cast from the Type enum
|
||||
// of ResourceType class defined in //src/webkit/commom/resource_type.h
|
||||
optional int32 resource_type = 5;
|
||||
}
|
||||
|
||||
// List of resource urls that match the malware IP list.
|
||||
repeated UrlInfo bad_ip_url_info = 7;
|
||||
}
|
||||
|
||||
message ClientMalwareResponse {
|
||||
required bool blacklist = 1;
|
||||
// The confirmed blacklisted bad IP and its url, which will be shown in
|
||||
// malware warning, if the blacklist verdict is true.
|
||||
// This IP string could be either in IPv4 or IPv6 format, which is the same
|
||||
// as the ones client sent to server.
|
||||
optional string bad_ip = 2;
|
||||
optional string bad_url = 3;
|
||||
}
|
||||
|
||||
message ClientDownloadRequest {
|
||||
// The final URL of the download (after all redirects).
|
||||
required string url = 1;
|
||||
|
||||
// This message contains various binary digests of the download payload.
|
||||
message Digests {
|
||||
optional bytes sha256 = 1;
|
||||
optional bytes sha1 = 2;
|
||||
optional bytes md5 = 3;
|
||||
}
|
||||
required Digests digests = 2;
|
||||
|
||||
// This is the length in bytes of the download payload.
|
||||
required int64 length = 3;
|
||||
|
||||
// Type of the resources stored below.
|
||||
enum ResourceType {
|
||||
// The final URL of the download payload. The resource URL should
|
||||
// correspond to the URL field above.
|
||||
DOWNLOAD_URL = 0;
|
||||
// A redirect URL that was fetched before hitting the final DOWNLOAD_URL.
|
||||
DOWNLOAD_REDIRECT = 1;
|
||||
// The final top-level URL of the tab that triggered the download.
|
||||
TAB_URL = 2;
|
||||
// A redirect URL thas was fetched before hitting the final TAB_URL.
|
||||
TAB_REDIRECT = 3;
|
||||
}
|
||||
|
||||
message Resource {
|
||||
required string url = 1;
|
||||
required ResourceType type = 2;
|
||||
optional bytes remote_ip = 3;
|
||||
// This will only be set if the referrer is available and if the
|
||||
// resource type is either TAB_URL or DOWNLOAD_URL.
|
||||
optional string referrer = 4;
|
||||
|
||||
// TODO(noelutz): add the transition type?
|
||||
}
|
||||
|
||||
// This repeated field will store all the redirects as well as the
|
||||
// final URLs for the top-level tab URL (i.e., the URL that
|
||||
// triggered the download) as well as for the download URL itself.
|
||||
repeated Resource resources = 4;
|
||||
|
||||
// A trust chain of certificates. Each chain begins with the signing
|
||||
// certificate of the binary, and ends with a self-signed certificate,
|
||||
// typically from a trusted root CA. This structure is analogous to
|
||||
// CERT_CHAIN_CONTEXT on Windows.
|
||||
message CertificateChain {
|
||||
// A single link in the chain.
|
||||
message Element {
|
||||
// DER-encoded X.509 representation of the certificate.
|
||||
optional bytes certificate = 1;
|
||||
// Fields 2 - 7 are only used on the server.
|
||||
}
|
||||
repeated Element element = 1;
|
||||
}
|
||||
|
||||
message SignatureInfo {
|
||||
// All of the certificate chains for the binary's signing certificate.
|
||||
// If no chains are present, the binary is not signed. Multiple chains
|
||||
// may be present if any certificate has multiple signers.
|
||||
repeated CertificateChain certificate_chain = 1;
|
||||
|
||||
// True if the signature was trusted on the client.
|
||||
optional bool trusted = 2;
|
||||
}
|
||||
|
||||
// This field will only be set if the binary is signed.
|
||||
optional SignatureInfo signature = 5;
|
||||
|
||||
// True if the download was user initiated.
|
||||
optional bool user_initiated = 6;
|
||||
|
||||
// Fields 7 and 8 are only used on the server.
|
||||
|
||||
// Name of the file where the download would be stored if the
|
||||
// download completes. E.g., "bla.exe".
|
||||
optional string file_basename = 9;
|
||||
|
||||
// Starting with Chrome M19 we're also sending back pings for Chrome
|
||||
// extensions that get downloaded by users.
|
||||
enum DownloadType {
|
||||
WIN_EXECUTABLE = 0; // Currently all .exe, .cab and .msi files.
|
||||
CHROME_EXTENSION = 1; // .crx files.
|
||||
ANDROID_APK = 2; // .apk files.
|
||||
// .zip files containing one of the other executable types.
|
||||
ZIPPED_EXECUTABLE = 3;
|
||||
MAC_EXECUTABLE = 4; // .dmg, .pkg, etc.
|
||||
}
|
||||
optional DownloadType download_type = 10 [default = WIN_EXECUTABLE];
|
||||
|
||||
// Locale of the device, eg en, en_US.
|
||||
optional string locale = 11;
|
||||
|
||||
message PEImageHeaders {
|
||||
// IMAGE_DOS_HEADER.
|
||||
optional bytes dos_header = 1;
|
||||
// IMAGE_FILE_HEADER.
|
||||
optional bytes file_header = 2;
|
||||
// IMAGE_OPTIONAL_HEADER32. Present only for 32-bit PE images.
|
||||
optional bytes optional_headers32 = 3;
|
||||
// IMAGE_OPTIONAL_HEADER64. Present only for 64-bit PE images.
|
||||
optional bytes optional_headers64 = 4;
|
||||
// IMAGE_SECTION_HEADER.
|
||||
repeated bytes section_header = 5;
|
||||
// Contents of the .edata section.
|
||||
optional bytes export_section_data = 6;
|
||||
|
||||
message DebugData {
|
||||
// IMAGE_DEBUG_DIRECTORY.
|
||||
optional bytes directory_entry = 1;
|
||||
optional bytes raw_data = 2;
|
||||
}
|
||||
|
||||
repeated DebugData debug_data = 7;
|
||||
}
|
||||
|
||||
message ImageHeaders {
|
||||
// Windows Portable Executable image headers.
|
||||
optional PEImageHeaders pe_headers = 1;
|
||||
};
|
||||
|
||||
// Fields 12-17 are reserved for server-side use and are never sent by the
|
||||
// client.
|
||||
|
||||
optional ImageHeaders image_headers = 18;
|
||||
|
||||
// Fields 19-21 are reserved for server-side use and are never sent by the
|
||||
// client.
|
||||
|
||||
// A binary contained in an archive (e.g., a .zip archive).
|
||||
message ArchivedBinary {
|
||||
optional string file_basename = 1;
|
||||
optional DownloadType download_type = 2;
|
||||
optional Digests digests = 3;
|
||||
optional int64 length = 4;
|
||||
optional SignatureInfo signature = 5;
|
||||
optional ImageHeaders image_headers = 6;
|
||||
}
|
||||
|
||||
repeated ArchivedBinary archived_binary = 22;
|
||||
}
|
||||
|
||||
message ClientDownloadResponse {
|
||||
enum Verdict {
|
||||
// Download is considered safe.
|
||||
SAFE = 0;
|
||||
// Download is considered dangerous. Chrome should show a warning to the
|
||||
// user.
|
||||
DANGEROUS = 1;
|
||||
// Download is unknown. Chrome should display a less severe warning.
|
||||
UNCOMMON = 2;
|
||||
// The download is potentially unwanted.
|
||||
POTENTIALLY_UNWANTED = 3;
|
||||
// The download is from a dangerous host.
|
||||
DANGEROUS_HOST = 4;
|
||||
}
|
||||
required Verdict verdict = 1;
|
||||
|
||||
message MoreInfo {
|
||||
// A human-readable string describing the nature of the warning.
|
||||
// Only if verdict != SAFE. Localized based on request.locale.
|
||||
optional string description = 1;
|
||||
|
||||
// A URL to get more information about this warning, if available.
|
||||
optional string url = 2;
|
||||
}
|
||||
optional MoreInfo more_info = 2;
|
||||
|
||||
// An arbitrary token that should be sent along for further server requests.
|
||||
optional bytes token = 3;
|
||||
}
|
||||
|
||||
// The following protocol buffer holds the feedback report gathered
|
||||
// from the user regarding the download.
|
||||
message ClientDownloadReport {
|
||||
// The information of user who provided the feedback.
|
||||
// This is going to be useful for handling appeals.
|
||||
message UserInformation {
|
||||
optional string email = 1;
|
||||
}
|
||||
|
||||
enum Reason {
|
||||
SHARE = 0;
|
||||
FALSE_POSITIVE = 1;
|
||||
APPEAL = 2;
|
||||
}
|
||||
|
||||
// The type of feedback for this report.
|
||||
optional Reason reason = 1;
|
||||
|
||||
// The original download ping
|
||||
optional ClientDownloadRequest download_request = 2;
|
||||
|
||||
// Stores the information of the user who provided the feedback.
|
||||
optional UserInformation user_information = 3;
|
||||
|
||||
// Unstructed comments provided by the user.
|
||||
optional bytes comment = 4;
|
||||
|
||||
// The original download response sent from the verdict server.
|
||||
optional ClientDownloadResponse download_response = 5;
|
||||
}
|
||||
|
||||
// This is used to send back upload status to the client after upload completion
|
||||
message ClientUploadResponse {
|
||||
enum UploadStatus {
|
||||
// The upload was successful and a complete response can be expected
|
||||
SUCCESS = 0;
|
||||
|
||||
// The upload was unsuccessful and the response is incomplete.
|
||||
UPLOAD_FAILURE = 1;
|
||||
}
|
||||
|
||||
// Holds the upload status
|
||||
optional UploadStatus status = 1;
|
||||
|
||||
// Holds the permalink where the results of scanning the binary are available
|
||||
optional string permalink = 2;
|
||||
}
|
||||
|
||||
message ClientIncidentReport {
|
||||
message IncidentData {
|
||||
message TrackedPreferenceIncident {
|
||||
enum ValueState {
|
||||
UNKNOWN = 0;
|
||||
CLEARED = 1;
|
||||
WEAK_LEGACY_OBSOLETE = 2;
|
||||
CHANGED = 3;
|
||||
UNTRUSTED_UNKNOWN_VALUE = 4;
|
||||
}
|
||||
|
||||
optional string path = 1;
|
||||
optional string atomic_value = 2;
|
||||
repeated string split_key = 3;
|
||||
optional ValueState value_state = 4;
|
||||
}
|
||||
message BinaryIntegrityIncident {
|
||||
optional string file_basename = 1;
|
||||
optional ClientDownloadRequest.SignatureInfo signature = 2;
|
||||
}
|
||||
message BlacklistLoadIncident {
|
||||
optional string path = 1;
|
||||
optional ClientDownloadRequest.Digests digest = 2;
|
||||
optional string version = 3;
|
||||
optional bool blacklist_initialized = 4;
|
||||
optional ClientDownloadRequest.SignatureInfo signature = 5;
|
||||
optional ClientDownloadRequest.ImageHeaders image_headers = 6;
|
||||
}
|
||||
message VariationsSeedSignatureIncident {
|
||||
optional string variations_seed_signature = 1;
|
||||
}
|
||||
message ScriptRequestIncident {
|
||||
optional string script_digest = 1;
|
||||
optional string inclusion_origin = 2;
|
||||
}
|
||||
optional int64 incident_time_msec = 1;
|
||||
optional TrackedPreferenceIncident tracked_preference = 2;
|
||||
optional BinaryIntegrityIncident binary_integrity = 3;
|
||||
optional BlacklistLoadIncident blacklist_load = 4;
|
||||
// Note: skip tag 5 because it was previously used.
|
||||
optional VariationsSeedSignatureIncident variations_seed_signature = 6;
|
||||
optional ScriptRequestIncident script_request = 7;
|
||||
}
|
||||
|
||||
repeated IncidentData incident = 1;
|
||||
|
||||
message DownloadDetails {
|
||||
optional bytes token = 1;
|
||||
optional ClientDownloadRequest download = 2;
|
||||
optional int64 download_time_msec = 3;
|
||||
optional int64 open_time_msec = 4;
|
||||
}
|
||||
|
||||
optional DownloadDetails download = 2;
|
||||
|
||||
message EnvironmentData {
|
||||
message OS {
|
||||
optional string os_name = 1;
|
||||
optional string os_version = 2;
|
||||
}
|
||||
optional OS os = 1;
|
||||
message Machine {
|
||||
optional string cpu_architecture = 1;
|
||||
optional string cpu_vendor = 2;
|
||||
optional uint32 cpuid = 3;
|
||||
}
|
||||
optional Machine machine = 2;
|
||||
message Process {
|
||||
optional string version = 1;
|
||||
repeated string OBSOLETE_dlls = 2;
|
||||
message Patch {
|
||||
optional string function = 1;
|
||||
optional string target_dll = 2;
|
||||
}
|
||||
repeated Patch patches = 3;
|
||||
message NetworkProvider {}
|
||||
repeated NetworkProvider network_providers = 4;
|
||||
enum Channel {
|
||||
CHANNEL_UNKNOWN = 0;
|
||||
CHANNEL_CANARY = 1;
|
||||
CHANNEL_DEV = 2;
|
||||
CHANNEL_BETA = 3;
|
||||
CHANNEL_STABLE = 4;
|
||||
}
|
||||
optional Channel chrome_update_channel = 5;
|
||||
optional int64 uptime_msec = 6;
|
||||
optional bool metrics_consent = 7;
|
||||
optional bool extended_consent = 8;
|
||||
message Dll {
|
||||
enum Feature {
|
||||
UNKNOWN = 0;
|
||||
LSP = 1;
|
||||
}
|
||||
optional string path = 1;
|
||||
optional uint64 base_address = 2;
|
||||
optional uint32 length = 3;
|
||||
repeated Feature feature = 4;
|
||||
optional ClientDownloadRequest.ImageHeaders image_headers = 5;
|
||||
}
|
||||
repeated Dll dll = 9;
|
||||
repeated string blacklisted_dll = 10;
|
||||
message ModuleState {
|
||||
enum ModifiedState {
|
||||
UNKNOWN = 0;
|
||||
MODULE_STATE_UNKNOWN = 1;
|
||||
MODULE_STATE_UNMODIFIED = 2;
|
||||
MODULE_STATE_MODIFIED = 3;
|
||||
}
|
||||
optional string name = 1;
|
||||
optional ModifiedState modified_state = 2;
|
||||
repeated string modified_export = 3;
|
||||
}
|
||||
repeated ModuleState module_state = 11;
|
||||
}
|
||||
optional Process process = 3;
|
||||
}
|
||||
|
||||
optional EnvironmentData environment = 3;
|
||||
}
|
||||
|
||||
message ClientIncidentResponse {
|
||||
optional bytes token = 1;
|
||||
optional bool download_requested = 2;
|
||||
|
||||
message EnvironmentRequest { optional int32 dll_index = 1; }
|
||||
|
||||
repeated EnvironmentRequest environment_requests = 3;
|
||||
}
|
||||
|
||||
message DownloadMetadata {
|
||||
optional uint32 download_id = 1;
|
||||
|
||||
optional ClientIncidentReport.DownloadDetails download = 2;
|
||||
}
|
|
@ -1,15 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
#!/bin/bash
|
||||
# A script to generate toolkit/components/downloads/csd.pb.{cc,h} for use in
|
||||
# nsIApplicationReputationQuery. This script assumes you have downloaded and
|
||||
# installed the protocol buffer compiler.
|
||||
# As of June 26 2014, csd.proto contains many protobufs that are currently
|
||||
# unused by ApplicationReputation. You may want to strip csd.proto of these
|
||||
# before running the protocol compiler on it.
|
||||
|
||||
set -e
|
||||
|
||||
if [ "${PROTOC_PATH:+set}" != "set" ]; then
|
||||
if [ -n $PROTOC_PATH ]; then
|
||||
PROTOC_PATH=/usr/local/bin/protoc
|
||||
fi
|
||||
|
||||
|
@ -21,14 +17,9 @@ if [ ! -e $PROTOC_PATH ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f nsDownloadManager.cpp ]; then
|
||||
echo "You must run this script in the toolkit/components/downloads" >&2
|
||||
echo "directory of the source tree." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get the protocol buffer and compile it
|
||||
CSD_PROTO_URL="https://chromium.googlesource.com/playground/chromium-blink-merge/+/master/chrome/common/safe_browsing/csd.proto?format=TEXT"
|
||||
CMD='wget http://src.chromium.org/chrome/trunk/src/chrome/common/safe_browsing/csd.proto -O csd.proto'
|
||||
OUTPUT_PATH=toolkit/components/downloads
|
||||
|
||||
curl $CSD_PROTO_URL | base64 --decode > csd.proto
|
||||
$PROTOC_PATH csd.proto --cpp_out=.
|
||||
$CMD
|
||||
$PROTOC_PATH csd.proto --cpp_out=$OUTPUT_PATH
|
||||
|
|
|
@ -76,6 +76,5 @@ LOCAL_INCLUDES += [
|
|||
]
|
||||
|
||||
DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
|
||||
DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
|
||||
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
|
|
|
@ -1,25 +1,19 @@
|
|||
This library has been updated to protobuf-2.4.1 as of 11/30/12.
|
||||
|
||||
Protocol Buffers (protobuf) source is available (via svn) at:
|
||||
|
||||
svn checkout http://protobuf.googlecode.com/svn/trunk/ protobuf-read-only
|
||||
|
||||
Or via git at:
|
||||
|
||||
https://github.com/google/protobuf
|
||||
svn checkout http://protobuf.googlecode.com/svn/trunk/ protobuf-read-only
|
||||
|
||||
This code is covered under the BSD license (see COPYING.txt). Documentation is
|
||||
available at http://code.google.com/p/protobuf.
|
||||
|
||||
The tree's current version of the protobuf library is 2.6.1.
|
||||
This import includes only files in protobuf-lite, a lighter-weight library that
|
||||
does not support reflection or descriptors. Manual changes include removing all
|
||||
tests, testdata, config.h, and all files not used in protobuf-lite.
|
||||
|
||||
We do not include the protobuf tests or the protoc compiler.
|
||||
Applied Patches
|
||||
===============
|
||||
r512.patch:
|
||||
Support VS2013 (from revision r512)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
# Upgrading the Protobuf Library
|
||||
|
||||
1. Get a new protobuf release from https://github.com/google/protobuf/releases
|
||||
|
||||
2. Run `$ ./toolkit/components/protobuf/upgrade_protobuf.sh ~/path/to/release/checkout/of/protobuf`.
|
||||
|
||||
3. Update the moz.build to export the new set of headers and add any new .cc
|
||||
files to the unified sources and remove old ones.
|
||||
vs2013.patch
|
||||
Additional changes to support VS2013 missed from revision r512.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -38,9 +38,10 @@
|
|||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/stubs/map_util.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -57,22 +58,6 @@ inline WireFormatLite::CppType cpp_type(FieldType type) {
|
|||
return WireFormatLite::FieldTypeToCppType(real_type(type));
|
||||
}
|
||||
|
||||
inline bool is_packable(WireFormatLite::WireType type) {
|
||||
switch (type) {
|
||||
case WireFormatLite::WIRETYPE_VARINT:
|
||||
case WireFormatLite::WIRETYPE_FIXED64:
|
||||
case WireFormatLite::WIRETYPE_FIXED32:
|
||||
return true;
|
||||
case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
|
||||
case WireFormatLite::WIRETYPE_START_GROUP:
|
||||
case WireFormatLite::WIRETYPE_END_GROUP:
|
||||
return false;
|
||||
|
||||
// Do not add a default statement. Let the compiler complain when someone
|
||||
// adds a new wire type.
|
||||
}
|
||||
}
|
||||
|
||||
// Registry stuff.
|
||||
typedef hash_map<pair<const MessageLite*, int>,
|
||||
ExtensionInfo> ExtensionRegistry;
|
||||
|
@ -86,7 +71,7 @@ void DeleteRegistry() {
|
|||
|
||||
void InitRegistry() {
|
||||
registry_ = new ExtensionRegistry;
|
||||
OnShutdown(&DeleteRegistry);
|
||||
internal::OnShutdown(&DeleteRegistry);
|
||||
}
|
||||
|
||||
// This function is only called at startup, so there is no need for thread-
|
||||
|
@ -195,17 +180,6 @@ bool ExtensionSet::Has(int number) const {
|
|||
return !iter->second.is_cleared;
|
||||
}
|
||||
|
||||
int ExtensionSet::NumExtensions() const {
|
||||
int result = 0;
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
if (!iter->second.is_cleared) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ExtensionSet::ExtensionSize(int number) const {
|
||||
map<int, Extension>::const_iterator iter = extensions_.find(number);
|
||||
if (iter == extensions_.end()) return false;
|
||||
|
@ -319,80 +293,6 @@ PRIMITIVE_ACCESSORS( BOOL, bool, Bool)
|
|||
|
||||
#undef PRIMITIVE_ACCESSORS
|
||||
|
||||
const void* ExtensionSet::GetRawRepeatedField(int number,
|
||||
const void* default_value) const {
|
||||
map<int, Extension>::const_iterator iter = extensions_.find(number);
|
||||
if (iter == extensions_.end()) {
|
||||
return default_value;
|
||||
}
|
||||
// We assume that all the RepeatedField<>* pointers have the same
|
||||
// size and alignment within the anonymous union in Extension.
|
||||
return iter->second.repeated_int32_value;
|
||||
}
|
||||
|
||||
void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
|
||||
bool packed,
|
||||
const FieldDescriptor* desc) {
|
||||
Extension* extension;
|
||||
|
||||
// We instantiate an empty Repeated{,Ptr}Field if one doesn't exist for this
|
||||
// extension.
|
||||
if (MaybeNewExtension(number, desc, &extension)) {
|
||||
extension->is_repeated = true;
|
||||
extension->type = field_type;
|
||||
extension->is_packed = packed;
|
||||
|
||||
switch (WireFormatLite::FieldTypeToCppType(
|
||||
static_cast<WireFormatLite::FieldType>(field_type))) {
|
||||
case WireFormatLite::CPPTYPE_INT32:
|
||||
extension->repeated_int32_value = new RepeatedField<int32>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_INT64:
|
||||
extension->repeated_int64_value = new RepeatedField<int64>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_UINT32:
|
||||
extension->repeated_uint32_value = new RepeatedField<uint32>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_UINT64:
|
||||
extension->repeated_uint64_value = new RepeatedField<uint64>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_DOUBLE:
|
||||
extension->repeated_double_value = new RepeatedField<double>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_FLOAT:
|
||||
extension->repeated_float_value = new RepeatedField<float>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_BOOL:
|
||||
extension->repeated_bool_value = new RepeatedField<bool>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_ENUM:
|
||||
extension->repeated_enum_value = new RepeatedField<int>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_STRING:
|
||||
extension->repeated_string_value = new RepeatedPtrField< ::std::string>();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_MESSAGE:
|
||||
extension->repeated_message_value = new RepeatedPtrField<MessageLite>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We assume that all the RepeatedField<>* pointers have the same
|
||||
// size and alignment within the anonymous union in Extension.
|
||||
return extension->repeated_int32_value;
|
||||
}
|
||||
|
||||
// Compatible version using old call signature. Does not create extensions when
|
||||
// the don't already exist; instead, just GOOGLE_CHECK-fails.
|
||||
void* ExtensionSet::MutableRawRepeatedField(int number) {
|
||||
map<int, Extension>::iterator iter = extensions_.find(number);
|
||||
GOOGLE_CHECK(iter == extensions_.end()) << "Extension not found.";
|
||||
// We assume that all the RepeatedField<>* pointers have the same
|
||||
// size and alignment within the anonymous union in Extension.
|
||||
return iter->second.repeated_int32_value;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Enums
|
||||
|
||||
|
@ -522,11 +422,7 @@ const MessageLite& ExtensionSet::GetMessage(
|
|||
return default_value;
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
|
||||
if (iter->second.is_lazy) {
|
||||
return iter->second.lazymessage_value->GetMessage(default_value);
|
||||
} else {
|
||||
return *iter->second.message_value;
|
||||
}
|
||||
return *iter->second.message_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,19 +439,12 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
|
|||
extension->type = type;
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = false;
|
||||
extension->is_lazy = false;
|
||||
extension->message_value = prototype.New();
|
||||
extension->is_cleared = false;
|
||||
return extension->message_value;
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
|
||||
extension->is_cleared = false;
|
||||
if (extension->is_lazy) {
|
||||
return extension->lazymessage_value->MutableMessage(prototype);
|
||||
} else {
|
||||
return extension->message_value;
|
||||
}
|
||||
}
|
||||
extension->is_cleared = false;
|
||||
return extension->message_value;
|
||||
}
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
|
@ -563,56 +452,6 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
|
|||
// const Descriptor* message_type,
|
||||
// MessageFactory* factory)
|
||||
|
||||
void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
|
||||
const FieldDescriptor* descriptor,
|
||||
MessageLite* message) {
|
||||
if (message == NULL) {
|
||||
ClearExtension(number);
|
||||
return;
|
||||
}
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(number, descriptor, &extension)) {
|
||||
extension->type = type;
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = false;
|
||||
extension->is_lazy = false;
|
||||
extension->message_value = message;
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
|
||||
if (extension->is_lazy) {
|
||||
extension->lazymessage_value->SetAllocatedMessage(message);
|
||||
} else {
|
||||
delete extension->message_value;
|
||||
extension->message_value = message;
|
||||
}
|
||||
}
|
||||
extension->is_cleared = false;
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::ReleaseMessage(int number,
|
||||
const MessageLite& prototype) {
|
||||
map<int, Extension>::iterator iter = extensions_.find(number);
|
||||
if (iter == extensions_.end()) {
|
||||
// Not present. Return NULL.
|
||||
return NULL;
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
|
||||
MessageLite* ret = NULL;
|
||||
if (iter->second.is_lazy) {
|
||||
ret = iter->second.lazymessage_value->ReleaseMessage(prototype);
|
||||
delete iter->second.lazymessage_value;
|
||||
} else {
|
||||
ret = iter->second.message_value;
|
||||
}
|
||||
extensions_.erase(number);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
// MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
|
||||
// MessageFactory* factory);
|
||||
|
||||
const MessageLite& ExtensionSet::GetRepeatedMessage(
|
||||
int number, int index) const {
|
||||
map<int, Extension>::const_iterator iter = extensions_.find(number);
|
||||
|
@ -645,7 +484,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
|
|||
// RepeatedPtrField<MessageLite> does not know how to Add() since it cannot
|
||||
// allocate an abstract object, so we have to be tricky.
|
||||
MessageLite* result = extension->repeated_message_value
|
||||
->AddFromCleared<GenericTypeHandler<MessageLite> >();
|
||||
->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
|
||||
if (result == NULL) {
|
||||
result = prototype.New();
|
||||
extension->repeated_message_value->AddAllocated(result);
|
||||
|
@ -701,16 +540,6 @@ void ExtensionSet::RemoveLast(int number) {
|
|||
}
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::ReleaseLast(int number) {
|
||||
map<int, Extension>::iterator iter = extensions_.find(number);
|
||||
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
|
||||
|
||||
Extension* extension = &iter->second;
|
||||
GOOGLE_DCHECK(extension->is_repeated);
|
||||
GOOGLE_DCHECK(cpp_type(extension->type) == WireFormatLite::CPPTYPE_MESSAGE);
|
||||
return extension->repeated_message_value->ReleaseLast();
|
||||
}
|
||||
|
||||
void ExtensionSet::SwapElements(int number, int index1, int index2) {
|
||||
map<int, Extension>::iterator iter = extensions_.find(number);
|
||||
GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
|
||||
|
@ -773,11 +602,9 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) {
|
|||
if (is_new) {
|
||||
// Extension did not already exist in set.
|
||||
extension->type = other_extension.type;
|
||||
extension->is_packed = other_extension.is_packed;
|
||||
extension->is_repeated = true;
|
||||
} else {
|
||||
GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
|
||||
GOOGLE_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
|
||||
GOOGLE_DCHECK(extension->is_repeated);
|
||||
}
|
||||
|
||||
|
@ -848,55 +675,12 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) {
|
|||
*other_extension.string_value,
|
||||
other_extension.descriptor);
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_MESSAGE: {
|
||||
Extension* extension;
|
||||
bool is_new = MaybeNewExtension(iter->first,
|
||||
other_extension.descriptor,
|
||||
&extension);
|
||||
if (is_new) {
|
||||
extension->type = other_extension.type;
|
||||
extension->is_packed = other_extension.is_packed;
|
||||
extension->is_repeated = false;
|
||||
if (other_extension.is_lazy) {
|
||||
extension->is_lazy = true;
|
||||
extension->lazymessage_value =
|
||||
other_extension.lazymessage_value->New();
|
||||
extension->lazymessage_value->MergeFrom(
|
||||
*other_extension.lazymessage_value);
|
||||
} else {
|
||||
extension->is_lazy = false;
|
||||
extension->message_value =
|
||||
other_extension.message_value->New();
|
||||
extension->message_value->CheckTypeAndMergeFrom(
|
||||
*other_extension.message_value);
|
||||
}
|
||||
} else {
|
||||
GOOGLE_DCHECK_EQ(extension->type, other_extension.type);
|
||||
GOOGLE_DCHECK_EQ(extension->is_packed,other_extension.is_packed);
|
||||
GOOGLE_DCHECK(!extension->is_repeated);
|
||||
if (other_extension.is_lazy) {
|
||||
if (extension->is_lazy) {
|
||||
extension->lazymessage_value->MergeFrom(
|
||||
*other_extension.lazymessage_value);
|
||||
} else {
|
||||
extension->message_value->CheckTypeAndMergeFrom(
|
||||
other_extension.lazymessage_value->GetMessage(
|
||||
*extension->message_value));
|
||||
}
|
||||
} else {
|
||||
if (extension->is_lazy) {
|
||||
extension->lazymessage_value->MutableMessage(
|
||||
*other_extension.message_value)->CheckTypeAndMergeFrom(
|
||||
*other_extension.message_value);
|
||||
} else {
|
||||
extension->message_value->CheckTypeAndMergeFrom(
|
||||
*other_extension.message_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
extension->is_cleared = false;
|
||||
case WireFormatLite::CPPTYPE_MESSAGE:
|
||||
MutableMessage(iter->first, other_extension.type,
|
||||
*other_extension.message_value,
|
||||
other_extension.descriptor)
|
||||
->CheckTypeAndMergeFrom(*other_extension.message_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -907,36 +691,6 @@ void ExtensionSet::Swap(ExtensionSet* x) {
|
|||
extensions_.swap(x->extensions_);
|
||||
}
|
||||
|
||||
void ExtensionSet::SwapExtension(ExtensionSet* other,
|
||||
int number) {
|
||||
if (this == other) return;
|
||||
map<int, Extension>::iterator this_iter = extensions_.find(number);
|
||||
map<int, Extension>::iterator other_iter = other->extensions_.find(number);
|
||||
|
||||
if (this_iter == extensions_.end() &&
|
||||
other_iter == other->extensions_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this_iter != extensions_.end() &&
|
||||
other_iter != other->extensions_.end()) {
|
||||
std::swap(this_iter->second, other_iter->second);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this_iter == extensions_.end()) {
|
||||
extensions_.insert(make_pair(number, other_iter->second));
|
||||
other->extensions_.erase(number);
|
||||
return;
|
||||
}
|
||||
|
||||
if (other_iter == other->extensions_.end()) {
|
||||
other->extensions_.insert(make_pair(number, this_iter->second));
|
||||
extensions_.erase(number);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::IsInitialized() const {
|
||||
// Extensions are never required. However, we need to check that all
|
||||
// embedded messages are initialized.
|
||||
|
@ -952,11 +706,7 @@ bool ExtensionSet::IsInitialized() const {
|
|||
}
|
||||
} else {
|
||||
if (!extension.is_cleared) {
|
||||
if (extension.is_lazy) {
|
||||
if (!extension.lazymessage_value->IsInitialized()) return false;
|
||||
} else {
|
||||
if (!extension.message_value->IsInitialized()) return false;
|
||||
}
|
||||
if (!extension.message_value->IsInitialized()) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -965,60 +715,27 @@ bool ExtensionSet::IsInitialized() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ExtensionSet::FindExtensionInfoFromTag(
|
||||
uint32 tag, ExtensionFinder* extension_finder, int* field_number,
|
||||
ExtensionInfo* extension, bool* was_packed_on_wire) {
|
||||
*field_number = WireFormatLite::GetTagFieldNumber(tag);
|
||||
WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
|
||||
return FindExtensionInfoFromFieldNumber(wire_type, *field_number,
|
||||
extension_finder, extension,
|
||||
was_packed_on_wire);
|
||||
}
|
||||
|
||||
bool ExtensionSet::FindExtensionInfoFromFieldNumber(
|
||||
int wire_type, int field_number, ExtensionFinder* extension_finder,
|
||||
ExtensionInfo* extension, bool* was_packed_on_wire) {
|
||||
if (!extension_finder->Find(field_number, extension)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WireFormatLite::WireType expected_wire_type =
|
||||
WireFormatLite::WireTypeForFieldType(real_type(extension->type));
|
||||
|
||||
// Check if this is a packed field.
|
||||
*was_packed_on_wire = false;
|
||||
if (extension->is_repeated &&
|
||||
wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED &&
|
||||
is_packable(expected_wire_type)) {
|
||||
*was_packed_on_wire = true;
|
||||
return true;
|
||||
}
|
||||
// Otherwise the wire type must match.
|
||||
return expected_wire_type == wire_type;
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper) {
|
||||
int number;
|
||||
bool was_packed_on_wire;
|
||||
ExtensionInfo extension;
|
||||
if (!FindExtensionInfoFromTag(
|
||||
tag, extension_finder, &number, &extension, &was_packed_on_wire)) {
|
||||
return field_skipper->SkipField(input, tag);
|
||||
} else {
|
||||
return ParseFieldWithExtensionInfo(
|
||||
number, was_packed_on_wire, extension, input, field_skipper);
|
||||
}
|
||||
}
|
||||
int number = WireFormatLite::GetTagFieldNumber(tag);
|
||||
WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
|
||||
|
||||
bool ExtensionSet::ParseFieldWithExtensionInfo(
|
||||
int number, bool was_packed_on_wire, const ExtensionInfo& extension,
|
||||
io::CodedInputStream* input,
|
||||
FieldSkipper* field_skipper) {
|
||||
// Explicitly not read extension.is_packed, instead check whether the field
|
||||
// was encoded in packed form on the wire.
|
||||
if (was_packed_on_wire) {
|
||||
ExtensionInfo extension;
|
||||
bool is_unknown;
|
||||
if (!extension_finder->Find(number, &extension)) {
|
||||
is_unknown = true;
|
||||
} else if (extension.is_packed) {
|
||||
is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
||||
} else {
|
||||
WireFormatLite::WireType expected_wire_type =
|
||||
WireFormatLite::WireTypeForFieldType(real_type(extension.type));
|
||||
is_unknown = (wire_type != expected_wire_type);
|
||||
}
|
||||
|
||||
if (is_unknown) {
|
||||
field_skipper->SkipField(input, tag);
|
||||
} else if (extension.is_packed) {
|
||||
uint32 size;
|
||||
if (!input->ReadVarint32(&size)) return false;
|
||||
io::CodedInputStream::Limit limit = input->PushLimit(size);
|
||||
|
@ -1032,8 +749,7 @@ bool ExtensionSet::ParseFieldWithExtensionInfo(
|
|||
CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \
|
||||
input, &value)) return false; \
|
||||
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
|
||||
extension.is_packed, value, \
|
||||
extension.descriptor); \
|
||||
true, value, extension.descriptor); \
|
||||
} \
|
||||
break
|
||||
|
||||
|
@ -1059,8 +775,8 @@ bool ExtensionSet::ParseFieldWithExtensionInfo(
|
|||
input, &value)) return false;
|
||||
if (extension.enum_validity_check.func(
|
||||
extension.enum_validity_check.arg, value)) {
|
||||
AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed,
|
||||
value, extension.descriptor);
|
||||
AddEnum(number, WireFormatLite::TYPE_ENUM, true, value,
|
||||
extension.descriptor);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1082,10 +798,9 @@ bool ExtensionSet::ParseFieldWithExtensionInfo(
|
|||
if (!WireFormatLite::ReadPrimitive< \
|
||||
CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \
|
||||
input, &value)) return false; \
|
||||
if (extension.is_repeated) { \
|
||||
if (extension.is_repeated) { \
|
||||
Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \
|
||||
extension.is_packed, value, \
|
||||
extension.descriptor); \
|
||||
false, value, extension.descriptor); \
|
||||
} else { \
|
||||
Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \
|
||||
extension.descriptor); \
|
||||
|
@ -1117,7 +832,7 @@ bool ExtensionSet::ParseFieldWithExtensionInfo(
|
|||
// Invalid value. Treat as unknown.
|
||||
field_skipper->SkipUnknownEnum(number, value);
|
||||
} else if (extension.is_repeated) {
|
||||
AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
|
||||
AddEnum(number, WireFormatLite::TYPE_ENUM, false, value,
|
||||
extension.descriptor);
|
||||
} else {
|
||||
SetEnum(number, WireFormatLite::TYPE_ENUM, value,
|
||||
|
@ -1137,8 +852,8 @@ bool ExtensionSet::ParseFieldWithExtensionInfo(
|
|||
|
||||
case WireFormatLite::TYPE_BYTES: {
|
||||
string* value = extension.is_repeated ?
|
||||
AddString(number, WireFormatLite::TYPE_BYTES, extension.descriptor) :
|
||||
MutableString(number, WireFormatLite::TYPE_BYTES,
|
||||
AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) :
|
||||
MutableString(number, WireFormatLite::TYPE_STRING,
|
||||
extension.descriptor);
|
||||
if (!WireFormatLite::ReadBytes(input, value)) return false;
|
||||
break;
|
||||
|
@ -1176,24 +891,125 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
|||
return ParseField(tag, input, &finder, &skipper);
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const MessageLite* containing_type,
|
||||
io::CodedOutputStream* unknown_fields) {
|
||||
CodedOutputStreamFieldSkipper skipper(unknown_fields);
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
}
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
// bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
// const MessageLite* containing_type,
|
||||
// UnknownFieldSet* unknown_fields)
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper) {
|
||||
while (true) {
|
||||
uint32 tag = input->ReadTag();
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return true;
|
||||
case WireFormatLite::kMessageSetItemStartTag:
|
||||
if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!ParseField(tag, input, extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
const MessageLite* containing_type) {
|
||||
FieldSkipper skipper;
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
}
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
// bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
// const MessageLite* containing_type,
|
||||
// UnknownFieldSet* unknown_fields);
|
||||
|
||||
bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper) {
|
||||
// TODO(kenton): It would be nice to share code between this and
|
||||
// WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
|
||||
// differences would be hard to factor out.
|
||||
|
||||
// This method parses a group which should contain two fields:
|
||||
// required int32 type_id = 2;
|
||||
// required data message = 3;
|
||||
|
||||
// Once we see a type_id, we'll construct a fake tag for this extension
|
||||
// which is the tag it would have had under the proto2 extensions wire
|
||||
// format.
|
||||
uint32 fake_tag = 0;
|
||||
|
||||
// If we see message data before the type_id, we'll append it to this so
|
||||
// we can parse it later. This will probably never happen in practice,
|
||||
// as no MessageSet encoder I know of writes the message before the type ID.
|
||||
// But, it's technically valid so we should allow it.
|
||||
// TODO(kenton): Use a Cord instead? Do I care?
|
||||
string message_data;
|
||||
|
||||
while (true) {
|
||||
uint32 tag = input->ReadTag();
|
||||
if (tag == 0) return false;
|
||||
|
||||
switch (tag) {
|
||||
case WireFormatLite::kMessageSetTypeIdTag: {
|
||||
uint32 type_id;
|
||||
if (!input->ReadVarint32(&type_id)) return false;
|
||||
fake_tag = WireFormatLite::MakeTag(type_id,
|
||||
WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
if (!message_data.empty()) {
|
||||
// We saw some message data before the type_id. Have to parse it
|
||||
// now.
|
||||
io::CodedInputStream sub_input(
|
||||
reinterpret_cast<const uint8*>(message_data.data()),
|
||||
message_data.size());
|
||||
if (!ParseField(fake_tag, &sub_input,
|
||||
extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
message_data.clear();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WireFormatLite::kMessageSetMessageTag: {
|
||||
if (fake_tag == 0) {
|
||||
// We haven't seen a type_id yet. Append this data to message_data.
|
||||
string temp;
|
||||
uint32 length;
|
||||
if (!input->ReadVarint32(&length)) return false;
|
||||
if (!input->ReadString(&temp, length)) return false;
|
||||
message_data.append(temp);
|
||||
} else {
|
||||
// Already saw type_id, so we can parse this directly.
|
||||
if (!ParseField(fake_tag, input,
|
||||
extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WireFormatLite::kMessageSetItemEndTag: {
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!field_skipper->SkipField(input, tag)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionSet::SerializeWithCachedSizes(
|
||||
int start_field_number, int end_field_number,
|
||||
io::CodedOutputStream* output) const {
|
||||
|
@ -1205,6 +1021,14 @@ void ExtensionSet::SerializeWithCachedSizes(
|
|||
}
|
||||
}
|
||||
|
||||
void ExtensionSet::SerializeMessageSetWithCachedSizes(
|
||||
io::CodedOutputStream* output) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
|
||||
iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
|
||||
}
|
||||
}
|
||||
|
||||
int ExtensionSet::ByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
|
@ -1216,6 +1040,17 @@ int ExtensionSet::ByteSize() const {
|
|||
return total_size;
|
||||
}
|
||||
|
||||
int ExtensionSet::MessageSetByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
total_size += iter->second.MessageSetItemByteSize(iter->first);
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
// int ExtensionSet::SpaceUsedExcludingSelf() const
|
||||
|
||||
|
@ -1259,11 +1094,7 @@ void ExtensionSet::Extension::Clear() {
|
|||
string_value->clear();
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_MESSAGE:
|
||||
if (is_lazy) {
|
||||
lazymessage_value->Clear();
|
||||
} else {
|
||||
message_value->Clear();
|
||||
}
|
||||
message_value->Clear();
|
||||
break;
|
||||
default:
|
||||
// No need to do anything. Get*() will return the default value
|
||||
|
@ -1375,18 +1206,40 @@ void ExtensionSet::Extension::SerializeFieldWithCachedSizes(
|
|||
HANDLE_TYPE( BYTES, Bytes, *string_value);
|
||||
HANDLE_TYPE( ENUM, Enum, enum_value);
|
||||
HANDLE_TYPE( GROUP, Group, *message_value);
|
||||
HANDLE_TYPE( MESSAGE, Message, *message_value);
|
||||
#undef HANDLE_TYPE
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
if (is_lazy) {
|
||||
lazymessage_value->WriteMessage(number, output);
|
||||
} else {
|
||||
WireFormatLite::WriteMessage(number, *message_value, output);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
|
||||
int number,
|
||||
io::CodedOutputStream* output) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but serialize it the normal way.
|
||||
SerializeFieldWithCachedSizes(number, output);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_cleared) return;
|
||||
|
||||
// Start group.
|
||||
output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
|
||||
|
||||
// Write type ID.
|
||||
WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
|
||||
number,
|
||||
output);
|
||||
// Write message.
|
||||
WireFormatLite::WriteMessageMaybeToArray(
|
||||
WireFormatLite::kMessageSetMessageNumber,
|
||||
*message_value,
|
||||
output);
|
||||
|
||||
// End group.
|
||||
output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::ByteSize(int number) const {
|
||||
int result = 0;
|
||||
|
||||
|
@ -1500,16 +1353,8 @@ int ExtensionSet::Extension::ByteSize(int number) const {
|
|||
HANDLE_TYPE( BYTES, Bytes, *string_value);
|
||||
HANDLE_TYPE( ENUM, Enum, enum_value);
|
||||
HANDLE_TYPE( GROUP, Group, *message_value);
|
||||
HANDLE_TYPE( MESSAGE, Message, *message_value);
|
||||
#undef HANDLE_TYPE
|
||||
case WireFormatLite::TYPE_MESSAGE: {
|
||||
if (is_lazy) {
|
||||
int size = lazymessage_value->ByteSize();
|
||||
result += io::CodedOutputStream::VarintSize32(size) + size;
|
||||
} else {
|
||||
result += WireFormatLite::MessageSize(*message_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Stuff with fixed size.
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE) \
|
||||
|
@ -1530,6 +1375,29 @@ int ExtensionSet::Extension::ByteSize(int number) const {
|
|||
return result;
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but compute the byte size for it the
|
||||
// normal way.
|
||||
return ByteSize(number);
|
||||
}
|
||||
|
||||
if (is_cleared) return 0;
|
||||
|
||||
int our_size = WireFormatLite::kMessageSetItemTagsSize;
|
||||
|
||||
// type_id
|
||||
our_size += io::CodedOutputStream::VarintSize32(number);
|
||||
|
||||
// message
|
||||
int message_size = message_value->ByteSize();
|
||||
|
||||
our_size += io::CodedOutputStream::VarintSize32(message_size);
|
||||
our_size += message_size;
|
||||
|
||||
return our_size;
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::GetSize() const {
|
||||
GOOGLE_DCHECK(is_repeated);
|
||||
switch (cpp_type(type)) {
|
||||
|
@ -1580,11 +1448,7 @@ void ExtensionSet::Extension::Free() {
|
|||
delete string_value;
|
||||
break;
|
||||
case WireFormatLite::CPPTYPE_MESSAGE:
|
||||
if (is_lazy) {
|
||||
delete lazymessage_value;
|
||||
} else {
|
||||
delete message_value;
|
||||
}
|
||||
delete message_value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1595,69 +1459,6 @@ void ExtensionSet::Extension::Free() {
|
|||
// Defined in extension_set_heavy.cc.
|
||||
// int ExtensionSet::Extension::SpaceUsedExcludingSelf() const
|
||||
|
||||
// ==================================================================
|
||||
// Default repeated field instances for iterator-compatible accessors
|
||||
|
||||
const RepeatedStringTypeTraits::RepeatedFieldType*
|
||||
RepeatedStringTypeTraits::default_repeated_field_ = NULL;
|
||||
|
||||
const RepeatedMessageGenericTypeTraits::RepeatedFieldType*
|
||||
RepeatedMessageGenericTypeTraits::default_repeated_field_ = NULL;
|
||||
|
||||
#define PROTOBUF_DEFINE_DEFAULT_REPEATED(TYPE) \
|
||||
const RepeatedField<TYPE>* \
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_##TYPE##_ = NULL;
|
||||
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(int32)
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(int64)
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(uint32)
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(uint64)
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(double)
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(float)
|
||||
PROTOBUF_DEFINE_DEFAULT_REPEATED(bool)
|
||||
|
||||
#undef PROTOBUF_DEFINE_DEFAULT_REPEATED
|
||||
|
||||
struct StaticDefaultRepeatedFieldsInitializer {
|
||||
StaticDefaultRepeatedFieldsInitializer() {
|
||||
InitializeDefaultRepeatedFields();
|
||||
OnShutdown(&DestroyDefaultRepeatedFields);
|
||||
}
|
||||
} static_repeated_fields_initializer;
|
||||
|
||||
void InitializeDefaultRepeatedFields() {
|
||||
RepeatedStringTypeTraits::default_repeated_field_ =
|
||||
new RepeatedStringTypeTraits::RepeatedFieldType;
|
||||
RepeatedMessageGenericTypeTraits::default_repeated_field_ =
|
||||
new RepeatedMessageGenericTypeTraits::RepeatedFieldType;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_ =
|
||||
new RepeatedField<int32>;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_ =
|
||||
new RepeatedField<int64>;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_ =
|
||||
new RepeatedField<uint32>;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_ =
|
||||
new RepeatedField<uint64>;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_ =
|
||||
new RepeatedField<double>;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_ =
|
||||
new RepeatedField<float>;
|
||||
RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_ =
|
||||
new RepeatedField<bool>;
|
||||
}
|
||||
|
||||
void DestroyDefaultRepeatedFields() {
|
||||
delete RepeatedStringTypeTraits::default_repeated_field_;
|
||||
delete RepeatedMessageGenericTypeTraits::default_repeated_field_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int32_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_int64_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint32_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_uint64_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_double_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_float_;
|
||||
delete RepeatedPrimitiveGenericTypeTraits::default_repeated_field_bool_;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -46,8 +46,6 @@
|
|||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
|
@ -64,7 +62,10 @@ namespace protobuf {
|
|||
}
|
||||
namespace internal {
|
||||
class FieldSkipper; // wire_format_lite.h
|
||||
class RepeatedPtrFieldBase; // repeated_field.h
|
||||
}
|
||||
template <typename Element> class RepeatedField; // repeated_field.h
|
||||
template <typename Element> class RepeatedPtrField; // repeated_field.h
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
|
@ -88,8 +89,8 @@ typedef bool EnumValidityFuncWithArg(const void* arg, int number);
|
|||
// Information about a registered extension.
|
||||
struct ExtensionInfo {
|
||||
inline ExtensionInfo() {}
|
||||
inline ExtensionInfo(FieldType type_param, bool isrepeated, bool ispacked)
|
||||
: type(type_param), is_repeated(isrepeated), is_packed(ispacked),
|
||||
inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed)
|
||||
: type(type), is_repeated(is_repeated), is_packed(is_packed),
|
||||
descriptor(NULL) {}
|
||||
|
||||
FieldType type;
|
||||
|
@ -137,9 +138,6 @@ class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder {
|
|||
const MessageLite* containing_type_;
|
||||
};
|
||||
|
||||
// A FieldSkipper used for parsing MessageSet.
|
||||
class MessageSetFieldSkipper;
|
||||
|
||||
// Note: extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
|
||||
// finding extensions from a DescriptorPool.
|
||||
|
||||
|
@ -216,7 +214,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
|
||||
bool Has(int number) const;
|
||||
int ExtensionSize(int number) const; // Size of a repeated extension.
|
||||
int NumExtensions() const; // The number of extensions
|
||||
FieldType ExtensionType(int number) const;
|
||||
void ClearExtension(int number);
|
||||
|
||||
|
@ -254,35 +251,10 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
const MessageLite& prototype, desc);
|
||||
MessageLite* MutableMessage(const FieldDescriptor* decsriptor,
|
||||
MessageFactory* factory);
|
||||
// Adds the given message to the ExtensionSet, taking ownership of the
|
||||
// message object. Existing message with the same number will be deleted.
|
||||
// If "message" is NULL, this is equivalent to "ClearExtension(number)".
|
||||
void SetAllocatedMessage(int number, FieldType type,
|
||||
const FieldDescriptor* descriptor,
|
||||
MessageLite* message);
|
||||
MessageLite* ReleaseMessage(int number, const MessageLite& prototype);
|
||||
MessageLite* ReleaseMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory);
|
||||
#undef desc
|
||||
|
||||
// repeated fields -------------------------------------------------
|
||||
|
||||
// Fetches a RepeatedField extension by number; returns |default_value|
|
||||
// if no such extension exists. User should not touch this directly; it is
|
||||
// used by the GetRepeatedExtension() method.
|
||||
const void* GetRawRepeatedField(int number, const void* default_value) const;
|
||||
// Fetches a mutable version of a RepeatedField extension by number,
|
||||
// instantiating one if none exists. Similar to above, user should not use
|
||||
// this directly; it underlies MutableRepeatedExtension().
|
||||
void* MutableRawRepeatedField(int number, FieldType field_type,
|
||||
bool packed, const FieldDescriptor* desc);
|
||||
|
||||
// This is an overload of MutableRawRepeatedField to maintain compatibility
|
||||
// with old code using a previous API. This version of
|
||||
// MutableRawRepeatedField() will GOOGLE_CHECK-fail on a missing extension.
|
||||
// (E.g.: borg/clients/internal/proto1/proto2_reflection.cc.)
|
||||
void* MutableRawRepeatedField(int number);
|
||||
|
||||
int32 GetRepeatedInt32 (int number, int index) const;
|
||||
int64 GetRepeatedInt64 (int number, int index) const;
|
||||
uint32 GetRepeatedUInt32(int number, int index) const;
|
||||
|
@ -324,7 +296,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
#undef desc
|
||||
|
||||
void RemoveLast(int number);
|
||||
MessageLite* ReleaseLast(int number);
|
||||
void SwapElements(int number, int index1, int index2);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
@ -339,35 +310,31 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
void Clear();
|
||||
void MergeFrom(const ExtensionSet& other);
|
||||
void Swap(ExtensionSet* other);
|
||||
void SwapExtension(ExtensionSet* other, int number);
|
||||
bool IsInitialized() const;
|
||||
|
||||
// Parses a single extension from the input. The input should start out
|
||||
// positioned immediately after the tag.
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically). |containing_type| is the default
|
||||
// Parses a single extension from the input. The input should start out
|
||||
// positioned immediately after the tag. |containing_type| is the default
|
||||
// instance for the containing message; it is used only to look up the
|
||||
// extension by number. See RegisterExtension(), above. Unlike the other
|
||||
// methods of ExtensionSet, this only works for generated message types --
|
||||
// it looks up extensions registered using RegisterExtension().
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically).
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const MessageLite* containing_type);
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields);
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const MessageLite* containing_type,
|
||||
io::CodedOutputStream* unknown_fields);
|
||||
|
||||
// Parse an entire message in MessageSet format. Such messages have no
|
||||
// fields, only extensions.
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
MessageSetFieldSkipper* field_skipper);
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically).
|
||||
|
@ -415,49 +382,18 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
|
||||
private:
|
||||
|
||||
// Interface of a lazily parsed singular message extension.
|
||||
class LIBPROTOBUF_EXPORT LazyMessageExtension {
|
||||
public:
|
||||
LazyMessageExtension() {}
|
||||
virtual ~LazyMessageExtension() {}
|
||||
|
||||
virtual LazyMessageExtension* New() const = 0;
|
||||
virtual const MessageLite& GetMessage(
|
||||
const MessageLite& prototype) const = 0;
|
||||
virtual MessageLite* MutableMessage(const MessageLite& prototype) = 0;
|
||||
virtual void SetAllocatedMessage(MessageLite *message) = 0;
|
||||
virtual MessageLite* ReleaseMessage(const MessageLite& prototype) = 0;
|
||||
|
||||
virtual bool IsInitialized() const = 0;
|
||||
virtual int ByteSize() const = 0;
|
||||
virtual int SpaceUsed() const = 0;
|
||||
|
||||
virtual void MergeFrom(const LazyMessageExtension& other) = 0;
|
||||
virtual void Clear() = 0;
|
||||
|
||||
virtual bool ReadMessage(const MessageLite& prototype,
|
||||
io::CodedInputStream* input) = 0;
|
||||
virtual void WriteMessage(int number,
|
||||
io::CodedOutputStream* output) const = 0;
|
||||
virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
|
||||
};
|
||||
struct Extension {
|
||||
// The order of these fields packs Extension into 24 bytes when using 8
|
||||
// byte alignment. Consider this when adding or removing fields here.
|
||||
union {
|
||||
int32 int32_value;
|
||||
int64 int64_value;
|
||||
uint32 uint32_value;
|
||||
uint64 uint64_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
bool bool_value;
|
||||
int enum_value;
|
||||
string* string_value;
|
||||
MessageLite* message_value;
|
||||
LazyMessageExtension* lazymessage_value;
|
||||
int32 int32_value;
|
||||
int64 int64_value;
|
||||
uint32 uint32_value;
|
||||
uint64 uint64_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
bool bool_value;
|
||||
int enum_value;
|
||||
string* string_value;
|
||||
MessageLite* message_value;
|
||||
|
||||
RepeatedField <int32 >* repeated_int32_value;
|
||||
RepeatedField <int64 >* repeated_int64_value;
|
||||
|
@ -480,28 +416,21 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
// removing it from the map, we just set is_cleared = true. This has no
|
||||
// meaning for repeated types; for those, the size of the RepeatedField
|
||||
// simply becomes zero when cleared.
|
||||
bool is_cleared : 4;
|
||||
|
||||
// For singular message types, indicates whether lazy parsing is enabled
|
||||
// for this extension. This field is only valid when type == TYPE_MESSAGE
|
||||
// and !is_repeated because we only support lazy parsing for singular
|
||||
// message types currently. If is_lazy = true, the extension is stored in
|
||||
// lazymessage_value. Otherwise, the extension will be message_value.
|
||||
bool is_lazy : 4;
|
||||
bool is_cleared;
|
||||
|
||||
// For repeated types, this indicates if the [packed=true] option is set.
|
||||
bool is_packed;
|
||||
|
||||
// For packed fields, the size of the packed data is recorded here when
|
||||
// ByteSize() is called then used during serialization.
|
||||
// TODO(kenton): Use atomic<int> when C++ supports it.
|
||||
mutable int cached_size;
|
||||
|
||||
// The descriptor for this extension, if one exists and is known. May be
|
||||
// NULL. Must not be NULL if the descriptor for the extension does not
|
||||
// live in the same pool as the descriptor for the containing type.
|
||||
const FieldDescriptor* descriptor;
|
||||
|
||||
// For packed fields, the size of the packed data is recorded here when
|
||||
// ByteSize() is called then used during serialization.
|
||||
// TODO(kenton): Use atomic<int> when C++ supports it.
|
||||
mutable int cached_size;
|
||||
|
||||
// Some helper methods for operations on a single Extension.
|
||||
void SerializeFieldWithCachedSizes(
|
||||
int number,
|
||||
|
@ -524,40 +453,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
};
|
||||
|
||||
|
||||
// Returns true and fills field_number and extension if extension is found.
|
||||
// Note to support packed repeated field compatibility, it also fills whether
|
||||
// the tag on wire is packed, which can be different from
|
||||
// extension->is_packed (whether packed=true is specified).
|
||||
bool FindExtensionInfoFromTag(uint32 tag, ExtensionFinder* extension_finder,
|
||||
int* field_number, ExtensionInfo* extension,
|
||||
bool* was_packed_on_wire);
|
||||
|
||||
// Returns true and fills extension if extension is found.
|
||||
// Note to support packed repeated field compatibility, it also fills whether
|
||||
// the tag on wire is packed, which can be different from
|
||||
// extension->is_packed (whether packed=true is specified).
|
||||
bool FindExtensionInfoFromFieldNumber(int wire_type, int field_number,
|
||||
ExtensionFinder* extension_finder,
|
||||
ExtensionInfo* extension,
|
||||
bool* was_packed_on_wire);
|
||||
|
||||
// Parses a single extension from the input. The input should start out
|
||||
// positioned immediately after the wire tag. This method is called in
|
||||
// ParseField() after field number and was_packed_on_wire is extracted from
|
||||
// the wire tag and ExtensionInfo is found by the field number.
|
||||
bool ParseFieldWithExtensionInfo(int field_number,
|
||||
bool was_packed_on_wire,
|
||||
const ExtensionInfo& extension,
|
||||
io::CodedInputStream* input,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Like ParseField(), but this method may parse singular message extensions
|
||||
// lazily depending on the value of FLAGS_eagerly_parse_message_sets.
|
||||
bool ParseFieldMaybeLazily(int wire_type, int field_number,
|
||||
io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
MessageSetFieldSkipper* field_skipper);
|
||||
|
||||
// Gets the extension with the given number, creating it if it does not
|
||||
// already exist. Returns true if the extension did not already exist.
|
||||
bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
|
||||
|
@ -567,7 +462,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
// tag has been read.
|
||||
bool ParseMessageSetItem(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
MessageSetFieldSkipper* field_skipper);
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
|
||||
// Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This
|
||||
|
@ -586,7 +481,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet {
|
|||
// only contain a small number of extensions whereas hash_map is optimized
|
||||
// for 100 elements or more. Also, we want AppendToList() to order fields
|
||||
// by field number.
|
||||
std::map<int, Extension> extensions_;
|
||||
map<int, Extension> extensions_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
|
||||
};
|
||||
|
@ -622,16 +517,6 @@ inline void ExtensionSet::AddString(int number, FieldType type,
|
|||
// public:
|
||||
// typedef ? ConstType;
|
||||
// typedef ? MutableType;
|
||||
// // TypeTraits for singular fields and repeated fields will define the
|
||||
// // symbol "Singular" or "Repeated" respectively. These two symbols will
|
||||
// // be used in extension accessors to distinguish between singular
|
||||
// // extensions and repeated extensions. If the TypeTraits for the passed
|
||||
// // in extension doesn't have the expected symbol defined, it means the
|
||||
// // user is passing a repeated extension to a singular accessor, or the
|
||||
// // opposite. In that case the C++ compiler will generate an error
|
||||
// // message "no matching member function" to inform the user.
|
||||
// typedef ? Singular
|
||||
// typedef ? Repeated
|
||||
//
|
||||
// static inline ConstType Get(int number, const ExtensionSet& set);
|
||||
// static inline void Set(int number, ConstType value, ExtensionSet* set);
|
||||
|
@ -670,8 +555,6 @@ template <typename Type>
|
|||
class PrimitiveTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
typedef Type MutableType;
|
||||
typedef PrimitiveTypeTraits<Type> Singular;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value);
|
||||
|
@ -683,41 +566,11 @@ template <typename Type>
|
|||
class RepeatedPrimitiveTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
typedef Type MutableType;
|
||||
typedef RepeatedPrimitiveTypeTraits<Type> Repeated;
|
||||
|
||||
typedef RepeatedField<Type> RepeatedFieldType;
|
||||
|
||||
static inline Type Get(int number, const ExtensionSet& set, int index);
|
||||
static inline void Set(int number, int index, Type value, ExtensionSet* set);
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool is_packed, Type value, ExtensionSet* set);
|
||||
|
||||
static inline const RepeatedField<ConstType>&
|
||||
GetRepeated(int number, const ExtensionSet& set);
|
||||
static inline RepeatedField<Type>*
|
||||
MutableRepeated(int number, FieldType field_type,
|
||||
bool is_packed, ExtensionSet* set);
|
||||
|
||||
static const RepeatedFieldType* GetDefaultRepeatedField();
|
||||
};
|
||||
|
||||
// Declared here so that this can be friended below.
|
||||
void InitializeDefaultRepeatedFields();
|
||||
void DestroyDefaultRepeatedFields();
|
||||
|
||||
class LIBPROTOBUF_EXPORT RepeatedPrimitiveGenericTypeTraits {
|
||||
private:
|
||||
template<typename Type> friend class RepeatedPrimitiveTypeTraits;
|
||||
friend void InitializeDefaultRepeatedFields();
|
||||
friend void DestroyDefaultRepeatedFields();
|
||||
static const RepeatedField<int32>* default_repeated_field_int32_;
|
||||
static const RepeatedField<int64>* default_repeated_field_int64_;
|
||||
static const RepeatedField<uint32>* default_repeated_field_uint32_;
|
||||
static const RepeatedField<uint64>* default_repeated_field_uint64_;
|
||||
static const RepeatedField<double>* default_repeated_field_double_;
|
||||
static const RepeatedField<float>* default_repeated_field_float_;
|
||||
static const RepeatedField<bool>* default_repeated_field_bool_;
|
||||
};
|
||||
|
||||
#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \
|
||||
|
@ -742,26 +595,6 @@ template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
|
|||
int number, FieldType field_type, bool is_packed, \
|
||||
TYPE value, ExtensionSet* set) { \
|
||||
set->Add##METHOD(number, field_type, is_packed, value, NULL); \
|
||||
} \
|
||||
template<> inline const RepeatedField<TYPE>* \
|
||||
RepeatedPrimitiveTypeTraits<TYPE>::GetDefaultRepeatedField() { \
|
||||
return RepeatedPrimitiveGenericTypeTraits:: \
|
||||
default_repeated_field_##TYPE##_; \
|
||||
} \
|
||||
template<> inline const RepeatedField<TYPE>& \
|
||||
RepeatedPrimitiveTypeTraits<TYPE>::GetRepeated(int number, \
|
||||
const ExtensionSet& set) { \
|
||||
return *reinterpret_cast<const RepeatedField<TYPE>*>( \
|
||||
set.GetRawRepeatedField( \
|
||||
number, GetDefaultRepeatedField())); \
|
||||
} \
|
||||
template<> inline RepeatedField<TYPE>* \
|
||||
RepeatedPrimitiveTypeTraits<TYPE>::MutableRepeated(int number, \
|
||||
FieldType field_type, \
|
||||
bool is_packed, \
|
||||
ExtensionSet* set) { \
|
||||
return reinterpret_cast<RepeatedField<TYPE>*>( \
|
||||
set->MutableRawRepeatedField(number, field_type, is_packed, NULL)); \
|
||||
}
|
||||
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32)
|
||||
|
@ -782,7 +615,6 @@ class LIBPROTOBUF_EXPORT StringTypeTraits {
|
|||
public:
|
||||
typedef const string& ConstType;
|
||||
typedef string* MutableType;
|
||||
typedef StringTypeTraits Singular;
|
||||
|
||||
static inline const string& Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
|
@ -802,9 +634,6 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
|
|||
public:
|
||||
typedef const string& ConstType;
|
||||
typedef string* MutableType;
|
||||
typedef RepeatedStringTypeTraits Repeated;
|
||||
|
||||
typedef RepeatedPtrField<string> RepeatedFieldType;
|
||||
|
||||
static inline const string& Get(int number, const ExtensionSet& set,
|
||||
int index) {
|
||||
|
@ -826,28 +655,6 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
|
|||
ExtensionSet* set) {
|
||||
return set->AddString(number, field_type, NULL);
|
||||
}
|
||||
static inline const RepeatedPtrField<string>&
|
||||
GetRepeated(int number, const ExtensionSet& set) {
|
||||
return *reinterpret_cast<const RepeatedPtrField<string>*>(
|
||||
set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
|
||||
}
|
||||
|
||||
static inline RepeatedPtrField<string>*
|
||||
MutableRepeated(int number, FieldType field_type,
|
||||
bool is_packed, ExtensionSet* set) {
|
||||
return reinterpret_cast<RepeatedPtrField<string>*>(
|
||||
set->MutableRawRepeatedField(number, field_type,
|
||||
is_packed, NULL));
|
||||
}
|
||||
|
||||
static const RepeatedFieldType* GetDefaultRepeatedField() {
|
||||
return default_repeated_field_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend void InitializeDefaultRepeatedFields();
|
||||
friend void DestroyDefaultRepeatedFields();
|
||||
static const RepeatedFieldType *default_repeated_field_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
@ -859,8 +666,6 @@ template <typename Type, bool IsValid(int)>
|
|||
class EnumTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
typedef Type MutableType;
|
||||
typedef EnumTypeTraits<Type, IsValid> Singular;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
|
@ -877,10 +682,6 @@ template <typename Type, bool IsValid(int)>
|
|||
class RepeatedEnumTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
typedef Type MutableType;
|
||||
typedef RepeatedEnumTypeTraits<Type, IsValid> Repeated;
|
||||
|
||||
typedef RepeatedField<Type> RepeatedFieldType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
|
||||
return static_cast<Type>(set.GetRepeatedEnum(number, index));
|
||||
|
@ -895,35 +696,6 @@ class RepeatedEnumTypeTraits {
|
|||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->AddEnum(number, field_type, is_packed, value, NULL);
|
||||
}
|
||||
static inline const RepeatedField<Type>& GetRepeated(int number,
|
||||
const ExtensionSet&
|
||||
set) {
|
||||
// Hack: the `Extension` struct stores a RepeatedField<int> for enums.
|
||||
// RepeatedField<int> cannot implicitly convert to RepeatedField<EnumType>
|
||||
// so we need to do some casting magic. See message.h for similar
|
||||
// contortions for non-extension fields.
|
||||
return *reinterpret_cast<const RepeatedField<Type>*>(
|
||||
set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
|
||||
}
|
||||
|
||||
static inline RepeatedField<Type>* MutableRepeated(int number,
|
||||
FieldType field_type,
|
||||
bool is_packed,
|
||||
ExtensionSet* set) {
|
||||
return reinterpret_cast<RepeatedField<Type>*>(
|
||||
set->MutableRawRepeatedField(number, field_type, is_packed, NULL));
|
||||
}
|
||||
|
||||
static const RepeatedFieldType* GetDefaultRepeatedField() {
|
||||
// Hack: as noted above, repeated enum fields are internally stored as a
|
||||
// RepeatedField<int>. We need to be able to instantiate global static
|
||||
// objects to return as default (empty) repeated fields on non-existent
|
||||
// extensions. We would not be able to know a-priori all of the enum types
|
||||
// (values of |Type|) to instantiate all of these, so we just re-use int32's
|
||||
// default repeated field object.
|
||||
return reinterpret_cast<const RepeatedField<Type>*>(
|
||||
RepeatedPrimitiveTypeTraits<int32>::GetDefaultRepeatedField());
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
@ -937,7 +709,6 @@ class MessageTypeTraits {
|
|||
public:
|
||||
typedef const Type& ConstType;
|
||||
typedef Type* MutableType;
|
||||
typedef MessageTypeTraits<Type> Singular;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
|
@ -949,28 +720,13 @@ class MessageTypeTraits {
|
|||
return static_cast<Type*>(
|
||||
set->MutableMessage(number, field_type, Type::default_instance(), NULL));
|
||||
}
|
||||
static inline void SetAllocated(int number, FieldType field_type,
|
||||
MutableType message, ExtensionSet* set) {
|
||||
set->SetAllocatedMessage(number, field_type, NULL, message);
|
||||
}
|
||||
static inline MutableType Release(int number, FieldType /* field_type */,
|
||||
ExtensionSet* set) {
|
||||
return static_cast<Type*>(set->ReleaseMessage(
|
||||
number, Type::default_instance()));
|
||||
}
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
class RepeatedMessageGenericTypeTraits;
|
||||
|
||||
template <typename Type>
|
||||
class RepeatedMessageTypeTraits {
|
||||
public:
|
||||
typedef const Type& ConstType;
|
||||
typedef Type* MutableType;
|
||||
typedef RepeatedMessageTypeTraits<Type> Repeated;
|
||||
|
||||
typedef RepeatedPtrField<Type> RepeatedFieldType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
|
||||
return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
|
||||
|
@ -983,47 +739,8 @@ class RepeatedMessageTypeTraits {
|
|||
return static_cast<Type*>(
|
||||
set->AddMessage(number, field_type, Type::default_instance(), NULL));
|
||||
}
|
||||
static inline const RepeatedPtrField<Type>& GetRepeated(int number,
|
||||
const ExtensionSet&
|
||||
set) {
|
||||
// See notes above in RepeatedEnumTypeTraits::GetRepeated(): same
|
||||
// casting hack applies here, because a RepeatedPtrField<MessageLite>
|
||||
// cannot naturally become a RepeatedPtrType<Type> even though Type is
|
||||
// presumably a message. google::protobuf::Message goes through similar contortions
|
||||
// with a reinterpret_cast<>.
|
||||
return *reinterpret_cast<const RepeatedPtrField<Type>*>(
|
||||
set.GetRawRepeatedField(number, GetDefaultRepeatedField()));
|
||||
}
|
||||
static inline RepeatedPtrField<Type>* MutableRepeated(int number,
|
||||
FieldType field_type,
|
||||
bool is_packed,
|
||||
ExtensionSet* set) {
|
||||
return reinterpret_cast<RepeatedPtrField<Type>*>(
|
||||
set->MutableRawRepeatedField(number, field_type, is_packed, NULL));
|
||||
}
|
||||
|
||||
static const RepeatedFieldType* GetDefaultRepeatedField();
|
||||
};
|
||||
|
||||
// This class exists only to hold a generic default empty repeated field for all
|
||||
// message-type repeated field extensions.
|
||||
class LIBPROTOBUF_EXPORT RepeatedMessageGenericTypeTraits {
|
||||
public:
|
||||
typedef RepeatedPtrField< ::google::protobuf::MessageLite*> RepeatedFieldType;
|
||||
private:
|
||||
template<typename Type> friend class RepeatedMessageTypeTraits;
|
||||
friend void InitializeDefaultRepeatedFields();
|
||||
friend void DestroyDefaultRepeatedFields();
|
||||
static const RepeatedFieldType* default_repeated_field_;
|
||||
};
|
||||
|
||||
template<typename Type> inline
|
||||
const typename RepeatedMessageTypeTraits<Type>::RepeatedFieldType*
|
||||
RepeatedMessageTypeTraits<Type>::GetDefaultRepeatedField() {
|
||||
return reinterpret_cast<const RepeatedFieldType*>(
|
||||
RepeatedMessageGenericTypeTraits::default_repeated_field_);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ExtensionIdentifier
|
||||
|
||||
|
@ -1070,161 +787,114 @@ class ExtensionIdentifier {
|
|||
// causes problems if the class has a nested message or enum type with that
|
||||
// name and "_TypeTraits" is technically reserved for the C++ library since
|
||||
// it starts with an underscore followed by a capital letter.
|
||||
//
|
||||
// For similar reason, we use "_field_type" and "_is_packed" as parameter names
|
||||
// below, so that "field_type" and "is_packed" can be used as field names.
|
||||
#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \
|
||||
/* Has, Size, Clear */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline bool HasExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _extensions_.Has(id.number()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void ClearExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
_extensions_.ClearExtension(id.number()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline int ExtensionSize( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _extensions_.ExtensionSize(id.number()); \
|
||||
} \
|
||||
\
|
||||
/* Singular accessors */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Singular::ConstType GetExtension( \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::ConstType GetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) const { \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _proto_TypeTraits::Get(id.number(), _extensions_, \
|
||||
id.default_value()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType MutableExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), _field_type, \
|
||||
&_extensions_); \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void SetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
|
||||
typename _proto_TypeTraits::Singular::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline void SetAllocatedExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
|
||||
typename _proto_TypeTraits::Singular::MutableType value) { \
|
||||
_proto_TypeTraits::SetAllocated(id.number(), _field_type, \
|
||||
value, &_extensions_); \
|
||||
} \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Singular::MutableType ReleaseExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
|
||||
return _proto_TypeTraits::Release(id.number(), _field_type, \
|
||||
&_extensions_); \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
/* Repeated accessors */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::ConstType GetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index) const { \
|
||||
return _proto_TypeTraits::Get(id.number(), _extensions_, index); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType MutableExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void SetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
|
||||
int index, typename _proto_TypeTraits::Repeated::ConstType value) { \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index, typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType AddExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) { \
|
||||
return _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_); \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void AddExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id, \
|
||||
typename _proto_TypeTraits::Repeated::ConstType value) { \
|
||||
_proto_TypeTraits::Add(id.number(), _field_type, _is_packed, \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Add(id.number(), field_type, is_packed, \
|
||||
value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& \
|
||||
GetRepeatedExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, \
|
||||
_is_packed>& id) const { \
|
||||
return _proto_TypeTraits::GetRepeated(id.number(), _extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType _field_type, \
|
||||
bool _is_packed> \
|
||||
inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* \
|
||||
MutableRepeatedExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, _field_type, \
|
||||
_is_packed>& id) { \
|
||||
return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, \
|
||||
_is_packed, &_extensions_); \
|
||||
}
|
||||
|
||||
} // namespace internal
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -47,17 +47,7 @@ double NaN() {
|
|||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
const ::std::string* empty_string_;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(empty_string_once_init_);
|
||||
|
||||
void DeleteEmptyString() {
|
||||
delete empty_string_;
|
||||
}
|
||||
|
||||
void InitEmptyString() {
|
||||
empty_string_ = new string;
|
||||
OnShutdown(&DeleteEmptyString);
|
||||
}
|
||||
const ::std::string kEmptyString;
|
||||
|
||||
|
||||
} // namespace internal
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -31,16 +31,52 @@
|
|||
// 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 <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/service.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class CodedInputStream; // coded_stream.h
|
||||
}
|
||||
}
|
||||
|
||||
Service::~Service() {}
|
||||
RpcChannel::~RpcChannel() {}
|
||||
RpcController::~RpcController() {}
|
||||
namespace protobuf {
|
||||
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
|
||||
#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
|
||||
# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED
|
||||
#else
|
||||
# define PROTOBUF_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
// Constants for special floating point values.
|
||||
double Infinity();
|
||||
double NaN();
|
||||
|
||||
// Constant used for empty default strings.
|
||||
extern const ::std::string kEmptyString;
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -43,7 +43,7 @@
|
|||
#include <limits.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
|
@ -69,23 +69,6 @@ inline bool NextNonEmpty(ZeroCopyInputStream* input,
|
|||
|
||||
// CodedInputStream ==================================================
|
||||
|
||||
CodedInputStream::~CodedInputStream() {
|
||||
if (input_ != NULL) {
|
||||
BackUpInputToCurrentPosition();
|
||||
}
|
||||
|
||||
if (total_bytes_warning_threshold_ == -2) {
|
||||
GOOGLE_LOG(WARNING) << "The total number of bytes read was " << total_bytes_read_;
|
||||
}
|
||||
}
|
||||
|
||||
// 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_;
|
||||
|
@ -115,7 +98,8 @@ inline void CodedInputStream::RecomputeBufferLimits() {
|
|||
|
||||
CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
|
||||
// Current position relative to the beginning of the stream.
|
||||
int current_position = CurrentPosition();
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
|
||||
Limit old_limit = current_limit_;
|
||||
|
||||
|
@ -149,9 +133,10 @@ void CodedInputStream::PopLimit(Limit limit) {
|
|||
legitimate_message_end_ = false;
|
||||
}
|
||||
|
||||
int CodedInputStream::BytesUntilLimit() const {
|
||||
int CodedInputStream::BytesUntilLimit() {
|
||||
if (current_limit_ == INT_MAX) return -1;
|
||||
int current_position = CurrentPosition();
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
|
||||
return current_limit_ - current_position;
|
||||
}
|
||||
|
@ -160,22 +145,13 @@ void CodedInputStream::SetTotalBytesLimit(
|
|||
int total_bytes_limit, int warning_threshold) {
|
||||
// Make sure the limit isn't already past, since this could confuse other
|
||||
// code.
|
||||
int current_position = CurrentPosition();
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
total_bytes_limit_ = max(current_position, total_bytes_limit);
|
||||
if (warning_threshold >= 0) {
|
||||
total_bytes_warning_threshold_ = warning_threshold;
|
||||
} else {
|
||||
// warning_threshold is negative
|
||||
total_bytes_warning_threshold_ = -1;
|
||||
}
|
||||
total_bytes_warning_threshold_ = warning_threshold;
|
||||
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_
|
||||
|
@ -256,14 +232,6 @@ bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
|
|||
buffer->clear();
|
||||
}
|
||||
|
||||
int closest_limit = 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).
|
||||
|
@ -330,16 +298,11 @@ inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
|
|||
uint32 b;
|
||||
uint32 result;
|
||||
|
||||
b = *(ptr++); result = b ; if (!(b & 0x80)) goto done;
|
||||
result -= 0x80;
|
||||
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.
|
||||
b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
|
||||
|
||||
// If the input is larger than 32 bits, we still need to read it all
|
||||
// and discard the high-order bits.
|
||||
|
@ -369,8 +332,8 @@ bool CodedInputStream::ReadVarint32Slow(uint32* value) {
|
|||
|
||||
bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
|
||||
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.
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
const uint8* end = ReadVarint32FromArray(buffer_, value);
|
||||
if (end == NULL) return false;
|
||||
|
@ -405,17 +368,16 @@ uint32 CodedInputStream::ReadTagSlow() {
|
|||
|
||||
// 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;
|
||||
uint64 result;
|
||||
if (!ReadVarint64(&result)) return 0;
|
||||
return static_cast<uint32>(result);
|
||||
}
|
||||
|
||||
uint32 CodedInputStream::ReadTagFallback() {
|
||||
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))) {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
uint32 tag;
|
||||
const uint8* end = ReadVarint32FromArray(buffer_, &tag);
|
||||
if (end == NULL) {
|
||||
|
@ -426,9 +388,7 @@ uint32 CodedInputStream::ReadTagFallback() {
|
|||
} 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_)) &&
|
||||
if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 &&
|
||||
// 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.
|
||||
|
@ -466,8 +426,8 @@ bool CodedInputStream::ReadVarint64Slow(uint64* value) {
|
|||
|
||||
bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
|
||||
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.
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
// 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.
|
||||
|
@ -479,30 +439,20 @@ bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
|
|||
// 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.
|
||||
b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
|
||||
// We have overrun the maximum size of a varint (10 bytes). The data
|
||||
// must be corrupt.
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
done:
|
||||
Advance(ptr - buffer_);
|
||||
|
@ -542,8 +492,8 @@ bool CodedInputStream::Refresh() {
|
|||
"CodedInputStream::SetTotalBytesLimit() in "
|
||||
"google/protobuf/io/coded_stream.h.";
|
||||
|
||||
// Don't warn again for this stream, and print total size at the end.
|
||||
total_bytes_warning_threshold_ = -2;
|
||||
// Don't warn again for this stream.
|
||||
total_bytes_warning_threshold_ = -1;
|
||||
}
|
||||
|
||||
const void* void_buffer;
|
||||
|
@ -587,8 +537,7 @@ CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
|
|||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
total_bytes_(0),
|
||||
had_error_(false),
|
||||
aliasing_enabled_(false) {
|
||||
had_error_(false) {
|
||||
// Eagerly Refresh() so buffer space is immediately available.
|
||||
Refresh();
|
||||
// The Refresh() may have failed. If the client doesn't write any data,
|
||||
|
@ -642,23 +591,6 @@ uint8* CodedOutputStream::WriteRawToArray(
|
|||
}
|
||||
|
||||
|
||||
void CodedOutputStream::WriteAliasedRaw(const void* data, int size) {
|
||||
if (size < buffer_size_
|
||||
) {
|
||||
WriteRaw(data, size);
|
||||
} else {
|
||||
if (buffer_size_ > 0) {
|
||||
output_->BackUp(buffer_size_);
|
||||
total_bytes_ -= buffer_size_;
|
||||
buffer_ = NULL;
|
||||
buffer_size_ = 0;
|
||||
}
|
||||
|
||||
total_bytes_ += size;
|
||||
had_error_ |= !output_->WriteAliasedRaw(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteLittleEndian32(uint32 value) {
|
||||
uint8 bytes[sizeof(value)];
|
||||
|
||||
|
@ -902,13 +834,6 @@ int CodedOutputStream::VarintSize64(uint64 value) {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -170,9 +170,6 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// successfully and the stream's byte limit.
|
||||
~CodedInputStream();
|
||||
|
||||
// Return true if this CodedInputStream reads from a flat array instead of
|
||||
// a ZeroCopyInputStream.
|
||||
inline bool IsFlat() const;
|
||||
|
||||
// Skips a number of bytes. Returns false if an underlying read error
|
||||
// occurs.
|
||||
|
@ -233,22 +230,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// Read a tag. This calls ReadVarint32() and returns the result, or returns
|
||||
// zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates
|
||||
// the last tag value, which can be checked with LastTagWas().
|
||||
// Always inline because this is only called in one place per parse loop
|
||||
// Always inline because this is only called in once place per parse loop
|
||||
// but it is called for every iteration of said loop, so it should be fast.
|
||||
// GCC doesn't want to inline this by default.
|
||||
uint32 ReadTag() GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
|
||||
// This usually a faster alternative to ReadTag() when cutoff is a manifest
|
||||
// constant. It does particularly well for cutoff >= 127. The first part
|
||||
// of the return value is the tag that was read, though it can also be 0 in
|
||||
// the cases where ReadTag() would return 0. If the second part is true
|
||||
// then the tag is known to be in [0, cutoff]. If not, the tag either is
|
||||
// above cutoff or is 0. (There's intentional wiggle room when tag is 0,
|
||||
// because that can arise in several ways, and for best performance we want
|
||||
// to avoid an extra "is tag == 0?" check here.)
|
||||
inline std::pair<uint32, bool> ReadTagWithCutoff(uint32 cutoff)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
|
||||
// Usually returns true if calling ReadVarint32() now would produce the given
|
||||
// value. Will always return false if ReadVarint32() would not return the
|
||||
// given value. If ExpectTag() returns true, it also advances past
|
||||
|
@ -275,8 +261,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// zero, and ConsumedEntireMessage() will return true.
|
||||
bool ExpectAtEnd();
|
||||
|
||||
// If the last call to ReadTag() or ReadTagWithCutoff() returned the
|
||||
// given value, returns true. Otherwise, returns false;
|
||||
// If the last call to ReadTag() returned the given value, returns true.
|
||||
// Otherwise, returns false;
|
||||
//
|
||||
// This is needed because parsers for some types of embedded messages
|
||||
// (with field type TYPE_GROUP) don't actually know that they've reached the
|
||||
|
@ -325,10 +311,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
|
||||
// Returns the number of bytes left until the nearest limit on the
|
||||
// stack is hit, or -1 if no limits are in place.
|
||||
int BytesUntilLimit() const;
|
||||
|
||||
// Returns current position relative to the beginning of the input stream.
|
||||
int CurrentPosition() const;
|
||||
int BytesUntilLimit();
|
||||
|
||||
// Total Bytes Limit -----------------------------------------------
|
||||
// To prevent malicious users from sending excessively large messages
|
||||
|
@ -344,9 +327,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// cause integer overflows is 512MB. The default limit is 64MB. Apps
|
||||
// should set shorter limits if possible. If warning_threshold is not -1,
|
||||
// a warning will be printed to stderr after warning_threshold bytes are
|
||||
// read. For backwards compatibility all negative values get squashed to -1,
|
||||
// as other negative values might have special internal meanings.
|
||||
// An error will always be printed to stderr if the limit is reached.
|
||||
// read. An error will always be printed to stderr if the limit is
|
||||
// reached.
|
||||
//
|
||||
// This is unrelated to PushLimit()/PopLimit().
|
||||
//
|
||||
|
@ -367,20 +349,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// something unusual.
|
||||
void SetTotalBytesLimit(int total_bytes_limit, int warning_threshold);
|
||||
|
||||
// The Total Bytes Limit minus the Current Position, or -1 if there
|
||||
// is no Total Bytes Limit.
|
||||
int BytesUntilTotalBytesLimit() const;
|
||||
|
||||
// Recursion Limit -------------------------------------------------
|
||||
// To prevent corrupt or malicious messages from causing stack overflows,
|
||||
// we must keep track of the depth of recursion when parsing embedded
|
||||
// messages and groups. CodedInputStream keeps track of this because it
|
||||
// is the only object that is passed down the stack during parsing.
|
||||
|
||||
// Sets the maximum recursion depth. The default is 100.
|
||||
// Sets the maximum recursion depth. The default is 64.
|
||||
void SetRecursionLimit(int limit);
|
||||
|
||||
|
||||
// Increments the current recursion depth. Returns true if the depth is
|
||||
// under the limit, false if it has gone over.
|
||||
bool IncrementRecursionDepth();
|
||||
|
@ -456,8 +433,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
//
|
||||
// Note that this feature is ignored when parsing "lite" messages as they do
|
||||
// not have descriptors.
|
||||
void SetExtensionRegistry(const DescriptorPool* pool,
|
||||
MessageFactory* factory);
|
||||
void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory);
|
||||
|
||||
// Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool
|
||||
// has been provided.
|
||||
|
@ -481,7 +457,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
int overflow_bytes_;
|
||||
|
||||
// LastTagWas() stuff.
|
||||
uint32 last_tag_; // result of last ReadTag() or ReadTagWithCutoff().
|
||||
uint32 last_tag_; // result of last ReadTag().
|
||||
|
||||
// This is set true by ReadTag{Fallback/Slow}() if it is called when exactly
|
||||
// at EOF, or by ExpectAtEnd() when it returns true. This happens when we
|
||||
|
@ -506,11 +482,6 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
// Maximum number of bytes to read, period. This is unrelated to
|
||||
// current_limit_. Set using SetTotalBytesLimit().
|
||||
int total_bytes_limit_;
|
||||
|
||||
// If positive/0: Limit for bytes read after which a warning due to size
|
||||
// should be logged.
|
||||
// If -1: Printing of warning disabled. Can be set by client.
|
||||
// If -2: Internal: Limit has been reached, print full size when destructing.
|
||||
int total_bytes_warning_threshold_;
|
||||
|
||||
// Current recursion depth, controlled by IncrementRecursionDepth() and
|
||||
|
@ -568,8 +539,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
|
|||
static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB
|
||||
|
||||
static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB
|
||||
|
||||
static int default_recursion_limit_; // 100 by default.
|
||||
static const int kDefaultRecursionLimit = 64;
|
||||
};
|
||||
|
||||
// Class which encodes and writes binary data which is composed of varint-
|
||||
|
@ -653,9 +623,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
|
|||
|
||||
// Write raw bytes, copying them from the given buffer.
|
||||
void WriteRaw(const void* buffer, int size);
|
||||
// Like WriteRaw() but will try to write aliased data if aliasing is
|
||||
// turned on.
|
||||
void WriteRawMaybeAliased(const void* data, int size);
|
||||
// Like WriteRaw() but writing directly to the target array.
|
||||
// This is _not_ inlined, as the compiler often optimizes memcpy into inline
|
||||
// copy loops. Since this gets called by every field with string or bytes
|
||||
|
@ -667,21 +634,8 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
|
|||
void WriteString(const string& str);
|
||||
// Like WriteString() but writing directly to the target array.
|
||||
static uint8* WriteStringToArray(const string& str, uint8* target);
|
||||
// Write the varint-encoded size of str followed by str.
|
||||
static uint8* WriteStringWithSizeToArray(const string& str, uint8* target);
|
||||
|
||||
|
||||
// Instructs the CodedOutputStream to allow the underlying
|
||||
// ZeroCopyOutputStream to hold pointers to the original structure instead of
|
||||
// copying, if it supports it (i.e. output->AllowsAliasing() is true). If the
|
||||
// underlying stream does not support aliasing, then enabling it has no
|
||||
// affect. For now, this only affects the behavior of
|
||||
// WriteRawMaybeAliased().
|
||||
//
|
||||
// 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.
|
||||
void EnableAliasing(bool enabled);
|
||||
|
||||
// Write a 32-bit little-endian integer.
|
||||
void WriteLittleEndian32(uint32 value);
|
||||
// Like WriteLittleEndian32() but writing directly to the target array.
|
||||
|
@ -726,21 +680,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
|
|||
// If negative, 10 bytes. Otheriwse, same as VarintSize32().
|
||||
static int VarintSize32SignExtended(int32 value);
|
||||
|
||||
// Compile-time equivalent of VarintSize32().
|
||||
template <uint32 Value>
|
||||
struct StaticVarintSize32 {
|
||||
static const int value =
|
||||
(Value < (1 << 7))
|
||||
? 1
|
||||
: (Value < (1 << 14))
|
||||
? 2
|
||||
: (Value < (1 << 21))
|
||||
? 3
|
||||
: (Value < (1 << 28))
|
||||
? 4
|
||||
: 5;
|
||||
};
|
||||
|
||||
// Returns the total number of bytes written since this object was created.
|
||||
inline int ByteCount() const;
|
||||
|
||||
|
@ -756,7 +695,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
|
|||
int buffer_size_;
|
||||
int total_bytes_; // Sum of sizes of all buffers seen so far.
|
||||
bool had_error_; // Whether an error occurred during output.
|
||||
bool aliasing_enabled_; // See EnableAliasing().
|
||||
|
||||
// Advance the buffer by a given number of bytes.
|
||||
void Advance(int amount);
|
||||
|
@ -765,10 +703,6 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
|
|||
// Advance(buffer_size_).
|
||||
bool Refresh();
|
||||
|
||||
// Like WriteRaw() but may avoid copying if the underlying
|
||||
// ZeroCopyOutputStream supports it.
|
||||
void WriteAliasedRaw(const void* buffer, int size);
|
||||
|
||||
static uint8* WriteVarint32FallbackToArray(uint32 value, uint8* target);
|
||||
|
||||
// Always-inlined versions of WriteVarint* functions so that code can be
|
||||
|
@ -886,45 +820,6 @@ inline uint32 CodedInputStream::ReadTag() {
|
|||
}
|
||||
}
|
||||
|
||||
inline std::pair<uint32, bool> CodedInputStream::ReadTagWithCutoff(
|
||||
uint32 cutoff) {
|
||||
// In performance-sensitive code we can expect cutoff to be a compile-time
|
||||
// constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at
|
||||
// compile time.
|
||||
if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
|
||||
// Hot case: buffer_ non_empty, buffer_[0] in [1, 128).
|
||||
// TODO(gpike): Is it worth rearranging this? E.g., if the number of fields
|
||||
// is large enough then is it better to check for the two-byte case first?
|
||||
if (static_cast<int8>(buffer_[0]) > 0) {
|
||||
const uint32 kMax1ByteVarint = 0x7f;
|
||||
uint32 tag = last_tag_ = buffer_[0];
|
||||
Advance(1);
|
||||
return make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff);
|
||||
}
|
||||
// Other hot case: cutoff >= 0x80, buffer_ has at least two bytes available,
|
||||
// and tag is two bytes. The latter is tested by bitwise-and-not of the
|
||||
// first byte and the second byte.
|
||||
if (cutoff >= 0x80 &&
|
||||
GOOGLE_PREDICT_TRUE(buffer_ + 1 < buffer_end_) &&
|
||||
GOOGLE_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) {
|
||||
const uint32 kMax2ByteVarint = (0x7f << 7) + 0x7f;
|
||||
uint32 tag = last_tag_ = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80);
|
||||
Advance(2);
|
||||
// It might make sense to test for tag == 0 now, but it is so rare that
|
||||
// that we don't bother. A varint-encoded 0 should be one byte unless
|
||||
// the encoder lost its mind. The second part of the return value of
|
||||
// this function is allowed to be either true or false if the tag is 0,
|
||||
// so we don't have to check for tag == 0. We may need to check whether
|
||||
// it exceeds cutoff.
|
||||
bool at_or_below_cutoff = cutoff >= kMax2ByteVarint || tag <= cutoff;
|
||||
return make_pair(tag, at_or_below_cutoff);
|
||||
}
|
||||
}
|
||||
// Slow path
|
||||
last_tag_ = ReadTagFallback();
|
||||
return make_pair(last_tag_, static_cast<uint32>(last_tag_ - 1) < cutoff);
|
||||
}
|
||||
|
||||
inline bool CodedInputStream::LastTagWas(uint32 expected) {
|
||||
return last_tag_ == expected;
|
||||
}
|
||||
|
@ -981,9 +876,7 @@ inline bool CodedInputStream::ExpectAtEnd() {
|
|||
// If we are at a limit we know no more bytes can be read. Otherwise, it's
|
||||
// hard to say without calling Refresh(), and we'd rather not do that.
|
||||
|
||||
if (buffer_ == buffer_end_ &&
|
||||
((buffer_size_after_limit_ != 0) ||
|
||||
(total_bytes_read_ == current_limit_))) {
|
||||
if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) {
|
||||
last_tag_ = 0; // Pretend we called ReadTag()...
|
||||
legitimate_message_end_ = true; // ... and it hit EOF.
|
||||
return true;
|
||||
|
@ -992,10 +885,6 @@ inline bool CodedInputStream::ExpectAtEnd() {
|
|||
}
|
||||
}
|
||||
|
||||
inline int CodedInputStream::CurrentPosition() const {
|
||||
return total_bytes_read_ - (BufferSize() + buffer_size_after_limit_);
|
||||
}
|
||||
|
||||
inline uint8* CodedOutputStream::GetDirectBufferForNBytesAndAdvance(int size) {
|
||||
if (buffer_size_ < size) {
|
||||
return NULL;
|
||||
|
@ -1104,15 +993,6 @@ inline void CodedOutputStream::WriteString(const string& str) {
|
|||
WriteRaw(str.data(), static_cast<int>(str.size()));
|
||||
}
|
||||
|
||||
inline void CodedOutputStream::WriteRawMaybeAliased(
|
||||
const void* data, int size) {
|
||||
if (aliasing_enabled_) {
|
||||
WriteAliasedRaw(data, size);
|
||||
} else {
|
||||
WriteRaw(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint8* CodedOutputStream::WriteStringToArray(
|
||||
const string& str, uint8* target) {
|
||||
return WriteRawToArray(str.data(), static_cast<int>(str.size()), target);
|
||||
|
@ -1144,7 +1024,7 @@ inline void CodedInputStream::DecrementRecursionDepth() {
|
|||
if (recursion_depth_ > 0) --recursion_depth_;
|
||||
}
|
||||
|
||||
inline void CodedInputStream::SetExtensionRegistry(const DescriptorPool* pool,
|
||||
inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool,
|
||||
MessageFactory* factory) {
|
||||
extension_pool_ = pool;
|
||||
extension_factory_ = factory;
|
||||
|
@ -1176,7 +1056,7 @@ inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input)
|
|||
total_bytes_limit_(kDefaultTotalBytesLimit),
|
||||
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
|
||||
recursion_depth_(0),
|
||||
recursion_limit_(default_recursion_limit_),
|
||||
recursion_limit_(kDefaultRecursionLimit),
|
||||
extension_pool_(NULL),
|
||||
extension_factory_(NULL) {
|
||||
// Eagerly Refresh() so buffer space is immediately available.
|
||||
|
@ -1197,15 +1077,17 @@ inline CodedInputStream::CodedInputStream(const uint8* buffer, int size)
|
|||
total_bytes_limit_(kDefaultTotalBytesLimit),
|
||||
total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold),
|
||||
recursion_depth_(0),
|
||||
recursion_limit_(default_recursion_limit_),
|
||||
recursion_limit_(kDefaultRecursionLimit),
|
||||
extension_pool_(NULL),
|
||||
extension_factory_(NULL) {
|
||||
// Note that setting current_limit_ == size is important to prevent some
|
||||
// code paths from trying to access input_ and segfaulting.
|
||||
}
|
||||
|
||||
inline bool CodedInputStream::IsFlat() const {
|
||||
return input_ == NULL;
|
||||
inline CodedInputStream::~CodedInputStream() {
|
||||
if (input_ != NULL) {
|
||||
BackUpInputToCurrentPosition();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace io
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -37,9 +37,8 @@
|
|||
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_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>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -51,12 +50,8 @@ inline bool CodedInputStream::InternalReadStringInline(string* buffer,
|
|||
|
||||
if (BufferSize() >= size) {
|
||||
STLStringResizeUninitialized(buffer, size);
|
||||
// When buffer is empty, string_as_array(buffer) will return NULL but memcpy
|
||||
// requires non-NULL pointers even when size is 0. Hench this check.
|
||||
if (size > 0) {
|
||||
memcpy(mutable_string_data(buffer), buffer_, size);
|
||||
Advance(size);
|
||||
}
|
||||
memcpy(string_as_array(buffer), buffer_, size);
|
||||
Advance(size);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -34,7 +34,6 @@
|
|||
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -44,14 +43,6 @@ ZeroCopyInputStream::~ZeroCopyInputStream() {}
|
|||
ZeroCopyOutputStream::~ZeroCopyOutputStream() {}
|
||||
|
||||
|
||||
bool ZeroCopyOutputStream::WriteAliasedRaw(const void* /* data */,
|
||||
int /* size */) {
|
||||
GOOGLE_LOG(FATAL) << "This ZeroCopyOutputStream doesn't support aliasing. "
|
||||
"Reaching here usually means a ZeroCopyOutputStream "
|
||||
"implementation bug.";
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -226,16 +226,6 @@ class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
|
|||
// 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);
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -344,7 +344,6 @@ class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
|
|||
private:
|
||||
ZeroCopyInputStream* input_;
|
||||
int64 limit_; // Decreases as we go, becomes negative if we overshoot.
|
||||
int64 prior_bytes_read_; // Bytes read on underlying stream at construction
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -32,13 +32,11 @@
|
|||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -163,23 +161,15 @@ bool StringOutputStream::Next(void** data, int* size) {
|
|||
// without a memory allocation this way.
|
||||
STLStringResizeUninitialized(target_, target_->capacity());
|
||||
} else {
|
||||
// Size has reached capacity, try to double the size.
|
||||
if (old_size > std::numeric_limits<int>::max() / 2) {
|
||||
// Can not double the size otherwise it is going to cause integer
|
||||
// overflow in the expression below: old_size * 2 ";
|
||||
GOOGLE_LOG(ERROR) << "Cannot allocate buffer larger than kint32max for "
|
||||
<< "StringOutputStream.";
|
||||
return false;
|
||||
}
|
||||
// Double the size, also make sure that the new size is at least
|
||||
// kMinimumSize.
|
||||
// Size has reached capacity, so double the size. Also make sure
|
||||
// that the new size is at least kMinimumSize.
|
||||
STLStringResizeUninitialized(
|
||||
target_,
|
||||
max(old_size * 2,
|
||||
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
|
||||
}
|
||||
|
||||
*data = mutable_string_data(target_) + old_size;
|
||||
*data = string_as_array(target_) + old_size;
|
||||
*size = target_->size() - old_size;
|
||||
return true;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -48,7 +48,6 @@
|
|||
#include <iosfwd>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
|
@ -334,19 +333,6 @@ class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStrea
|
|||
|
||||
// ===================================================================
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -38,7 +38,7 @@
|
|||
#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>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -278,8 +278,7 @@ bool MessageLite::AppendPartialToString(string* output) const {
|
|||
int old_size = output->size();
|
||||
int byte_size = ByteSize();
|
||||
STLStringResizeUninitialized(output, old_size + byte_size);
|
||||
uint8* start =
|
||||
reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
|
||||
uint8* start = reinterpret_cast<uint8*>(string_as_array(output) + old_size);
|
||||
uint8* end = SerializeWithCachedSizesToArray(start);
|
||||
if (end - start != byte_size) {
|
||||
ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -40,17 +40,11 @@
|
|||
#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace io {
|
||||
class CodedInputStream;
|
||||
class CodedOutputStream;
|
||||
class ZeroCopyInputStream;
|
||||
class ZeroCopyOutputStream;
|
||||
}
|
||||
|
||||
// Interface to light weight protocol messages.
|
||||
//
|
||||
// This interface is implemented by all protocol message objects. Non-lite
|
||||
|
@ -109,8 +103,7 @@ class LIBPROTOBUF_EXPORT MessageLite {
|
|||
|
||||
// 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.
|
||||
// just simple wrappers around MergeFromCodedStream().
|
||||
|
||||
// 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
|
||||
|
@ -165,7 +158,6 @@ class LIBPROTOBUF_EXPORT MessageLite {
|
|||
// 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().
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -46,31 +46,42 @@ void RepeatedPtrFieldBase::Reserve(int new_size) {
|
|||
if (total_size_ >= new_size) return;
|
||||
|
||||
void** old_elements = elements_;
|
||||
total_size_ = max(kMinRepeatedFieldAllocationSize,
|
||||
max(total_size_ * 2, new_size));
|
||||
total_size_ = max(total_size_ * 2, new_size);
|
||||
elements_ = new void*[total_size_];
|
||||
if (old_elements != NULL) {
|
||||
memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
|
||||
memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
|
||||
if (old_elements != initial_space_) {
|
||||
delete [] old_elements;
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
|
||||
if (this == other) return;
|
||||
void** swap_elements = elements_;
|
||||
int swap_current_size = current_size_;
|
||||
int swap_allocated_size = allocated_size_;
|
||||
int swap_total_size = total_size_;
|
||||
// We may not be using initial_space_ but it's not worth checking. Just
|
||||
// copy it anyway.
|
||||
void* swap_initial_space[kInitialSize];
|
||||
memcpy(swap_initial_space, initial_space_, sizeof(initial_space_));
|
||||
|
||||
elements_ = other->elements_;
|
||||
current_size_ = other->current_size_;
|
||||
allocated_size_ = other->allocated_size_;
|
||||
total_size_ = other->total_size_;
|
||||
memcpy(initial_space_, other->initial_space_, sizeof(initial_space_));
|
||||
|
||||
other->elements_ = swap_elements;
|
||||
other->current_size_ = swap_current_size;
|
||||
other->allocated_size_ = swap_allocated_size;
|
||||
other->total_size_ = swap_total_size;
|
||||
memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space));
|
||||
|
||||
if (elements_ == other->initial_space_) {
|
||||
elements_ = initial_space_;
|
||||
}
|
||||
if (other->elements_ == initial_space_) {
|
||||
other->elements_ = other->initial_space_;
|
||||
}
|
||||
}
|
||||
|
||||
string* StringTypeHandlerBase::New() {
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -46,55 +46,24 @@
|
|||
#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// This is required for min/max on VS2013 only.
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/type_traits.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace upb {
|
||||
namespace google_opensource {
|
||||
class GMR_Handlers;
|
||||
} // namespace google_opensource
|
||||
} // namespace upb
|
||||
|
||||
namespace protobuf {
|
||||
|
||||
class Message;
|
||||
|
||||
namespace internal {
|
||||
|
||||
static const int kMinRepeatedFieldAllocationSize = 4;
|
||||
// We need this (from generated_message_reflection.cc).
|
||||
LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
|
||||
|
||||
// A utility function for logging that doesn't need any template types.
|
||||
void LogIndexOutOfBounds(int index, int size);
|
||||
|
||||
template <typename Iter>
|
||||
inline int CalculateReserve(Iter begin, Iter end, std::forward_iterator_tag) {
|
||||
return std::distance(begin, end);
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
inline int CalculateReserve(Iter begin, Iter end, std::input_iterator_tag) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
inline int CalculateReserve(Iter begin, Iter end) {
|
||||
typedef typename std::iterator_traits<Iter>::iterator_category Category;
|
||||
return CalculateReserve(begin, end, Category());
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
|
||||
// RepeatedField is used to represent repeated fields of a primitive type (in
|
||||
// other words, everything except strings and nested Messages). Most users will
|
||||
// not ever use a RepeatedField directly; they will use the get-by-index,
|
||||
|
@ -104,13 +73,10 @@ class RepeatedField {
|
|||
public:
|
||||
RepeatedField();
|
||||
RepeatedField(const RepeatedField& other);
|
||||
template <typename Iter>
|
||||
RepeatedField(Iter begin, const Iter& end);
|
||||
~RepeatedField();
|
||||
|
||||
RepeatedField& operator=(const RepeatedField& other);
|
||||
|
||||
bool empty() const;
|
||||
int size() const;
|
||||
|
||||
const Element& Get(int index) const;
|
||||
|
@ -119,14 +85,12 @@ class RepeatedField {
|
|||
void Add(const Element& value);
|
||||
Element* Add();
|
||||
// Remove the last element in the array.
|
||||
// We don't provide a way to remove any element other than the last
|
||||
// because it invites inefficient use, such as O(n^2) filtering loops
|
||||
// that should have been O(n). If you want to remove an element other
|
||||
// than the last, the best way to do it is to re-arrange the elements
|
||||
// so that the one you want removed is at the end, then call RemoveLast().
|
||||
void RemoveLast();
|
||||
|
||||
// Extract elements with indices in "[start .. start+num-1]".
|
||||
// Copy them into "elements[0 .. num-1]" if "elements" is not NULL.
|
||||
// Caution: implementation also moves elements with indices [start+num ..].
|
||||
// Calling this routine inside a loop can cause quadratic behavior.
|
||||
void ExtractSubrange(int start, int num, Element* elements);
|
||||
|
||||
void Clear();
|
||||
void MergeFrom(const RepeatedField& other);
|
||||
void CopyFrom(const RepeatedField& other);
|
||||
|
@ -142,11 +106,6 @@ class RepeatedField {
|
|||
Element* AddAlreadyReserved();
|
||||
int Capacity() const;
|
||||
|
||||
// Like STL resize. Uses value to fill appended elements.
|
||||
// Like Truncate() if new_size <= size(), otherwise this is
|
||||
// O(new_size - size()).
|
||||
void Resize(int new_size, const Element& value);
|
||||
|
||||
// Gets the underlying array. This pointer is possibly invalidated by
|
||||
// any add or remove operation.
|
||||
Element* mutable_data();
|
||||
|
@ -162,45 +121,25 @@ class RepeatedField {
|
|||
typedef Element* iterator;
|
||||
typedef const Element* const_iterator;
|
||||
typedef Element value_type;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef value_type* pointer;
|
||||
typedef const value_type* const_pointer;
|
||||
typedef int size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
iterator begin();
|
||||
const_iterator begin() const;
|
||||
iterator end();
|
||||
const_iterator end() const;
|
||||
|
||||
// Reverse iterator support
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
// Returns the number of bytes used by the repeated field, excluding
|
||||
// sizeof(*this)
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
|
||||
private:
|
||||
static const int kInitialSize = 0;
|
||||
static const int kInitialSize = 4;
|
||||
|
||||
Element* elements_;
|
||||
int current_size_;
|
||||
int total_size_;
|
||||
|
||||
Element initial_space_[kInitialSize];
|
||||
|
||||
// Move the contents of |from| into |to|, possibly clobbering |from| in the
|
||||
// process. For primitive types this is just a memcpy(), but it could be
|
||||
// specialized for non-primitive types to, say, swap each element instead.
|
||||
|
@ -212,21 +151,7 @@ class RepeatedField {
|
|||
|
||||
namespace internal {
|
||||
template <typename It> class RepeatedPtrIterator;
|
||||
template <typename It, typename VoidPtr> class RepeatedPtrOverPtrsIterator;
|
||||
} // namespace internal
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This is a helper template to copy an array of elements effeciently when they
|
||||
// have a trivial copy constructor, and correctly otherwise. This really
|
||||
// shouldn't be necessary, but our compiler doesn't optimize std::copy very
|
||||
// effectively.
|
||||
template <typename Element,
|
||||
bool HasTrivialCopy = has_trivial_copy<Element>::value>
|
||||
struct ElementCopier {
|
||||
void operator()(Element to[], const Element from[], int array_size);
|
||||
};
|
||||
|
||||
template <typename It> class RepeatedPtrOverPtrsIterator;
|
||||
} // namespace internal
|
||||
|
||||
namespace internal {
|
||||
|
@ -261,17 +186,12 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
|
|||
// use of AddFromCleared(), which is not part of the public interface.
|
||||
friend class ExtensionSet;
|
||||
|
||||
// To parse directly into a proto2 generated class, the upb class GMR_Handlers
|
||||
// needs to be able to modify a RepeatedPtrFieldBase directly.
|
||||
friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
|
||||
|
||||
RepeatedPtrFieldBase();
|
||||
|
||||
// Must be called from destructor.
|
||||
template <typename TypeHandler>
|
||||
void Destroy();
|
||||
|
||||
bool empty() const;
|
||||
int size() const;
|
||||
|
||||
template <typename TypeHandler>
|
||||
|
@ -289,14 +209,6 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
|
|||
template <typename TypeHandler>
|
||||
void CopyFrom(const RepeatedPtrFieldBase& other);
|
||||
|
||||
void CloseGap(int start, int num) {
|
||||
// Close up a gap of "num" elements starting at offset "start".
|
||||
for (int i = start + num; i < allocated_size_; ++i)
|
||||
elements_[i - num] = elements_[i];
|
||||
current_size_ -= num;
|
||||
allocated_size_ -= num;
|
||||
}
|
||||
|
||||
void Reserve(int new_size);
|
||||
|
||||
int Capacity() const;
|
||||
|
@ -336,13 +248,17 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
|
|||
typename TypeHandler::Type* ReleaseCleared();
|
||||
|
||||
private:
|
||||
static const int kInitialSize = 0;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase);
|
||||
|
||||
static const int kInitialSize = 4;
|
||||
|
||||
void** elements_;
|
||||
int current_size_;
|
||||
int allocated_size_;
|
||||
int total_size_;
|
||||
|
||||
void* initial_space_[kInitialSize];
|
||||
|
||||
template <typename TypeHandler>
|
||||
static inline typename TypeHandler::Type* cast(void* element) {
|
||||
return reinterpret_cast<typename TypeHandler::Type*>(element);
|
||||
|
@ -351,8 +267,6 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase {
|
|||
static inline const typename TypeHandler::Type* cast(const void* element) {
|
||||
return reinterpret_cast<const typename TypeHandler::Type*>(element);
|
||||
}
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase);
|
||||
};
|
||||
|
||||
template <typename GenericType>
|
||||
|
@ -366,7 +280,6 @@ class GenericTypeHandler {
|
|||
to->MergeFrom(from);
|
||||
}
|
||||
static int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); }
|
||||
static const Type& default_instance() { return Type::default_instance(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -375,25 +288,6 @@ inline void GenericTypeHandler<MessageLite>::Merge(
|
|||
to->CheckTypeAndMergeFrom(from);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const MessageLite& GenericTypeHandler<MessageLite>::default_instance() {
|
||||
// Yes, the behavior of the code is undefined, but this function is only
|
||||
// called when we're already deep into the world of undefined, because the
|
||||
// caller called Get(index) out of bounds.
|
||||
MessageLite* null = NULL;
|
||||
return *null;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline const Message& GenericTypeHandler<Message>::default_instance() {
|
||||
// Yes, the behavior of the code is undefined, but this function is only
|
||||
// called when we're already deep into the world of undefined, because the
|
||||
// caller called Get(index) out of bounds.
|
||||
Message* null = NULL;
|
||||
return *null;
|
||||
}
|
||||
|
||||
|
||||
// HACK: If a class is declared as DLL-exported in MSVC, it insists on
|
||||
// generating copies of all its methods -- even inline ones -- to include
|
||||
// in the DLL. But SpaceUsed() calls StringSpaceUsedExcludingSelf() which
|
||||
|
@ -409,12 +303,9 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase {
|
|||
static void Delete(string* value);
|
||||
static void Clear(string* value) { value->clear(); }
|
||||
static void Merge(const string& from, string* to) { *to = from; }
|
||||
static const Type& default_instance() {
|
||||
return ::google::protobuf::internal::GetEmptyString();
|
||||
}
|
||||
};
|
||||
|
||||
class StringTypeHandler : public StringTypeHandlerBase {
|
||||
class LIBPROTOBUF_EXPORT StringTypeHandler : public StringTypeHandlerBase {
|
||||
public:
|
||||
static int SpaceUsed(const string& value) {
|
||||
return sizeof(value) + StringSpaceUsedExcludingSelf(value);
|
||||
|
@ -431,28 +322,16 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
|
|||
public:
|
||||
RepeatedPtrField();
|
||||
RepeatedPtrField(const RepeatedPtrField& other);
|
||||
template <typename Iter>
|
||||
RepeatedPtrField(Iter begin, const Iter& end);
|
||||
~RepeatedPtrField();
|
||||
|
||||
RepeatedPtrField& operator=(const RepeatedPtrField& other);
|
||||
|
||||
bool empty() const;
|
||||
int size() const;
|
||||
|
||||
const Element& Get(int index) const;
|
||||
Element* Mutable(int index);
|
||||
Element* Add();
|
||||
|
||||
// Remove the last element in the array.
|
||||
// Ownership of the element is retained by the array.
|
||||
void RemoveLast();
|
||||
|
||||
// Delete elements with indices in the range [start .. start+num-1].
|
||||
// Caution: implementation moves all elements with indices [start+num .. ].
|
||||
// Calling this routine inside a loop can cause quadratic behavior.
|
||||
void DeleteSubrange(int start, int num);
|
||||
|
||||
void RemoveLast(); // Remove the last element in the array.
|
||||
void Clear();
|
||||
void MergeFrom(const RepeatedPtrField& other);
|
||||
void CopyFrom(const RepeatedPtrField& other);
|
||||
|
@ -479,78 +358,42 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
|
|||
typedef internal::RepeatedPtrIterator<Element> iterator;
|
||||
typedef internal::RepeatedPtrIterator<const Element> const_iterator;
|
||||
typedef Element value_type;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef value_type* pointer;
|
||||
typedef const value_type* const_pointer;
|
||||
typedef int size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
iterator begin();
|
||||
const_iterator begin() const;
|
||||
iterator end();
|
||||
const_iterator end() const;
|
||||
|
||||
// Reverse iterator support
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
// Custom STL-like iterator that iterates over and returns the underlying
|
||||
// pointers to Element rather than Element itself.
|
||||
typedef internal::RepeatedPtrOverPtrsIterator<Element, void*>
|
||||
pointer_iterator;
|
||||
typedef internal::RepeatedPtrOverPtrsIterator<const Element, const void*>
|
||||
const_pointer_iterator;
|
||||
typedef internal::RepeatedPtrOverPtrsIterator<Element> pointer_iterator;
|
||||
pointer_iterator pointer_begin();
|
||||
const_pointer_iterator pointer_begin() const;
|
||||
pointer_iterator pointer_end();
|
||||
const_pointer_iterator pointer_end() const;
|
||||
|
||||
// Returns (an estimate of) the number of bytes used by the repeated field,
|
||||
// excluding sizeof(*this).
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
|
||||
// Advanced memory management --------------------------------------
|
||||
// When hardcore memory management becomes necessary -- as it sometimes
|
||||
// When hardcore memory management becomes necessary -- as it often
|
||||
// does here at Google -- the following methods may be useful.
|
||||
|
||||
// Add an already-allocated object, passing ownership to the
|
||||
// RepeatedPtrField.
|
||||
void AddAllocated(Element* value);
|
||||
// Remove the last element and return it, passing ownership to the caller.
|
||||
// Remove the last element and return it, passing ownership to the
|
||||
// caller.
|
||||
// Requires: size() > 0
|
||||
Element* ReleaseLast();
|
||||
|
||||
// Extract elements with indices in the range "[start .. start+num-1]".
|
||||
// The caller assumes ownership of the extracted elements and is responsible
|
||||
// for deleting them when they are no longer needed.
|
||||
// If "elements" is non-NULL, then pointers to the extracted elements
|
||||
// are stored in "elements[0 .. num-1]" for the convenience of the caller.
|
||||
// If "elements" is NULL, then the caller must use some other mechanism
|
||||
// to perform any further operations (like deletion) on these elements.
|
||||
// Caution: implementation also moves elements with indices [start+num ..].
|
||||
// Calling this routine inside a loop can cause quadratic behavior.
|
||||
void ExtractSubrange(int start, int num, Element** elements);
|
||||
|
||||
// When elements are removed by calls to RemoveLast() or Clear(), they
|
||||
// are not actually freed. Instead, they are cleared and kept so that
|
||||
// they can be reused later. This can save lots of CPU time when
|
||||
// repeatedly reusing a protocol message for similar purposes.
|
||||
//
|
||||
// Hardcore programs may choose to manipulate these cleared objects
|
||||
// to better optimize memory management using the following routines.
|
||||
// Really, extremely hardcore programs may actually want to manipulate
|
||||
// these objects to better-optimize memory management. These methods
|
||||
// allow that.
|
||||
|
||||
// Get the number of cleared objects that are currently being kept
|
||||
// around for reuse.
|
||||
|
@ -577,56 +420,33 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase {
|
|||
|
||||
template <typename Element>
|
||||
inline RepeatedField<Element>::RepeatedField()
|
||||
: elements_(NULL),
|
||||
: elements_(initial_space_),
|
||||
current_size_(0),
|
||||
total_size_(kInitialSize) {
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline RepeatedField<Element>::RepeatedField(const RepeatedField& other)
|
||||
: elements_(NULL),
|
||||
: elements_(initial_space_),
|
||||
current_size_(0),
|
||||
total_size_(kInitialSize) {
|
||||
CopyFrom(other);
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
template <typename Iter>
|
||||
inline RepeatedField<Element>::RepeatedField(Iter begin, const Iter& end)
|
||||
: elements_(NULL),
|
||||
current_size_(0),
|
||||
total_size_(kInitialSize) {
|
||||
int reserve = internal::CalculateReserve(begin, end);
|
||||
if (reserve != -1) {
|
||||
Reserve(reserve);
|
||||
for (; begin != end; ++begin) {
|
||||
AddAlreadyReserved(*begin);
|
||||
}
|
||||
} else {
|
||||
for (; begin != end; ++begin) {
|
||||
Add(*begin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
RepeatedField<Element>::~RepeatedField() {
|
||||
delete [] elements_;
|
||||
if (elements_ != initial_space_) {
|
||||
delete [] elements_;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline RepeatedField<Element>&
|
||||
RepeatedField<Element>::operator=(const RepeatedField& other) {
|
||||
if (this != &other)
|
||||
CopyFrom(other);
|
||||
CopyFrom(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline bool RepeatedField<Element>::empty() const {
|
||||
return current_size_ == 0;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline int RepeatedField<Element>::size() const {
|
||||
return current_size_;
|
||||
|
@ -649,33 +469,20 @@ inline Element* RepeatedField<Element>::AddAlreadyReserved() {
|
|||
return &elements_[current_size_++];
|
||||
}
|
||||
|
||||
template<typename Element>
|
||||
inline void RepeatedField<Element>::Resize(int new_size, const Element& value) {
|
||||
GOOGLE_DCHECK_GE(new_size, 0);
|
||||
if (new_size > size()) {
|
||||
Reserve(new_size);
|
||||
std::fill(&elements_[current_size_], &elements_[new_size], value);
|
||||
}
|
||||
current_size_ = new_size;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline const Element& RepeatedField<Element>::Get(int index) const {
|
||||
GOOGLE_DCHECK_GE(index, 0);
|
||||
GOOGLE_DCHECK_LT(index, size());
|
||||
return elements_[index];
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline Element* RepeatedField<Element>::Mutable(int index) {
|
||||
GOOGLE_DCHECK_GE(index, 0);
|
||||
GOOGLE_DCHECK_LT(index, size());
|
||||
return elements_ + index;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedField<Element>::Set(int index, const Element& value) {
|
||||
GOOGLE_DCHECK_GE(index, 0);
|
||||
GOOGLE_DCHECK_LT(index, size());
|
||||
elements_[index] = value;
|
||||
}
|
||||
|
@ -698,27 +505,6 @@ inline void RepeatedField<Element>::RemoveLast() {
|
|||
--current_size_;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
void RepeatedField<Element>::ExtractSubrange(
|
||||
int start, int num, Element* elements) {
|
||||
GOOGLE_DCHECK_GE(start, 0);
|
||||
GOOGLE_DCHECK_GE(num, 0);
|
||||
GOOGLE_DCHECK_LE(start + num, this->size());
|
||||
|
||||
// Save the values of the removed elements if requested.
|
||||
if (elements != NULL) {
|
||||
for (int i = 0; i < num; ++i)
|
||||
elements[i] = this->Get(i + start);
|
||||
}
|
||||
|
||||
// Slide remaining elements down to fill the gap.
|
||||
if (num > 0) {
|
||||
for (int i = start + num; i < this->size(); ++i)
|
||||
this->Set(i - num, this->Get(i));
|
||||
this->Truncate(this->size() - num);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedField<Element>::Clear() {
|
||||
current_size_ = 0;
|
||||
|
@ -726,17 +512,13 @@ inline void RepeatedField<Element>::Clear() {
|
|||
|
||||
template <typename Element>
|
||||
inline void RepeatedField<Element>::MergeFrom(const RepeatedField& other) {
|
||||
GOOGLE_CHECK_NE(&other, this);
|
||||
if (other.current_size_ != 0) {
|
||||
Reserve(current_size_ + other.current_size_);
|
||||
CopyArray(elements_ + current_size_, other.elements_, other.current_size_);
|
||||
current_size_ += other.current_size_;
|
||||
}
|
||||
Reserve(current_size_ + other.current_size_);
|
||||
CopyArray(elements_ + current_size_, other.elements_, other.current_size_);
|
||||
current_size_ += other.current_size_;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedField<Element>::CopyFrom(const RepeatedField& other) {
|
||||
if (&other == this) return;
|
||||
Clear();
|
||||
MergeFrom(other);
|
||||
}
|
||||
|
@ -754,24 +536,35 @@ inline const Element* RepeatedField<Element>::data() const {
|
|||
|
||||
template <typename Element>
|
||||
void RepeatedField<Element>::Swap(RepeatedField* other) {
|
||||
if (this == other) return;
|
||||
Element* swap_elements = elements_;
|
||||
int swap_current_size = current_size_;
|
||||
int swap_total_size = total_size_;
|
||||
// We may not be using initial_space_ but it's not worth checking. Just
|
||||
// copy it anyway.
|
||||
Element swap_initial_space[kInitialSize];
|
||||
MoveArray(swap_initial_space, initial_space_, kInitialSize);
|
||||
|
||||
elements_ = other->elements_;
|
||||
current_size_ = other->current_size_;
|
||||
total_size_ = other->total_size_;
|
||||
MoveArray(initial_space_, other->initial_space_, kInitialSize);
|
||||
|
||||
other->elements_ = swap_elements;
|
||||
other->current_size_ = swap_current_size;
|
||||
other->total_size_ = swap_total_size;
|
||||
MoveArray(other->initial_space_, swap_initial_space, kInitialSize);
|
||||
|
||||
if (elements_ == other->initial_space_) {
|
||||
elements_ = initial_space_;
|
||||
}
|
||||
if (other->elements_ == initial_space_) {
|
||||
other->elements_ = other->initial_space_;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
void RepeatedField<Element>::SwapElements(int index1, int index2) {
|
||||
using std::swap; // enable ADL with fallback
|
||||
swap(elements_[index1], elements_[index2]);
|
||||
std::swap(elements_[index1], elements_[index2]);
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
|
@ -797,21 +590,20 @@ RepeatedField<Element>::end() const {
|
|||
|
||||
template <typename Element>
|
||||
inline int RepeatedField<Element>::SpaceUsedExcludingSelf() const {
|
||||
return (elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0;
|
||||
return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0;
|
||||
}
|
||||
|
||||
// Avoid inlining of Reserve(): new, copy, and delete[] lead to a significant
|
||||
// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant
|
||||
// amount of code bloat.
|
||||
template <typename Element>
|
||||
void RepeatedField<Element>::Reserve(int new_size) {
|
||||
if (total_size_ >= new_size) return;
|
||||
|
||||
Element* old_elements = elements_;
|
||||
total_size_ = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize,
|
||||
max(total_size_ * 2, new_size));
|
||||
total_size_ = max(total_size_ * 2, new_size);
|
||||
elements_ = new Element[total_size_];
|
||||
if (old_elements != NULL) {
|
||||
MoveArray(elements_, old_elements, current_size_);
|
||||
MoveArray(elements_, old_elements, current_size_);
|
||||
if (old_elements != initial_space_) {
|
||||
delete [] old_elements;
|
||||
}
|
||||
}
|
||||
|
@ -825,39 +617,22 @@ inline void RepeatedField<Element>::Truncate(int new_size) {
|
|||
template <typename Element>
|
||||
inline void RepeatedField<Element>::MoveArray(
|
||||
Element to[], Element from[], int array_size) {
|
||||
CopyArray(to, from, array_size);
|
||||
memcpy(to, from, array_size * sizeof(Element));
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedField<Element>::CopyArray(
|
||||
Element to[], const Element from[], int array_size) {
|
||||
internal::ElementCopier<Element>()(to, from, array_size);
|
||||
memcpy(to, from, array_size * sizeof(Element));
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Element, bool HasTrivialCopy>
|
||||
void ElementCopier<Element, HasTrivialCopy>::operator()(
|
||||
Element to[], const Element from[], int array_size) {
|
||||
std::copy(from, from + array_size, to);
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
struct ElementCopier<Element, true> {
|
||||
void operator()(Element to[], const Element from[], int array_size) {
|
||||
memcpy(to, from, array_size * sizeof(Element));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
namespace internal {
|
||||
|
||||
inline RepeatedPtrFieldBase::RepeatedPtrFieldBase()
|
||||
: elements_(NULL),
|
||||
: elements_(initial_space_),
|
||||
current_size_(0),
|
||||
allocated_size_(0),
|
||||
total_size_(kInitialSize) {
|
||||
|
@ -868,30 +643,26 @@ void RepeatedPtrFieldBase::Destroy() {
|
|||
for (int i = 0; i < allocated_size_; i++) {
|
||||
TypeHandler::Delete(cast<TypeHandler>(elements_[i]));
|
||||
}
|
||||
delete [] elements_;
|
||||
}
|
||||
|
||||
inline bool RepeatedPtrFieldBase::empty() const {
|
||||
return current_size_ == 0;
|
||||
if (elements_ != initial_space_) {
|
||||
delete [] elements_;
|
||||
}
|
||||
}
|
||||
|
||||
inline int RepeatedPtrFieldBase::size() const {
|
||||
return current_size_;
|
||||
}
|
||||
|
||||
|
||||
template <typename TypeHandler>
|
||||
inline const typename TypeHandler::Type&
|
||||
RepeatedPtrFieldBase::Get(int index) const {
|
||||
GOOGLE_DCHECK_GE(index, 0);
|
||||
GOOGLE_DCHECK_LT(index, size());
|
||||
return *cast<TypeHandler>(elements_[index]);
|
||||
}
|
||||
|
||||
|
||||
template <typename TypeHandler>
|
||||
inline typename TypeHandler::Type*
|
||||
RepeatedPtrFieldBase::Mutable(int index) {
|
||||
GOOGLE_DCHECK_GE(index, 0);
|
||||
GOOGLE_DCHECK_LT(index, size());
|
||||
return cast<TypeHandler>(elements_[index]);
|
||||
}
|
||||
|
@ -902,8 +673,8 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add() {
|
|||
return cast<TypeHandler>(elements_[current_size_++]);
|
||||
}
|
||||
if (allocated_size_ == total_size_) Reserve(total_size_ + 1);
|
||||
typename TypeHandler::Type* result = TypeHandler::New();
|
||||
++allocated_size_;
|
||||
typename TypeHandler::Type* result = TypeHandler::New();
|
||||
elements_[current_size_++] = result;
|
||||
return result;
|
||||
}
|
||||
|
@ -924,7 +695,6 @@ void RepeatedPtrFieldBase::Clear() {
|
|||
|
||||
template <typename TypeHandler>
|
||||
inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) {
|
||||
GOOGLE_CHECK_NE(&other, this);
|
||||
Reserve(current_size_ + other.current_size_);
|
||||
for (int i = 0; i < other.current_size_; i++) {
|
||||
TypeHandler::Merge(other.template Get<TypeHandler>(i), Add<TypeHandler>());
|
||||
|
@ -933,7 +703,6 @@ inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) {
|
|||
|
||||
template <typename TypeHandler>
|
||||
inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) {
|
||||
if (&other == this) return;
|
||||
RepeatedPtrFieldBase::Clear<TypeHandler>();
|
||||
RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
|
||||
}
|
||||
|
@ -966,14 +735,13 @@ RepeatedPtrFieldBase::data() const {
|
|||
}
|
||||
|
||||
inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) {
|
||||
using std::swap; // enable ADL with fallback
|
||||
swap(elements_[index1], elements_[index2]);
|
||||
std::swap(elements_[index1], elements_[index2]);
|
||||
}
|
||||
|
||||
template <typename TypeHandler>
|
||||
inline int RepeatedPtrFieldBase::SpaceUsedExcludingSelf() const {
|
||||
int allocated_bytes =
|
||||
(elements_ != NULL) ? total_size_ * sizeof(elements_[0]) : 0;
|
||||
(elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0;
|
||||
for (int i = 0; i < allocated_size_; ++i) {
|
||||
allocated_bytes += TypeHandler::SpaceUsed(*cast<TypeHandler>(elements_[i]));
|
||||
}
|
||||
|
@ -1030,6 +798,7 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() {
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
inline int RepeatedPtrFieldBase::ClearedCount() const {
|
||||
return allocated_size_ - current_size_;
|
||||
}
|
||||
|
@ -1053,13 +822,11 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() {
|
|||
|
||||
template <typename Element>
|
||||
class RepeatedPtrField<Element>::TypeHandler
|
||||
: public internal::GenericTypeHandler<Element> {
|
||||
};
|
||||
: public internal::GenericTypeHandler<Element> {};
|
||||
|
||||
template <>
|
||||
class RepeatedPtrField<string>::TypeHandler
|
||||
: public internal::StringTypeHandler {
|
||||
};
|
||||
: public internal::StringTypeHandler {};
|
||||
|
||||
|
||||
template <typename Element>
|
||||
|
@ -1067,24 +834,10 @@ inline RepeatedPtrField<Element>::RepeatedPtrField() {}
|
|||
|
||||
template <typename Element>
|
||||
inline RepeatedPtrField<Element>::RepeatedPtrField(
|
||||
const RepeatedPtrField& other)
|
||||
: RepeatedPtrFieldBase() {
|
||||
const RepeatedPtrField& other) {
|
||||
CopyFrom(other);
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
template <typename Iter>
|
||||
inline RepeatedPtrField<Element>::RepeatedPtrField(
|
||||
Iter begin, const Iter& end) {
|
||||
int reserve = internal::CalculateReserve(begin, end);
|
||||
if (reserve != -1) {
|
||||
Reserve(reserve);
|
||||
}
|
||||
for (; begin != end; ++begin) {
|
||||
*Add() = *begin;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
RepeatedPtrField<Element>::~RepeatedPtrField() {
|
||||
Destroy<TypeHandler>();
|
||||
|
@ -1093,16 +846,10 @@ RepeatedPtrField<Element>::~RepeatedPtrField() {
|
|||
template <typename Element>
|
||||
inline RepeatedPtrField<Element>& RepeatedPtrField<Element>::operator=(
|
||||
const RepeatedPtrField& other) {
|
||||
if (this != &other)
|
||||
CopyFrom(other);
|
||||
CopyFrom(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline bool RepeatedPtrField<Element>::empty() const {
|
||||
return RepeatedPtrFieldBase::empty();
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline int RepeatedPtrField<Element>::size() const {
|
||||
return RepeatedPtrFieldBase::size();
|
||||
|
@ -1113,7 +860,6 @@ inline const Element& RepeatedPtrField<Element>::Get(int index) const {
|
|||
return RepeatedPtrFieldBase::Get<TypeHandler>(index);
|
||||
}
|
||||
|
||||
|
||||
template <typename Element>
|
||||
inline Element* RepeatedPtrField<Element>::Mutable(int index) {
|
||||
return RepeatedPtrFieldBase::Mutable<TypeHandler>(index);
|
||||
|
@ -1129,33 +875,6 @@ inline void RepeatedPtrField<Element>::RemoveLast() {
|
|||
RepeatedPtrFieldBase::RemoveLast<TypeHandler>();
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedPtrField<Element>::DeleteSubrange(int start, int num) {
|
||||
GOOGLE_DCHECK_GE(start, 0);
|
||||
GOOGLE_DCHECK_GE(num, 0);
|
||||
GOOGLE_DCHECK_LE(start + num, size());
|
||||
for (int i = 0; i < num; ++i)
|
||||
delete RepeatedPtrFieldBase::Mutable<TypeHandler>(start + i);
|
||||
ExtractSubrange(start, num, NULL);
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedPtrField<Element>::ExtractSubrange(
|
||||
int start, int num, Element** elements) {
|
||||
GOOGLE_DCHECK_GE(start, 0);
|
||||
GOOGLE_DCHECK_GE(num, 0);
|
||||
GOOGLE_DCHECK_LE(start + num, size());
|
||||
|
||||
if (num > 0) {
|
||||
// Save the values of the removed elements if requested.
|
||||
if (elements != NULL) {
|
||||
for (int i = 0; i < num; ++i)
|
||||
elements[i] = RepeatedPtrFieldBase::Mutable<TypeHandler>(i + start);
|
||||
}
|
||||
CloseGap(start, num);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
inline void RepeatedPtrField<Element>::Clear() {
|
||||
RepeatedPtrFieldBase::Clear<TypeHandler>();
|
||||
|
@ -1242,7 +961,7 @@ namespace internal {
|
|||
// refer to this class directly; use RepeatedPtrField<T>::iterator instead.
|
||||
//
|
||||
// The iterator for RepeatedPtrField<T>, RepeatedPtrIterator<T>, is
|
||||
// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors.h,
|
||||
// very similar to iterator_ptr<T**> in util/gtl/iterator_adaptors-inl.h,
|
||||
// but adds random-access operators and is modified to wrap a void** base
|
||||
// iterator (since RepeatedPtrField stores its array as a void* array and
|
||||
// casting void** to T** would violate C++ aliasing rules).
|
||||
|
@ -1258,10 +977,6 @@ class RepeatedPtrIterator
|
|||
typedef std::iterator<
|
||||
std::random_access_iterator_tag, Element> superclass;
|
||||
|
||||
// Shadow the value_type in std::iterator<> because const_iterator::value_type
|
||||
// needs to be T, not const T.
|
||||
typedef typename remove_const<Element>::type value_type;
|
||||
|
||||
// Let the compiler know that these are type names, so we don't have to
|
||||
// write "typename" in front of them everywhere.
|
||||
typedef typename superclass::reference reference;
|
||||
|
@ -1342,21 +1057,14 @@ class RepeatedPtrIterator
|
|||
// rather than the objects themselves as RepeatedPtrIterator does.
|
||||
// Consider using this when working with stl algorithms that change
|
||||
// the array.
|
||||
// The VoidPtr template parameter holds the type-agnostic pointer value
|
||||
// referenced by the iterator. It should either be "void *" for a mutable
|
||||
// iterator, or "const void *" for a constant iterator.
|
||||
template<typename Element, typename VoidPtr>
|
||||
template<typename Element>
|
||||
class RepeatedPtrOverPtrsIterator
|
||||
: public std::iterator<std::random_access_iterator_tag, Element*> {
|
||||
public:
|
||||
typedef RepeatedPtrOverPtrsIterator<Element, VoidPtr> iterator;
|
||||
typedef RepeatedPtrOverPtrsIterator<Element> iterator;
|
||||
typedef std::iterator<
|
||||
std::random_access_iterator_tag, Element*> superclass;
|
||||
|
||||
// Shadow the value_type in std::iterator<> because const_iterator::value_type
|
||||
// needs to be T, not const T.
|
||||
typedef typename remove_const<Element*>::type value_type;
|
||||
|
||||
// Let the compiler know that these are type names, so we don't have to
|
||||
// write "typename" in front of them everywhere.
|
||||
typedef typename superclass::reference reference;
|
||||
|
@ -1364,7 +1072,7 @@ class RepeatedPtrOverPtrsIterator
|
|||
typedef typename superclass::difference_type difference_type;
|
||||
|
||||
RepeatedPtrOverPtrsIterator() : it_(NULL) {}
|
||||
explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {}
|
||||
explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {}
|
||||
|
||||
// dereferenceable
|
||||
reference operator*() const { return *reinterpret_cast<Element**>(it_); }
|
||||
|
@ -1419,9 +1127,10 @@ class RepeatedPtrOverPtrsIterator
|
|||
friend class RepeatedPtrIterator;
|
||||
|
||||
// The internal iterator.
|
||||
VoidPtr* it_;
|
||||
void** it_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Element>
|
||||
|
@ -1451,21 +1160,10 @@ RepeatedPtrField<Element>::pointer_begin() {
|
|||
return pointer_iterator(raw_mutable_data());
|
||||
}
|
||||
template <typename Element>
|
||||
inline typename RepeatedPtrField<Element>::const_pointer_iterator
|
||||
RepeatedPtrField<Element>::pointer_begin() const {
|
||||
return const_pointer_iterator(const_cast<const void**>(raw_mutable_data()));
|
||||
}
|
||||
template <typename Element>
|
||||
inline typename RepeatedPtrField<Element>::pointer_iterator
|
||||
RepeatedPtrField<Element>::pointer_end() {
|
||||
return pointer_iterator(raw_mutable_data() + size());
|
||||
}
|
||||
template <typename Element>
|
||||
inline typename RepeatedPtrField<Element>::const_pointer_iterator
|
||||
RepeatedPtrField<Element>::pointer_end() const {
|
||||
return const_pointer_iterator(
|
||||
const_cast<const void**>(raw_mutable_data() + size()));
|
||||
}
|
||||
|
||||
|
||||
// Iterators and helper functions that follow the spirit of the STL
|
||||
|
@ -1475,7 +1173,7 @@ RepeatedPtrField<Element>::pointer_end() const {
|
|||
// std::copy(some_sequence.begin(), some_sequence.end(),
|
||||
// google::protobuf::RepeatedFieldBackInserter(proto.mutable_sequence()));
|
||||
//
|
||||
// Ported by johannes from util/gtl/proto-array-iterators.h
|
||||
// Ported by johannes from util/gtl/proto-array-iterators-inl.h
|
||||
|
||||
namespace internal {
|
||||
// A back inserter for RepeatedField objects.
|
||||
|
@ -1496,7 +1194,7 @@ template<typename T> class RepeatedFieldBackInsertIterator
|
|||
RepeatedFieldBackInsertIterator<T>& operator++() {
|
||||
return *this;
|
||||
}
|
||||
RepeatedFieldBackInsertIterator<T>& operator++(int /* unused */) {
|
||||
RepeatedFieldBackInsertIterator<T>& operator++(int ignores_parameter) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1225,7 @@ template<typename T> class RepeatedPtrFieldBackInsertIterator
|
|||
RepeatedPtrFieldBackInsertIterator<T>& operator++() {
|
||||
return *this;
|
||||
}
|
||||
RepeatedPtrFieldBackInsertIterator<T>& operator++(int /* unused */) {
|
||||
RepeatedPtrFieldBackInsertIterator<T>& operator++(int ignores_parameter) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1556,7 +1254,7 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
|
|||
return *this;
|
||||
}
|
||||
AllocatedRepeatedPtrFieldBackInsertIterator<T>& operator++(
|
||||
int /* unused */) {
|
||||
int ignores_parameter) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1566,22 +1264,16 @@ template<typename T> class AllocatedRepeatedPtrFieldBackInsertIterator
|
|||
} // namespace internal
|
||||
|
||||
// Provides a back insert iterator for RepeatedField instances,
|
||||
// similar to std::back_inserter().
|
||||
// similar to std::back_inserter(). Note the identically named
|
||||
// function for RepeatedPtrField instances.
|
||||
template<typename T> internal::RepeatedFieldBackInsertIterator<T>
|
||||
RepeatedFieldBackInserter(RepeatedField<T>* const mutable_field) {
|
||||
return internal::RepeatedFieldBackInsertIterator<T>(mutable_field);
|
||||
}
|
||||
|
||||
// Provides a back insert iterator for RepeatedPtrField instances,
|
||||
// similar to std::back_inserter().
|
||||
template<typename T> internal::RepeatedPtrFieldBackInsertIterator<T>
|
||||
RepeatedPtrFieldBackInserter(RepeatedPtrField<T>* const mutable_field) {
|
||||
return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
|
||||
}
|
||||
|
||||
// Special back insert iterator for RepeatedPtrField instances, just in
|
||||
// case someone wants to write generic template code that can access both
|
||||
// RepeatedFields and RepeatedPtrFields using a common name.
|
||||
// similar to std::back_inserter(). Note the identically named
|
||||
// function for RepeatedField instances.
|
||||
template<typename T> internal::RepeatedPtrFieldBackInsertIterator<T>
|
||||
RepeatedFieldBackInserter(RepeatedPtrField<T>* const mutable_field) {
|
||||
return internal::RepeatedPtrFieldBackInsertIterator<T>(mutable_field);
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -36,15 +36,14 @@
|
|||
#include <errno.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef WIN32
|
||||
#define WIN32_LEAN_AND_MEAN // We only need minimal includes
|
||||
#include <windows.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
#define snprintf _snprintf // see comment in strutil.cc
|
||||
#elif defined(HAVE_PTHREAD_H)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#else
|
||||
#error "No suitable threading library available."
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
|
@ -109,13 +108,13 @@ void DefaultLogHandler(LogLevel level, const char* filename, int line,
|
|||
|
||||
// We use fprintf() instead of cerr because we want this to work at static
|
||||
// initialization time.
|
||||
fprintf(stderr, "[libprotobuf %s %s:%d] %s\n",
|
||||
fprintf(stderr, "libprotobuf %s %s:%d] %s\n",
|
||||
level_names[level], filename, line, message.c_str());
|
||||
fflush(stderr); // Needed on MSVC.
|
||||
}
|
||||
|
||||
void NullLogHandler(LogLevel /* level */, const char* /* filename */,
|
||||
int /* line */, const string& /* message */) {
|
||||
void NullLogHandler(LogLevel level, const char* filename, int line,
|
||||
const string& message) {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
|
@ -182,15 +181,15 @@ void LogMessage::Finish() {
|
|||
if (level_ != LOGLEVEL_FATAL) {
|
||||
InitLogSilencerCountOnce();
|
||||
MutexLock lock(log_silencer_count_mutex_);
|
||||
suppress = log_silencer_count_ > 0;
|
||||
suppress = internal::log_silencer_count_ > 0;
|
||||
}
|
||||
|
||||
if (!suppress) {
|
||||
log_handler_(level_, filename_, line_, message_);
|
||||
internal::log_handler_(level_, filename_, line_, message_);
|
||||
}
|
||||
|
||||
if (level_ == LOGLEVEL_FATAL) {
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
#ifdef PROTOBUF_USE_EXCEPTIONS
|
||||
throw FatalException(filename_, line_, message_);
|
||||
#else
|
||||
abort();
|
||||
|
@ -241,7 +240,7 @@ void DoNothing() {}
|
|||
// ===================================================================
|
||||
// emulates google3/base/mutex.cc
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef WIN32
|
||||
|
||||
struct Mutex::Internal {
|
||||
CRITICAL_SECTION mutex;
|
||||
|
@ -281,7 +280,7 @@ void Mutex::AssertHeld() {
|
|||
#endif
|
||||
}
|
||||
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
#else
|
||||
|
||||
struct Mutex::Internal {
|
||||
pthread_mutex_t mutex;
|
||||
|
@ -318,24 +317,6 @@ void Mutex::AssertHeld() {
|
|||
|
||||
#endif
|
||||
|
||||
// ===================================================================
|
||||
// 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.
|
||||
|
||||
|
@ -382,7 +363,7 @@ void ShutdownProtobufLibrary() {
|
|||
internal::shutdown_functions_mutex = NULL;
|
||||
}
|
||||
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
#ifdef PROTOBUF_USE_EXCEPTIONS
|
||||
FatalException::~FatalException() throw() {}
|
||||
|
||||
const char* FatalException::what() const throw() {
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -48,17 +48,12 @@
|
|||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifndef PROTOBUF_USE_EXCEPTIONS
|
||||
#if defined(_MSC_VER) && defined(_CPPUNWIND)
|
||||
#define PROTOBUF_USE_EXCEPTIONS 1
|
||||
#define PROTOBUF_USE_EXCEPTIONS
|
||||
#elif defined(__EXCEPTIONS)
|
||||
#define PROTOBUF_USE_EXCEPTIONS 1
|
||||
#else
|
||||
#define PROTOBUF_USE_EXCEPTIONS 0
|
||||
#define PROTOBUF_USE_EXCEPTIONS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
#ifdef PROTOBUF_USE_EXCEPTIONS
|
||||
#include <exception>
|
||||
#endif
|
||||
|
||||
|
@ -113,24 +108,24 @@ namespace internal {
|
|||
|
||||
// The current version, represented as a single integer to make comparison
|
||||
// easier: major * 10^6 + minor * 10^3 + micro
|
||||
#define GOOGLE_PROTOBUF_VERSION 2006001
|
||||
#define GOOGLE_PROTOBUF_VERSION 2004001
|
||||
|
||||
// The minimum library version which works with the current version of the
|
||||
// headers.
|
||||
#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2006000
|
||||
#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 2004000
|
||||
|
||||
// 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 = 2006000;
|
||||
static const int kMinHeaderVersionForLibrary = 2004000;
|
||||
|
||||
// The minimum protoc version which works with the current version of the
|
||||
// headers.
|
||||
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2006000
|
||||
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 2004000
|
||||
|
||||
// The minimum header version which works with the current version of
|
||||
// protoc. This constant should only be used in VerifyVersion().
|
||||
static const int kMinHeaderVersionForProtoc = 2006000;
|
||||
static const int kMinHeaderVersionForProtoc = 2004000;
|
||||
|
||||
// Verifies that the headers and libraries are compatible. Use the macro
|
||||
// below to call this.
|
||||
|
@ -368,9 +363,60 @@ using internal::down_cast;
|
|||
// the expression is false, most compilers will issue a warning/error
|
||||
// containing the name of the variable.
|
||||
|
||||
#define GOOGLE_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
|
||||
namespace internal {
|
||||
|
||||
template <bool>
|
||||
struct CompileAssert {
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#undef GOOGLE_COMPILE_ASSERT
|
||||
#define GOOGLE_COMPILE_ASSERT(expr, msg) \
|
||||
typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \
|
||||
msg[bool(expr) ? 1 : -1]
|
||||
|
||||
|
||||
// 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.
|
||||
|
||||
// ===================================================================
|
||||
// from google3/base/scoped_ptr.h
|
||||
|
@ -587,17 +633,6 @@ enum LogLevel {
|
|||
#else
|
||||
LOGLEVEL_DFATAL = LOGLEVEL_FATAL
|
||||
#endif
|
||||
|
||||
#ifdef ERROR
|
||||
// ERROR is defined as 0 on some windows builds, so `GOOGLE_LOG(ERROR, ...)`
|
||||
// expands into `GOOGLE_LOG(0, ...)` which then expands into
|
||||
// `someGoogleLogging(LOGLEVEL_0, ...)`. This is not ideal, because the
|
||||
// GOOGLE_LOG macro expects to expand itself into
|
||||
// `someGoogleLogging(LOGLEVEL_ERROR, ...)` instead. The workaround to get
|
||||
// everything building is to simply define LOGLEVEL_0 as LOGLEVEL_ERROR and
|
||||
// move on with our lives.
|
||||
, LOGLEVEL_0 = LOGLEVEL_ERROR
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
@ -645,14 +680,12 @@ class LIBPROTOBUF_EXPORT LogFinisher {
|
|||
#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
|
||||
|
@ -672,7 +705,6 @@ class LIBPROTOBUF_EXPORT LogFinisher {
|
|||
|
||||
#define GOOGLE_CHECK(EXPRESSION) \
|
||||
GOOGLE_LOG_IF(FATAL, !(EXPRESSION)) << "CHECK failed: " #EXPRESSION ": "
|
||||
#define GOOGLE_CHECK_OK(A) GOOGLE_CHECK(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))
|
||||
|
@ -680,19 +712,6 @@ class LIBPROTOBUF_EXPORT LogFinisher {
|
|||
#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) \
|
||||
internal::CheckNotNull(__FILE__, __LINE__, "'" #A "' must not be NULL", (A))
|
||||
|
||||
#ifdef NDEBUG
|
||||
|
||||
#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false)
|
||||
|
@ -1117,20 +1136,26 @@ using internal::WriterMutexLock;
|
|||
using internal::MutexLockMaybe;
|
||||
|
||||
// ===================================================================
|
||||
// from google3/util/utf8/public/unilib.h
|
||||
// from google3/base/type_traits.h
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Specified by TR1 [4.7.4] Pointer modifications.
|
||||
template<typename T> struct remove_pointer { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T*> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const volatile> {
|
||||
typedef T type; };
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// Checks if the buffer contains structurally-valid UTF-8. Implemented in
|
||||
// structurally_valid.cc.
|
||||
LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ===================================================================
|
||||
// from google3/util/endian/endian.h
|
||||
LIBPROTOBUF_EXPORT uint32 ghtonl(uint32 x);
|
||||
|
||||
// ===================================================================
|
||||
// Shutdown support.
|
||||
|
||||
|
@ -1156,7 +1181,7 @@ LIBPROTOBUF_EXPORT void OnShutdown(void (*func)());
|
|||
|
||||
} // namespace internal
|
||||
|
||||
#if PROTOBUF_USE_EXCEPTIONS
|
||||
#ifdef PROTOBUF_USE_EXCEPTIONS
|
||||
class FatalException : public std::exception {
|
||||
public:
|
||||
FatalException(const char* filename, int line, const std::string& message)
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -89,16 +89,12 @@ template <typename Key, typename Data,
|
|||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_map : public std::map<Key, Data, HashFcn> {
|
||||
public:
|
||||
hash_map(int = 0) {}
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_set : public std::set<Key, HashFcn> {
|
||||
public:
|
||||
hash_set(int = 0) {}
|
||||
};
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
|
||||
|
@ -126,8 +122,6 @@ template <typename Key, typename Data,
|
|||
typename EqualKey = int >
|
||||
class hash_map : public HASH_NAMESPACE::hash_map<
|
||||
Key, Data, HashFcn> {
|
||||
public:
|
||||
hash_map(int = 0) {}
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
|
@ -135,8 +129,6 @@ template <typename Key,
|
|||
typename EqualKey = int >
|
||||
class hash_set : public HASH_NAMESPACE::hash_set<
|
||||
Key, HashFcn> {
|
||||
public:
|
||||
hash_set(int = 0) {}
|
||||
};
|
||||
|
||||
#else
|
||||
|
@ -170,8 +162,6 @@ template <typename Key, typename Data,
|
|||
typename EqualKey = std::equal_to<Key> >
|
||||
class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
|
||||
Key, Data, HashFcn, EqualKey> {
|
||||
public:
|
||||
hash_map(int = 0) {}
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
|
@ -179,8 +169,6 @@ template <typename Key,
|
|||
typename EqualKey = std::equal_to<Key> >
|
||||
class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
|
||||
Key, HashFcn, EqualKey> {
|
||||
public:
|
||||
hash_set(int = 0) {}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,119 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// 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 <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Perform a lookup in a map or hash_map.
|
||||
// If the key is present in the map then the value associated with that
|
||||
// key is returned, otherwise the value passed as a default is returned.
|
||||
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;
|
||||
}
|
||||
|
||||
// Perform a lookup in a map or hash_map.
|
||||
// If the key is present a const pointer to the associated value is returned,
|
||||
// otherwise a NULL pointer is returned.
|
||||
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;
|
||||
}
|
||||
|
||||
// Perform a lookup in a map or hash_map whose values are pointers.
|
||||
// If the key is present a const pointer to the associated value is returned,
|
||||
// otherwise a NULL pointer is returned.
|
||||
// This function does not distinguish between a missing key and a key mapped
|
||||
// to a NULL value.
|
||||
template <class Collection>
|
||||
const 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 0;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Change the value associated with a particular key in a map or hash_map.
|
||||
// If the key is not present in the map the key and value are inserted,
|
||||
// otherwise the value is updated to be a copy of the value provided.
|
||||
// True indicates that an insert took place, false indicates an update.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool InsertOrUpdate(Collection * const collection,
|
||||
const Key& key, const Value& value) {
|
||||
pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
if (!ret.second) {
|
||||
// update
|
||||
ret.first->second = value;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert a new key and value into a map or hash_map.
|
||||
// If the key is not present in the map the key and value are
|
||||
// inserted, otherwise nothing happens. True indicates that an insert
|
||||
// took place, false indicates the key was already present.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool InsertIfNotPresent(Collection * const collection,
|
||||
const Key& key, const Value& value) {
|
||||
pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -35,65 +35,54 @@
|
|||
// This header is intended to be included only by internal .cc files and
|
||||
// generated .pb.cc files. Users should not use this directly.
|
||||
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/atomicops.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace {
|
||||
|
||||
void SchedYield() {
|
||||
#ifdef _WIN32
|
||||
Sleep(0);
|
||||
#else // POSIX
|
||||
sched_yield();
|
||||
|
||||
struct ProtobufOnceInternal {
|
||||
ProtobufOnceInternal() {
|
||||
InitializeCriticalSection(&critical_section);
|
||||
}
|
||||
~ProtobufOnceInternal() {
|
||||
DeleteCriticalSection(&critical_section);
|
||||
}
|
||||
CRITICAL_SECTION critical_section;
|
||||
};
|
||||
|
||||
ProtobufOnceType::~ProtobufOnceType()
|
||||
{
|
||||
delete internal_;
|
||||
internal_ = NULL;
|
||||
}
|
||||
|
||||
ProtobufOnceType::ProtobufOnceType() {
|
||||
// internal_ may be non-NULL if Init() was already called.
|
||||
if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
|
||||
}
|
||||
|
||||
void ProtobufOnceType::Init(void (*init_func)()) {
|
||||
// internal_ may be NULL if we're still in dynamic initialization and the
|
||||
// constructor has not been called yet. As mentioned in once.h, we assume
|
||||
// that the program is still single-threaded at this time, and therefore it
|
||||
// should be safe to initialize internal_ like so.
|
||||
if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
|
||||
|
||||
EnterCriticalSection(&internal_->critical_section);
|
||||
if (!initialized_) {
|
||||
init_func();
|
||||
initialized_ = true;
|
||||
}
|
||||
LeaveCriticalSection(&internal_->critical_section);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure) {
|
||||
internal::AtomicWord state = internal::Acquire_Load(once);
|
||||
// Fast path. The provided closure was already executed.
|
||||
if (state == ONCE_STATE_DONE) {
|
||||
return;
|
||||
}
|
||||
// The closure execution did not complete yet. The once object can be in one
|
||||
// of the two following states:
|
||||
// - UNINITIALIZED: We are the first thread calling this function.
|
||||
// - EXECUTING_CLOSURE: Another thread is already executing the closure.
|
||||
//
|
||||
// First, try to change the state from UNINITIALIZED to EXECUTING_CLOSURE
|
||||
// atomically.
|
||||
state = internal::Acquire_CompareAndSwap(
|
||||
once, ONCE_STATE_UNINITIALIZED, ONCE_STATE_EXECUTING_CLOSURE);
|
||||
if (state == ONCE_STATE_UNINITIALIZED) {
|
||||
// We are the first thread to call this function, so we have to call the
|
||||
// closure.
|
||||
closure->Run();
|
||||
internal::Release_Store(once, ONCE_STATE_DONE);
|
||||
} else {
|
||||
// Another thread has already started executing the closure. We need to
|
||||
// wait until it completes the initialization.
|
||||
while (state == ONCE_STATE_EXECUTING_CLOSURE) {
|
||||
// Note that futex() could be used here on Linux as an improvement.
|
||||
SchedYield();
|
||||
state = internal::Acquire_Load(once);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -37,22 +37,16 @@
|
|||
//
|
||||
// This is basically a portable version of pthread_once().
|
||||
//
|
||||
// This header declares:
|
||||
// This header declares three things:
|
||||
// * 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)()).
|
||||
// The macro may only be used at the global scope (you cannot create local
|
||||
// or class member variables of this type).
|
||||
// * A function GogoleOnceInit(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
|
||||
|
@ -78,87 +72,50 @@
|
|||
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
|
||||
#include <google/protobuf/stubs/atomicops.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
|
||||
#ifdef _WIN32
|
||||
|
||||
typedef bool ProtobufOnceType;
|
||||
struct ProtobufOnceInternal;
|
||||
|
||||
#define GOOGLE_PROTOBUF_ONCE_INIT false
|
||||
struct LIBPROTOBUF_EXPORT ProtobufOnceType {
|
||||
ProtobufOnceType();
|
||||
~ProtobufOnceType();
|
||||
void Init(void (*init_func)());
|
||||
|
||||
volatile bool initialized_;
|
||||
ProtobufOnceInternal* internal_;
|
||||
};
|
||||
|
||||
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
|
||||
::google::protobuf::ProtobufOnceType NAME
|
||||
|
||||
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
|
||||
if (!*once) {
|
||||
*once = true;
|
||||
init_func();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg),
|
||||
Arg arg) {
|
||||
if (!*once) {
|
||||
*once = true;
|
||||
init_func(arg);
|
||||
// Note: Double-checked locking is safe on x86.
|
||||
if (!once->initialized_) {
|
||||
once->Init(init_func);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
enum {
|
||||
ONCE_STATE_UNINITIALIZED = 0,
|
||||
ONCE_STATE_EXECUTING_CLOSURE = 1,
|
||||
ONCE_STATE_DONE = 2
|
||||
};
|
||||
typedef pthread_once_t ProtobufOnceType;
|
||||
|
||||
typedef internal::AtomicWord ProtobufOnceType;
|
||||
|
||||
#define GOOGLE_PROTOBUF_ONCE_INIT ::google::protobuf::ONCE_STATE_UNINITIALIZED
|
||||
|
||||
LIBPROTOBUF_EXPORT
|
||||
void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure);
|
||||
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
|
||||
pthread_once_t NAME = PTHREAD_ONCE_INIT
|
||||
|
||||
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
|
||||
if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
|
||||
internal::FunctionClosure0 func(init_func, false);
|
||||
GoogleOnceInitImpl(once, &func);
|
||||
}
|
||||
pthread_once(once, init_func);
|
||||
}
|
||||
|
||||
template <typename Arg>
|
||||
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg*),
|
||||
Arg* arg) {
|
||||
if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
|
||||
internal::FunctionClosure1<Arg*> func(init_func, false, arg);
|
||||
GoogleOnceInitImpl(once, &func);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
|
||||
|
||||
class GoogleOnceDynamic {
|
||||
public:
|
||||
GoogleOnceDynamic() : state_(GOOGLE_PROTOBUF_ONCE_INIT) { }
|
||||
|
||||
// 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) {
|
||||
GoogleOnceInit<T>(&this->state_,
|
||||
func_with_arg,
|
||||
arg);
|
||||
}
|
||||
private:
|
||||
ProtobufOnceType state_;
|
||||
};
|
||||
|
||||
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
|
||||
::google::protobuf::ProtobufOnceType NAME = GOOGLE_PROTOBUF_ONCE_INIT
|
||||
#endif
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -28,10 +28,10 @@
|
|||
// (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
|
||||
// from google3/util/gtl/stl_util-inl.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
@ -118,4 +118,4 @@ void STLDeleteValues(T *v) {
|
|||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_H__
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -56,10 +56,10 @@ const int WireFormatLite::kMessageSetMessageTag;
|
|||
#endif
|
||||
|
||||
const int WireFormatLite::kMessageSetItemTagsSize =
|
||||
io::CodedOutputStream::StaticVarintSize32<kMessageSetItemStartTag>::value +
|
||||
io::CodedOutputStream::StaticVarintSize32<kMessageSetItemEndTag>::value +
|
||||
io::CodedOutputStream::StaticVarintSize32<kMessageSetTypeIdTag>::value +
|
||||
io::CodedOutputStream::StaticVarintSize32<kMessageSetMessageTag>::value;
|
||||
io::CodedOutputStream::VarintSize32(kMessageSetItemStartTag) +
|
||||
io::CodedOutputStream::VarintSize32(kMessageSetItemEndTag) +
|
||||
io::CodedOutputStream::VarintSize32(kMessageSetTypeIdTag) +
|
||||
io::CodedOutputStream::VarintSize32(kMessageSetMessageTag);
|
||||
|
||||
const WireFormatLite::CppType
|
||||
WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = {
|
||||
|
@ -153,65 +153,8 @@ bool WireFormatLite::SkipField(
|
|||
}
|
||||
}
|
||||
|
||||
bool WireFormatLite::SkipField(
|
||||
io::CodedInputStream* input, uint32 tag, io::CodedOutputStream* output) {
|
||||
switch (WireFormatLite::GetTagWireType(tag)) {
|
||||
case WireFormatLite::WIRETYPE_VARINT: {
|
||||
uint64 value;
|
||||
if (!input->ReadVarint64(&value)) return false;
|
||||
output->WriteVarint32(tag);
|
||||
output->WriteVarint64(value);
|
||||
return true;
|
||||
}
|
||||
case WireFormatLite::WIRETYPE_FIXED64: {
|
||||
uint64 value;
|
||||
if (!input->ReadLittleEndian64(&value)) return false;
|
||||
output->WriteVarint32(tag);
|
||||
output->WriteLittleEndian64(value);
|
||||
return true;
|
||||
}
|
||||
case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
|
||||
uint32 length;
|
||||
if (!input->ReadVarint32(&length)) return false;
|
||||
output->WriteVarint32(tag);
|
||||
output->WriteVarint32(length);
|
||||
// TODO(mkilavuz): Provide API to prevent extra string copying.
|
||||
string temp;
|
||||
if (!input->ReadString(&temp, length)) return false;
|
||||
output->WriteString(temp);
|
||||
return true;
|
||||
}
|
||||
case WireFormatLite::WIRETYPE_START_GROUP: {
|
||||
output->WriteVarint32(tag);
|
||||
if (!input->IncrementRecursionDepth()) return false;
|
||||
if (!SkipMessage(input, output)) return false;
|
||||
input->DecrementRecursionDepth();
|
||||
// Check that the ending tag matched the starting tag.
|
||||
if (!input->LastTagWas(WireFormatLite::MakeTag(
|
||||
WireFormatLite::GetTagFieldNumber(tag),
|
||||
WireFormatLite::WIRETYPE_END_GROUP))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case WireFormatLite::WIRETYPE_END_GROUP: {
|
||||
return false;
|
||||
}
|
||||
case WireFormatLite::WIRETYPE_FIXED32: {
|
||||
uint32 value;
|
||||
if (!input->ReadLittleEndian32(&value)) return false;
|
||||
output->WriteVarint32(tag);
|
||||
output->WriteLittleEndian32(value);
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
|
||||
while (true) {
|
||||
while(true) {
|
||||
uint32 tag = input->ReadTag();
|
||||
if (tag == 0) {
|
||||
// End of input. This is a valid place to end, so return true.
|
||||
|
@ -229,27 +172,6 @@ bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
|
|||
}
|
||||
}
|
||||
|
||||
bool WireFormatLite::SkipMessage(io::CodedInputStream* input,
|
||||
io::CodedOutputStream* output) {
|
||||
while (true) {
|
||||
uint32 tag = input->ReadTag();
|
||||
if (tag == 0) {
|
||||
// End of input. This is a valid place to end, so return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
|
||||
|
||||
if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
|
||||
output->WriteVarint32(tag);
|
||||
// Must be the end of the message.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SkipField(input, tag, output)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FieldSkipper::SkipField(
|
||||
io::CodedInputStream* input, uint32 tag) {
|
||||
return WireFormatLite::SkipField(input, tag);
|
||||
|
@ -260,23 +182,8 @@ bool FieldSkipper::SkipMessage(io::CodedInputStream* input) {
|
|||
}
|
||||
|
||||
void FieldSkipper::SkipUnknownEnum(
|
||||
int /* field_number */, int /* value */) {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
bool CodedOutputStreamFieldSkipper::SkipField(
|
||||
io::CodedInputStream* input, uint32 tag) {
|
||||
return WireFormatLite::SkipField(input, tag, unknown_fields_);
|
||||
}
|
||||
|
||||
bool CodedOutputStreamFieldSkipper::SkipMessage(io::CodedInputStream* input) {
|
||||
return WireFormatLite::SkipMessage(input, unknown_fields_);
|
||||
}
|
||||
|
||||
void CodedOutputStreamFieldSkipper::SkipUnknownEnum(
|
||||
int field_number, int value) {
|
||||
unknown_fields_->WriteVarint32(field_number);
|
||||
unknown_fields_->WriteVarint64(value);
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input,
|
||||
|
@ -374,34 +281,15 @@ void WireFormatLite::WriteString(int field_number, const string& value,
|
|||
io::CodedOutputStream* output) {
|
||||
// String is for UTF-8 text only
|
||||
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
|
||||
GOOGLE_CHECK(value.size() <= kint32max);
|
||||
output->WriteVarint32(value.size());
|
||||
output->WriteString(value);
|
||||
}
|
||||
void WireFormatLite::WriteStringMaybeAliased(
|
||||
int field_number, const string& value,
|
||||
io::CodedOutputStream* output) {
|
||||
// String is for UTF-8 text only
|
||||
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
|
||||
GOOGLE_CHECK(value.size() <= kint32max);
|
||||
output->WriteVarint32(value.size());
|
||||
output->WriteRawMaybeAliased(value.data(), value.size());
|
||||
}
|
||||
void WireFormatLite::WriteBytes(int field_number, const string& value,
|
||||
io::CodedOutputStream* output) {
|
||||
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
|
||||
GOOGLE_CHECK(value.size() <= kint32max);
|
||||
output->WriteVarint32(value.size());
|
||||
output->WriteString(value);
|
||||
}
|
||||
void WireFormatLite::WriteBytesMaybeAliased(
|
||||
int field_number, const string& value,
|
||||
io::CodedOutputStream* output) {
|
||||
WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
|
||||
GOOGLE_CHECK(value.size() <= kint32max);
|
||||
output->WriteVarint32(value.size());
|
||||
output->WriteRawMaybeAliased(value.data(), value.size());
|
||||
}
|
||||
|
||||
|
||||
void WireFormatLite::WriteGroup(int field_number,
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -40,16 +40,17 @@
|
|||
#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
|
||||
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <google/protobuf/io/coded_stream.h> // for CodedOutputStream::Varint32Size
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
template <typename T> class RepeatedField; // repeated_field.h
|
||||
namespace io {
|
||||
class CodedInputStream; // coded_stream.h
|
||||
class CodedOutputStream; // coded_stream.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
|
@ -164,22 +165,11 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
|
|||
// 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
|
||||
|
@ -240,9 +230,9 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
|
|||
// that file to use these.
|
||||
|
||||
// Avoid ugly line wrapping
|
||||
#define input io::CodedInputStream* input_arg
|
||||
#define output io::CodedOutputStream* output_arg
|
||||
#define field_number int field_number_arg
|
||||
#define input io::CodedInputStream* input
|
||||
#define output io::CodedOutputStream* output
|
||||
#define field_number int field_number
|
||||
#define INL GOOGLE_ATTRIBUTE_ALWAYS_INLINE
|
||||
|
||||
// Read fields, not including tags. The assumption is that you already
|
||||
|
@ -352,10 +342,6 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
|
|||
|
||||
static void WriteString(field_number, const string& value, output);
|
||||
static void WriteBytes (field_number, const string& value, output);
|
||||
static void WriteStringMaybeAliased(
|
||||
field_number, const string& value, output);
|
||||
static void WriteBytesMaybeAliased(
|
||||
field_number, const string& value, output);
|
||||
|
||||
static void WriteGroup(
|
||||
field_number, const MessageLite& value, output);
|
||||
|
@ -491,10 +477,6 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
|
|||
template<typename MessageType>
|
||||
static inline int 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 int LengthDelimitedSize(int 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
|
||||
|
@ -506,12 +488,6 @@ class LIBPROTOBUF_EXPORT WireFormatLite {
|
|||
google::protobuf::io::CodedInputStream* input,
|
||||
RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
|
||||
// Like ReadRepeatedFixedSizePrimitive but for packed primitive fields.
|
||||
template <typename CType, enum FieldType DeclaredType>
|
||||
static inline bool ReadPackedFixedSizePrimitive(
|
||||
google::protobuf::io::CodedInputStream* input,
|
||||
RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
|
||||
static const CppType kFieldTypeToCppTypeMap[];
|
||||
static const WireFormatLite::WireType kWireTypeForFieldType[];
|
||||
|
||||
|
@ -540,24 +516,6 @@ class LIBPROTOBUF_EXPORT FieldSkipper {
|
|||
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
|
|
@ -1,6 +1,6 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
|
@ -36,16 +36,13 @@
|
|||
#ifndef GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
|
||||
#define GOOGLE_PROTOBUF_WIRE_FORMAT_LITE_INL_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// This is required for min/max on VS2013 only.
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/wire_format_lite.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
|
||||
|
||||
|
@ -155,8 +152,8 @@ template <>
|
|||
inline bool WireFormatLite::ReadPrimitive<bool, WireFormatLite::TYPE_BOOL>(
|
||||
io::CodedInputStream* input,
|
||||
bool* value) {
|
||||
uint64 temp;
|
||||
if (!input->ReadVarint64(&temp)) return false;
|
||||
uint32 temp;
|
||||
if (!input->ReadVarint32(&temp)) return false;
|
||||
*value = temp != 0;
|
||||
return true;
|
||||
}
|
||||
|
@ -226,11 +223,10 @@ inline const uint8* WireFormatLite::ReadPrimitiveFromArray<
|
|||
}
|
||||
|
||||
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
|
||||
inline bool WireFormatLite::ReadRepeatedPrimitive(
|
||||
int, // tag_size, unused.
|
||||
uint32 tag,
|
||||
io::CodedInputStream* input,
|
||||
RepeatedField<CType>* values) {
|
||||
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);
|
||||
|
@ -290,7 +286,7 @@ inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive(
|
|||
return true;
|
||||
}
|
||||
|
||||
// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
|
||||
// Specializations of ReadRepeatedPrimitive for the fixed size types, which use
|
||||
// the optimized code path.
|
||||
#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \
|
||||
template <> \
|
||||
|
@ -305,12 +301,12 @@ inline bool WireFormatLite::ReadRepeatedPrimitive< \
|
|||
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)
|
||||
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
|
||||
|
||||
|
@ -339,86 +335,6 @@ inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename CType, enum WireFormatLite::FieldType DeclaredType>
|
||||
inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
|
||||
io::CodedInputStream* input, RepeatedField<CType>* values) {
|
||||
uint32 length;
|
||||
if (!input->ReadVarint32(&length)) return false;
|
||||
const uint32 old_entries = values->size();
|
||||
const uint32 new_entries = length / sizeof(CType);
|
||||
const uint32 new_bytes = new_entries * 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 {
|
||||
bytes_limit =
|
||||
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 (uint32 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 (uint32 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) {
|
||||
|
@ -746,13 +662,15 @@ inline uint8* WireFormatLite::WriteStringToArray(int field_number,
|
|||
// 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);
|
||||
target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target);
|
||||
return io::CodedOutputStream::WriteStringToArray(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);
|
||||
target = io::CodedOutputStream::WriteVarint32ToArray(value.size(), target);
|
||||
return io::CodedOutputStream::WriteStringToArray(value, target);
|
||||
}
|
||||
|
||||
|
||||
|
@ -832,7 +750,8 @@ inline int WireFormatLite::GroupSize(const MessageLite& value) {
|
|||
return value.ByteSize();
|
||||
}
|
||||
inline int WireFormatLite::MessageSize(const MessageLite& value) {
|
||||
return LengthDelimitedSize(value.ByteSize());
|
||||
int size = value.ByteSize();
|
||||
return io::CodedOutputStream::VarintSize32(size) + size;
|
||||
}
|
||||
|
||||
// See comment on ReadGroupNoVirtual to understand the need for this template
|
||||
|
@ -845,12 +764,8 @@ inline int WireFormatLite::GroupSizeNoVirtual(
|
|||
template<typename MessageType_WorkAroundCppLookupDefect>
|
||||
inline int WireFormatLite::MessageSizeNoVirtual(
|
||||
const MessageType_WorkAroundCppLookupDefect& value) {
|
||||
return LengthDelimitedSize(
|
||||
value.MessageType_WorkAroundCppLookupDefect::ByteSize());
|
||||
}
|
||||
|
||||
inline int WireFormatLite::LengthDelimitedSize(int length) {
|
||||
return io::CodedOutputStream::VarintSize32(length) + length;
|
||||
int size = value.MessageType_WorkAroundCppLookupDefect::ByteSize();
|
||||
return io::CodedOutputStream::VarintSize32(size) + size;
|
||||
}
|
||||
|
||||
} // namespace internal
|
|
@ -1,365 +0,0 @@
|
|||
--- a/toolkit/components/protobuf/src/google/protobuf/wire_format_lite.h
|
||||
+++ b/toolkit/components/protobuf/src/google/protobuf/wire_format_lite.h
|
||||
@@ -35,16 +35,17 @@
|
||||
// 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 <algorithm>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <google/protobuf/io/coded_stream.h> // for CodedOutputStream::Varint32Size
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
--- a/toolkit/components/protobuf/src/google/protobuf/wire_format.cc
|
||||
+++ b/toolkit/components/protobuf/src/google/protobuf/wire_format.cc
|
||||
@@ -819,30 +819,35 @@ void WireFormat::SerializeFieldWithCachedSizes(
|
||||
HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64)
|
||||
|
||||
HANDLE_PRIMITIVE_TYPE(FLOAT , float , Float , Float )
|
||||
HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
|
||||
|
||||
HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
|
||||
#undef HANDLE_PRIMITIVE_TYPE
|
||||
|
||||
-#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \
|
||||
- case FieldDescriptor::TYPE_##TYPE: \
|
||||
- WireFormatLite::Write##TYPE_METHOD( \
|
||||
- field->number(), \
|
||||
- field->is_repeated() ? \
|
||||
- message_reflection->GetRepeated##CPPTYPE_METHOD( \
|
||||
- message, field, j) : \
|
||||
- message_reflection->Get##CPPTYPE_METHOD(message, field), \
|
||||
- output); \
|
||||
+ case FieldDescriptor::TYPE_GROUP:
|
||||
+ WireFormatLite::WriteGroup(
|
||||
+ field->number(),
|
||||
+ field->is_repeated() ?
|
||||
+ message_reflection->GetRepeatedMessage(
|
||||
+ message, field, j) :
|
||||
+ message_reflection->GetMessage(message, field),
|
||||
+ output);
|
||||
break;
|
||||
|
||||
- HANDLE_TYPE(GROUP , Group , Message)
|
||||
- HANDLE_TYPE(MESSAGE, Message, Message)
|
||||
-#undef HANDLE_TYPE
|
||||
+ case FieldDescriptor::TYPE_MESSAGE:
|
||||
+ WireFormatLite::WriteMessage(
|
||||
+ field->number(),
|
||||
+ field->is_repeated() ?
|
||||
+ message_reflection->GetRepeatedMessage(
|
||||
+ message, field, j) :
|
||||
+ message_reflection->GetMessage(message, field),
|
||||
+ output);
|
||||
+ break;
|
||||
|
||||
case FieldDescriptor::TYPE_ENUM: {
|
||||
const EnumValueDescriptor* value = field->is_repeated() ?
|
||||
message_reflection->GetRepeatedEnum(message, field, j) :
|
||||
message_reflection->GetEnum(message, field);
|
||||
if (is_packed) {
|
||||
WireFormatLite::WriteEnumNoTag(value->number(), output);
|
||||
} else {
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/io/gzip_stream.cc
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/io/gzip_stream.cc
|
||||
@@ -28,17 +28,16 @@
|
||||
// (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: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the implementation of classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
|
||||
-#include "config.h"
|
||||
|
||||
#if HAVE_ZLIB
|
||||
#include <google/protobuf/io/gzip_stream.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/stubs/common.cc
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/stubs/common.cc
|
||||
@@ -31,23 +31,22 @@
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
|
||||
-#include "config.h"
|
||||
|
||||
#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_H)
|
||||
-#elif defined(HAVE_PTHREAD)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "No suitable threading library available."
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/stubs/common.h
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/stubs/common.h
|
||||
@@ -363,71 +363,20 @@
|
||||
// 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.
|
||||
|
||||
+#define GOOGLE_COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
|
||||
-namespace internal {
|
||||
-
|
||||
-template <bool>
|
||||
-struct CompileAssert {
|
||||
-};
|
||||
-
|
||||
-} // namespace internal
|
||||
|
||||
-#undef GOOGLE_COMPILE_ASSERT
|
||||
-#define GOOGLE_COMPILE_ASSERT(expr, msg) \
|
||||
- typedef ::google::protobuf::internal::CompileAssert<(bool(expr))> \
|
||||
- msg[bool(expr) ? 1 : -1]
|
||||
|
||||
|
||||
-// 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.
|
||||
-
|
||||
// ===================================================================
|
||||
// from google3/base/scoped_ptr.h
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This is an implementation designed to match the anticipated future TR2
|
||||
// implementation of the scoped_ptr class, and its closely-related brethren,
|
||||
// scoped_array, scoped_ptr_malloc, and make_scoped_ptr.
|
||||
@@ -582,16 +582,27 @@ enum LogLevel {
|
||||
// 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
|
||||
+
|
||||
+#ifdef ERROR
|
||||
+ // ERROR is defined as 0 on some windows builds, so `GOOGLE_LOG(ERROR, ...)`
|
||||
+ // expands into `GOOGLE_LOG(0, ...)` which then expands into
|
||||
+ // `someGoogleLogging(LOGLEVEL_0, ...)`. This is not ideal, because the
|
||||
+ // GOOGLE_LOG macro expects to expand itself into
|
||||
+ // `someGoogleLogging(LOGLEVEL_ERROR, ...)` instead. The workaround to get
|
||||
+ // everything building is to simply define LOGLEVEL_0 as LOGLEVEL_ERROR and
|
||||
+ // move on with our lives.
|
||||
+ , LOGLEVEL_0 = LOGLEVEL_ERROR
|
||||
+#endif
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
class LogFinisher;
|
||||
|
||||
class LIBPROTOBUF_EXPORT LogMessage {
|
||||
public:
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/stubs/hash.h
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/stubs/hash.h
|
||||
@@ -32,17 +32,16 @@
|
||||
//
|
||||
// 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>
|
||||
-#include "config.h"
|
||||
|
||||
#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
|
||||
#include HASH_MAP_H
|
||||
#include HASH_SET_H
|
||||
#else
|
||||
#define MISSING_HASH
|
||||
#include <map>
|
||||
#include <set>
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/stubs/stringprintf.cc
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/stubs/stringprintf.cc
|
||||
@@ -32,17 +32,16 @@
|
||||
|
||||
#include <google/protobuf/stubs/stringprintf.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h> // For va_list and related operations
|
||||
#include <stdio.h> // MSVC requires this for _vsnprintf
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
-#include <google/protobuf/testing/googletest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
enum { IS_COMPILER_MSVC = 1 };
|
||||
#ifndef va_copy
|
||||
// Define va_copy for MSVC. This is a hack, assuming va_list is simply a
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/stubs/strutil.h
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/stubs/strutil.h
|
||||
@@ -332,16 +332,17 @@
|
||||
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) {
|
||||
+ static_assert(sizeof(int64) == sizeof(long long), "Protobuf needs sizeof(int64) == sizeof(long long)");
|
||||
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);
|
||||
--- a/toolkit/components/protobuf/src/google/protobuf/stubs/strutil.cc
|
||||
+++ b/toolkit/components/protobuf/src/google/protobuf/stubs/strutil.cc
|
||||
@@ -33,16 +33,18 @@
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <errno.h>
|
||||
#include <float.h> // FLT_DIG and DBL_DIG
|
||||
#include <limits>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <iterator>
|
||||
|
||||
+#include "mozilla/FloatingPoint.h"
|
||||
+
|
||||
#ifdef _WIN32
|
||||
// MSVC has only _snprintf, not snprintf.
|
||||
//
|
||||
// MinGW has both snprintf and _snprintf, but they appear to be different
|
||||
// functions. The former is buggy. When invoked like so:
|
||||
// char buffer[32];
|
||||
// snprintf(buffer, 32, "%.*g\n", FLT_DIG, 1.23e10f);
|
||||
// it prints "1.23000e+10". This is plainly wrong: %g should never print
|
||||
@@ -51,18 +53,17 @@
|
||||
// right thing, so we use it.
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
inline bool IsNaN(double value) {
|
||||
- // NaN is never equal to anything, even itself.
|
||||
- return value != value;
|
||||
+ return ::mozilla::IsNaN(value);
|
||||
}
|
||||
|
||||
// These are defined as macros on some platforms. #undef them so that we can
|
||||
// redefine them.
|
||||
#undef isxdigit
|
||||
#undef isprint
|
||||
|
||||
// The definitions of these in ctype.h change based on locale. Since our
|
||||
--- b/toolkit/components/protobuf/src/google/protobuf/stubs/type_traits.h
|
||||
+++ a/toolkit/components/protobuf/src/google/protobuf/stubs/type_traits.h
|
||||
@@ -107,20 +107,18 @@
|
||||
template<> struct is_integral<wchar_t> : true_type { };
|
||||
#endif
|
||||
template<> struct is_integral<short> : true_type { };
|
||||
template<> struct is_integral<unsigned short> : true_type { };
|
||||
template<> struct is_integral<int> : true_type { };
|
||||
template<> struct is_integral<unsigned int> : true_type { };
|
||||
template<> struct is_integral<long> : true_type { };
|
||||
template<> struct is_integral<unsigned long> : true_type { };
|
||||
-#ifdef HAVE_LONG_LONG
|
||||
template<> struct is_integral<long long> : true_type { };
|
||||
template<> struct is_integral<unsigned long long> : true_type { };
|
||||
-#endif
|
||||
template <class T> struct is_integral<const T> : is_integral<T> { };
|
||||
template <class T> struct is_integral<volatile T> : is_integral<T> { };
|
||||
template <class T> struct is_integral<const volatile T> : is_integral<T> { };
|
||||
|
||||
// is_floating_point is false except for the built-in floating-point types.
|
||||
// A cv-qualified type is integral if and only if the underlying type is.
|
||||
template <class T> struct is_floating_point : false_type { };
|
||||
template<> struct is_floating_point<float> : true_type { };
|
||||
--- a/toolkit/components/protobuf/src/google/protobuf/wire_format_lite_inl.h
|
||||
+++ b/toolkit/components/protobuf/src/google/protobuf/wire_format_lite_inl.h
|
||||
@@ -375,17 +375,17 @@ inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
|
||||
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) {
|
||||
+ for (uint32 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.
|
|
@ -5,117 +5,52 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.google.protobuf += [
|
||||
'src/google/protobuf/descriptor.h',
|
||||
'src/google/protobuf/descriptor.pb.h',
|
||||
'src/google/protobuf/descriptor_database.h',
|
||||
'src/google/protobuf/dynamic_message.h',
|
||||
'src/google/protobuf/extension_set.h',
|
||||
'src/google/protobuf/generated_enum_reflection.h',
|
||||
'src/google/protobuf/generated_message_reflection.h',
|
||||
'src/google/protobuf/generated_message_util.h',
|
||||
'src/google/protobuf/message.h',
|
||||
'src/google/protobuf/message_lite.h',
|
||||
'src/google/protobuf/package_info.h',
|
||||
'src/google/protobuf/reflection_ops.h',
|
||||
'src/google/protobuf/repeated_field.h',
|
||||
'src/google/protobuf/service.h',
|
||||
'src/google/protobuf/text_format.h',
|
||||
'src/google/protobuf/unknown_field_set.h',
|
||||
'src/google/protobuf/wire_format.h',
|
||||
'src/google/protobuf/wire_format_lite.h',
|
||||
'src/google/protobuf/wire_format_lite_inl.h',
|
||||
]
|
||||
|
||||
EXPORTS.google.protobuf.io += [
|
||||
'src/google/protobuf/io/coded_stream.h',
|
||||
'src/google/protobuf/io/coded_stream_inl.h',
|
||||
'src/google/protobuf/io/gzip_stream.h',
|
||||
'src/google/protobuf/io/package_info.h',
|
||||
'src/google/protobuf/io/printer.h',
|
||||
'src/google/protobuf/io/strtod.h',
|
||||
'src/google/protobuf/io/tokenizer.h',
|
||||
'src/google/protobuf/io/zero_copy_stream.h',
|
||||
'src/google/protobuf/io/zero_copy_stream_impl.h',
|
||||
'src/google/protobuf/io/zero_copy_stream_impl_lite.h',
|
||||
'google/protobuf/extension_set.h',
|
||||
'google/protobuf/generated_message_util.h',
|
||||
'google/protobuf/message_lite.h',
|
||||
'google/protobuf/repeated_field.h',
|
||||
'google/protobuf/wire_format_lite.h',
|
||||
'google/protobuf/wire_format_lite_inl.h',
|
||||
]
|
||||
|
||||
EXPORTS.google.protobuf.stubs += [
|
||||
'src/google/protobuf/stubs/atomicops.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_arm64_gcc.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_arm_gcc.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_arm_qnx.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_atomicword_compat.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_generic_gcc.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_macosx.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_mips_gcc.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_pnacl.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_solaris.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_tsan.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_x86_gcc.h',
|
||||
'src/google/protobuf/stubs/atomicops_internals_x86_msvc.h',
|
||||
'src/google/protobuf/stubs/common.h',
|
||||
'src/google/protobuf/stubs/hash.h',
|
||||
'src/google/protobuf/stubs/map_util.h',
|
||||
'src/google/protobuf/stubs/once.h',
|
||||
'src/google/protobuf/stubs/platform_macros.h',
|
||||
'src/google/protobuf/stubs/shared_ptr.h',
|
||||
'src/google/protobuf/stubs/stl_util.h',
|
||||
'src/google/protobuf/stubs/stringprintf.h',
|
||||
'src/google/protobuf/stubs/strutil.h',
|
||||
'src/google/protobuf/stubs/substitute.h',
|
||||
'src/google/protobuf/stubs/template_util.h',
|
||||
'src/google/protobuf/stubs/type_traits.h',
|
||||
'google/protobuf/stubs/common.h',
|
||||
'google/protobuf/stubs/hash.h',
|
||||
'google/protobuf/stubs/map-util.h',
|
||||
'google/protobuf/stubs/once.h',
|
||||
'google/protobuf/stubs/stl_util-inl.h',
|
||||
]
|
||||
|
||||
EXPORTS.google.protobuf.io += [
|
||||
'google/protobuf/io/coded_stream.h',
|
||||
'google/protobuf/io/coded_stream_inl.h',
|
||||
'google/protobuf/io/zero_copy_stream.h',
|
||||
'google/protobuf/io/zero_copy_stream_impl.h',
|
||||
'google/protobuf/io/zero_copy_stream_impl_lite.h',
|
||||
'google/protobuf/package_info.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'src/google/protobuf/descriptor.cc',
|
||||
'src/google/protobuf/descriptor.pb.cc',
|
||||
'src/google/protobuf/descriptor_database.cc',
|
||||
'src/google/protobuf/dynamic_message.cc',
|
||||
'src/google/protobuf/extension_set.cc',
|
||||
'src/google/protobuf/generated_message_reflection.cc',
|
||||
'src/google/protobuf/generated_message_util.cc',
|
||||
'src/google/protobuf/io/coded_stream.cc',
|
||||
'src/google/protobuf/io/gzip_stream.cc',
|
||||
'src/google/protobuf/io/printer.cc',
|
||||
'src/google/protobuf/io/strtod.cc',
|
||||
'src/google/protobuf/io/tokenizer.cc',
|
||||
'src/google/protobuf/io/zero_copy_stream.cc',
|
||||
'src/google/protobuf/io/zero_copy_stream_impl.cc',
|
||||
'src/google/protobuf/io/zero_copy_stream_impl_lite.cc',
|
||||
'src/google/protobuf/message.cc',
|
||||
'src/google/protobuf/message_lite.cc',
|
||||
'src/google/protobuf/reflection_ops.cc',
|
||||
'src/google/protobuf/repeated_field.cc',
|
||||
'src/google/protobuf/service.cc',
|
||||
'src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc',
|
||||
'src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc',
|
||||
'src/google/protobuf/stubs/common.cc',
|
||||
'src/google/protobuf/stubs/once.cc',
|
||||
'src/google/protobuf/stubs/stringprintf.cc',
|
||||
'src/google/protobuf/stubs/structurally_valid.cc',
|
||||
'src/google/protobuf/stubs/strutil.cc',
|
||||
'src/google/protobuf/stubs/substitute.cc',
|
||||
'src/google/protobuf/unknown_field_set.cc',
|
||||
'src/google/protobuf/wire_format_lite.cc',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'src/google/protobuf/extension_set_heavy.cc',
|
||||
'src/google/protobuf/text_format.cc',
|
||||
'src/google/protobuf/wire_format.cc',
|
||||
'google/protobuf/extension_set.cc',
|
||||
'google/protobuf/generated_message_util.cc',
|
||||
'google/protobuf/io/coded_stream.cc',
|
||||
'google/protobuf/io/zero_copy_stream.cc',
|
||||
'google/protobuf/io/zero_copy_stream_impl_lite.cc',
|
||||
'google/protobuf/message_lite.cc',
|
||||
'google/protobuf/repeated_field.cc',
|
||||
'google/protobuf/stubs/common.cc',
|
||||
'google/protobuf/stubs/once.cc',
|
||||
'google/protobuf/wire_format_lite.cc',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
DEFINES['GOOGLE_PROTOBUF_NO_RTTI'] = True
|
||||
DEFINES['GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER'] = True
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-null-conversion',
|
||||
'-Wno-return-type',
|
||||
'-Wno-sign-compare',
|
||||
]
|
||||
elif CONFIG['_MSC_VER']:
|
||||
|
@ -125,10 +60,4 @@ elif CONFIG['_MSC_VER']:
|
|||
'-wd4099', # mismatched class/struct tags
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_USE_PTHREADS']:
|
||||
DEFINES['HAVE_PTHREAD'] = True
|
||||
|
||||
# Needed for the gzip streams.
|
||||
DEFINES['HAVE_ZLIB'] = True
|
||||
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
Index: src/google/protobuf/io/zero_copy_stream_impl_lite.cc
|
||||
===================================================================
|
||||
--- src/google/protobuf/io/zero_copy_stream_impl_lite.cc (revision 511)
|
||||
+++ src/google/protobuf/io/zero_copy_stream_impl_lite.cc (revision 512)
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
+#include <algorithm>
|
||||
+
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,687 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// The messages in this file describe the definitions found in .proto files.
|
||||
// A valid .proto file can be translated directly to a FileDescriptorProto
|
||||
// without any other information (e.g. without reading its imports).
|
||||
|
||||
|
||||
|
||||
package google.protobuf;
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DescriptorProtos";
|
||||
|
||||
// descriptor.proto must be optimized for speed because reflection-based
|
||||
// algorithms don't work during bootstrapping.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// The protocol compiler can output a FileDescriptorSet containing the .proto
|
||||
// files it parses.
|
||||
message FileDescriptorSet {
|
||||
repeated FileDescriptorProto file = 1;
|
||||
}
|
||||
|
||||
// Describes a complete .proto file.
|
||||
message FileDescriptorProto {
|
||||
optional string name = 1; // file name, relative to root of source tree
|
||||
optional string package = 2; // e.g. "foo", "foo.bar", etc.
|
||||
|
||||
// Names of files imported by this file.
|
||||
repeated string dependency = 3;
|
||||
// Indexes of the public imported files in the dependency list above.
|
||||
repeated int32 public_dependency = 10;
|
||||
// Indexes of the weak imported files in the dependency list.
|
||||
// For Google-internal migration only. Do not use.
|
||||
repeated int32 weak_dependency = 11;
|
||||
|
||||
// All top-level definitions in this file.
|
||||
repeated DescriptorProto message_type = 4;
|
||||
repeated EnumDescriptorProto enum_type = 5;
|
||||
repeated ServiceDescriptorProto service = 6;
|
||||
repeated FieldDescriptorProto extension = 7;
|
||||
|
||||
optional FileOptions options = 8;
|
||||
|
||||
// This field contains optional information about the original source code.
|
||||
// You may safely remove this entire field whithout harming runtime
|
||||
// functionality of the descriptors -- the information is needed only by
|
||||
// development tools.
|
||||
optional SourceCodeInfo source_code_info = 9;
|
||||
}
|
||||
|
||||
// Describes a message type.
|
||||
message DescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated FieldDescriptorProto field = 2;
|
||||
repeated FieldDescriptorProto extension = 6;
|
||||
|
||||
repeated DescriptorProto nested_type = 3;
|
||||
repeated EnumDescriptorProto enum_type = 4;
|
||||
|
||||
message ExtensionRange {
|
||||
optional int32 start = 1;
|
||||
optional int32 end = 2;
|
||||
}
|
||||
repeated ExtensionRange extension_range = 5;
|
||||
|
||||
repeated OneofDescriptorProto oneof_decl = 8;
|
||||
|
||||
optional MessageOptions options = 7;
|
||||
}
|
||||
|
||||
// Describes a field within a message.
|
||||
message FieldDescriptorProto {
|
||||
enum Type {
|
||||
// 0 is reserved for errors.
|
||||
// Order is weird for historical reasons.
|
||||
TYPE_DOUBLE = 1;
|
||||
TYPE_FLOAT = 2;
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
|
||||
// negative values are likely.
|
||||
TYPE_INT64 = 3;
|
||||
TYPE_UINT64 = 4;
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
|
||||
// negative values are likely.
|
||||
TYPE_INT32 = 5;
|
||||
TYPE_FIXED64 = 6;
|
||||
TYPE_FIXED32 = 7;
|
||||
TYPE_BOOL = 8;
|
||||
TYPE_STRING = 9;
|
||||
TYPE_GROUP = 10; // Tag-delimited aggregate.
|
||||
TYPE_MESSAGE = 11; // Length-delimited aggregate.
|
||||
|
||||
// New in version 2.
|
||||
TYPE_BYTES = 12;
|
||||
TYPE_UINT32 = 13;
|
||||
TYPE_ENUM = 14;
|
||||
TYPE_SFIXED32 = 15;
|
||||
TYPE_SFIXED64 = 16;
|
||||
TYPE_SINT32 = 17; // Uses ZigZag encoding.
|
||||
TYPE_SINT64 = 18; // Uses ZigZag encoding.
|
||||
};
|
||||
|
||||
enum Label {
|
||||
// 0 is reserved for errors
|
||||
LABEL_OPTIONAL = 1;
|
||||
LABEL_REQUIRED = 2;
|
||||
LABEL_REPEATED = 3;
|
||||
// TODO(sanjay): Should we add LABEL_MAP?
|
||||
};
|
||||
|
||||
optional string name = 1;
|
||||
optional int32 number = 3;
|
||||
optional Label label = 4;
|
||||
|
||||
// If type_name is set, this need not be set. If both this and type_name
|
||||
// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
|
||||
optional Type type = 5;
|
||||
|
||||
// For message and enum types, this is the name of the type. If the name
|
||||
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
|
||||
// rules are used to find the type (i.e. first the nested types within this
|
||||
// message are searched, then within the parent, on up to the root
|
||||
// namespace).
|
||||
optional string type_name = 6;
|
||||
|
||||
// For extensions, this is the name of the type being extended. It is
|
||||
// resolved in the same manner as type_name.
|
||||
optional string extendee = 2;
|
||||
|
||||
// For numeric types, contains the original text representation of the value.
|
||||
// For booleans, "true" or "false".
|
||||
// For strings, contains the default text contents (not escaped in any way).
|
||||
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
|
||||
// TODO(kenton): Base-64 encode?
|
||||
optional string default_value = 7;
|
||||
|
||||
// If set, gives the index of a oneof in the containing type's oneof_decl
|
||||
// list. This field is a member of that oneof. Extensions of a oneof should
|
||||
// not set this since the oneof to which they belong will be inferred based
|
||||
// on the extension range containing the extension's field number.
|
||||
optional int32 oneof_index = 9;
|
||||
|
||||
optional FieldOptions options = 8;
|
||||
}
|
||||
|
||||
// Describes a oneof.
|
||||
message OneofDescriptorProto {
|
||||
optional string name = 1;
|
||||
}
|
||||
|
||||
// Describes an enum type.
|
||||
message EnumDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated EnumValueDescriptorProto value = 2;
|
||||
|
||||
optional EnumOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a value within an enum.
|
||||
message EnumValueDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional int32 number = 2;
|
||||
|
||||
optional EnumValueOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a service.
|
||||
message ServiceDescriptorProto {
|
||||
optional string name = 1;
|
||||
repeated MethodDescriptorProto method = 2;
|
||||
|
||||
optional ServiceOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a method of a service.
|
||||
message MethodDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
// Input and output type names. These are resolved in the same way as
|
||||
// FieldDescriptorProto.type_name, but must refer to a message type.
|
||||
optional string input_type = 2;
|
||||
optional string output_type = 3;
|
||||
|
||||
optional MethodOptions options = 4;
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Options
|
||||
|
||||
// Each of the definitions above may have "options" attached. These are
|
||||
// just annotations which may cause code to be generated slightly differently
|
||||
// or may contain hints for code that manipulates protocol messages.
|
||||
//
|
||||
// Clients may define custom options as extensions of the *Options messages.
|
||||
// These extensions may not yet be known at parsing time, so the parser cannot
|
||||
// store the values in them. Instead it stores them in a field in the *Options
|
||||
// message called uninterpreted_option. This field must have the same name
|
||||
// across all *Options messages. We then use this field to populate the
|
||||
// extensions when we build a descriptor, at which point all protos have been
|
||||
// parsed and so all extensions are known.
|
||||
//
|
||||
// Extension numbers for custom options may be chosen as follows:
|
||||
// * For options which will only be used within a single application or
|
||||
// organization, or for experimental options, use field numbers 50000
|
||||
// through 99999. It is up to you to ensure that you do not use the
|
||||
// same number for multiple options.
|
||||
// * For options which will be published and used publicly by multiple
|
||||
// independent entities, e-mail protobuf-global-extension-registry@google.com
|
||||
// to reserve extension numbers. Simply provide your project name (e.g.
|
||||
// Object-C plugin) and your porject website (if available) -- there's no need
|
||||
// to explain how you intend to use them. Usually you only need one extension
|
||||
// number. You can declare multiple options with only one extension number by
|
||||
// putting them in a sub-message. See the Custom Options section of the docs
|
||||
// for examples:
|
||||
// https://developers.google.com/protocol-buffers/docs/proto#options
|
||||
// If this turns out to be popular, a web service will be set up
|
||||
// to automatically assign option numbers.
|
||||
|
||||
|
||||
message FileOptions {
|
||||
|
||||
// Sets the Java package where classes generated from this .proto will be
|
||||
// placed. By default, the proto package is used, but this is often
|
||||
// inappropriate because proto packages do not normally start with backwards
|
||||
// domain names.
|
||||
optional string java_package = 1;
|
||||
|
||||
|
||||
// If set, all the classes from the .proto file are wrapped in a single
|
||||
// outer class with the given name. This applies to both Proto1
|
||||
// (equivalent to the old "--one_java_file" option) and Proto2 (where
|
||||
// a .proto always translates to a single class, but you may want to
|
||||
// explicitly choose the class name).
|
||||
optional string java_outer_classname = 8;
|
||||
|
||||
// If set true, then the Java code generator will generate a separate .java
|
||||
// file for each top-level message, enum, and service defined in the .proto
|
||||
// file. Thus, these types will *not* be nested inside the outer class
|
||||
// named by java_outer_classname. However, the outer class will still be
|
||||
// generated to contain the file's getDescriptor() method as well as any
|
||||
// top-level extensions defined in the file.
|
||||
optional bool java_multiple_files = 10 [default=false];
|
||||
|
||||
// If set true, then the Java code generator will generate equals() and
|
||||
// hashCode() methods for all messages defined in the .proto file.
|
||||
// - In the full runtime, this is purely a speed optimization, as the
|
||||
// AbstractMessage base class includes reflection-based implementations of
|
||||
// these methods.
|
||||
//- In the lite runtime, setting this option changes the semantics of
|
||||
// equals() and hashCode() to more closely match those of the full runtime;
|
||||
// the generated methods compute their results based on field values rather
|
||||
// than object identity. (Implementations should not assume that hashcodes
|
||||
// will be consistent across runtimes or versions of the protocol compiler.)
|
||||
optional bool java_generate_equals_and_hash = 20 [default=false];
|
||||
|
||||
// If set true, then the Java2 code generator will generate code that
|
||||
// throws an exception whenever an attempt is made to assign a non-UTF-8
|
||||
// byte sequence to a string field.
|
||||
// Message reflection will do the same.
|
||||
// However, an extension field still accepts non-UTF-8 byte sequences.
|
||||
// This option has no effect on when used with the lite runtime.
|
||||
optional bool java_string_check_utf8 = 27 [default=false];
|
||||
|
||||
|
||||
// Generated classes can be optimized for speed or code size.
|
||||
enum OptimizeMode {
|
||||
SPEED = 1; // Generate complete code for parsing, serialization,
|
||||
// etc.
|
||||
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
|
||||
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
|
||||
}
|
||||
optional OptimizeMode optimize_for = 9 [default=SPEED];
|
||||
|
||||
// Sets the Go package where structs generated from this .proto will be
|
||||
// placed. There is no default.
|
||||
optional string go_package = 11;
|
||||
|
||||
|
||||
|
||||
// Should generic services be generated in each language? "Generic" services
|
||||
// are not specific to any particular RPC system. They are generated by the
|
||||
// main code generators in each language (without additional plugins).
|
||||
// Generic services were the only kind of service generation supported by
|
||||
// early versions of proto2.
|
||||
//
|
||||
// Generic services are now considered deprecated in favor of using plugins
|
||||
// that generate code specific to your particular RPC system. Therefore,
|
||||
// these default to false. Old code which depends on generic services should
|
||||
// explicitly set them to true.
|
||||
optional bool cc_generic_services = 16 [default=false];
|
||||
optional bool java_generic_services = 17 [default=false];
|
||||
optional bool py_generic_services = 18 [default=false];
|
||||
|
||||
// Is this file deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for everything in the file, or it will be completely ignored; in the very
|
||||
// least, this is a formalization for deprecating files.
|
||||
optional bool deprecated = 23 [default=false];
|
||||
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MessageOptions {
|
||||
// Set true to use the old proto1 MessageSet wire format for extensions.
|
||||
// This is provided for backwards-compatibility with the MessageSet wire
|
||||
// format. You should not use this for any other reason: It's less
|
||||
// efficient, has fewer features, and is more complicated.
|
||||
//
|
||||
// The message must be defined exactly as follows:
|
||||
// message Foo {
|
||||
// option message_set_wire_format = true;
|
||||
// extensions 4 to max;
|
||||
// }
|
||||
// Note that the message cannot have any defined fields; MessageSets only
|
||||
// have extensions.
|
||||
//
|
||||
// All extensions of your type must be singular messages; e.g. they cannot
|
||||
// be int32s, enums, or repeated messages.
|
||||
//
|
||||
// Because this is an option, the above two restrictions are not enforced by
|
||||
// the protocol compiler.
|
||||
optional bool message_set_wire_format = 1 [default=false];
|
||||
|
||||
// Disables the generation of the standard "descriptor()" accessor, which can
|
||||
// conflict with a field of the same name. This is meant to make migration
|
||||
// from proto1 easier; new code should avoid fields named "descriptor".
|
||||
optional bool no_standard_descriptor_accessor = 2 [default=false];
|
||||
|
||||
// Is this message deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the message, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating messages.
|
||||
optional bool deprecated = 3 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message FieldOptions {
|
||||
// The ctype option instructs the C++ code generator to use a different
|
||||
// representation of the field than it normally would. See the specific
|
||||
// options below. This option is not yet implemented in the open source
|
||||
// release -- sorry, we'll try to include it in a future version!
|
||||
optional CType ctype = 1 [default = STRING];
|
||||
enum CType {
|
||||
// Default mode.
|
||||
STRING = 0;
|
||||
|
||||
CORD = 1;
|
||||
|
||||
STRING_PIECE = 2;
|
||||
}
|
||||
// The packed option can be enabled for repeated primitive fields to enable
|
||||
// a more efficient representation on the wire. Rather than repeatedly
|
||||
// writing the tag and type for each element, the entire array is encoded as
|
||||
// a single length-delimited blob.
|
||||
optional bool packed = 2;
|
||||
|
||||
|
||||
|
||||
// Should this field be parsed lazily? Lazy applies only to message-type
|
||||
// fields. It means that when the outer message is initially parsed, the
|
||||
// inner message's contents will not be parsed but instead stored in encoded
|
||||
// form. The inner message will actually be parsed when it is first accessed.
|
||||
//
|
||||
// This is only a hint. Implementations are free to choose whether to use
|
||||
// eager or lazy parsing regardless of the value of this option. However,
|
||||
// setting this option true suggests that the protocol author believes that
|
||||
// using lazy parsing on this field is worth the additional bookkeeping
|
||||
// overhead typically needed to implement it.
|
||||
//
|
||||
// This option does not affect the public interface of any generated code;
|
||||
// all method signatures remain the same. Furthermore, thread-safety of the
|
||||
// interface is not affected by this option; const methods remain safe to
|
||||
// call from multiple threads concurrently, while non-const methods continue
|
||||
// to require exclusive access.
|
||||
//
|
||||
//
|
||||
// Note that implementations may choose not to check required fields within
|
||||
// a lazy sub-message. That is, calling IsInitialized() on the outher message
|
||||
// may return true even if the inner message has missing required fields.
|
||||
// This is necessary because otherwise the inner message would have to be
|
||||
// parsed in order to perform the check, defeating the purpose of lazy
|
||||
// parsing. An implementation which chooses not to check required fields
|
||||
// must be consistent about it. That is, for any particular sub-message, the
|
||||
// implementation must either *always* check its required fields, or *never*
|
||||
// check its required fields, regardless of whether or not the message has
|
||||
// been parsed.
|
||||
optional bool lazy = 5 [default=false];
|
||||
|
||||
// Is this field deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for accessors, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating fields.
|
||||
optional bool deprecated = 3 [default=false];
|
||||
|
||||
// EXPERIMENTAL. DO NOT USE.
|
||||
// For "map" fields, the name of the field in the enclosed type that
|
||||
// is the key for this map. For example, suppose we have:
|
||||
// message Item {
|
||||
// required string name = 1;
|
||||
// required string value = 2;
|
||||
// }
|
||||
// message Config {
|
||||
// repeated Item items = 1 [experimental_map_key="name"];
|
||||
// }
|
||||
// In this situation, the map key for Item will be set to "name".
|
||||
// TODO: Fully-implement this, then remove the "experimental_" prefix.
|
||||
optional string experimental_map_key = 9;
|
||||
|
||||
// For Google-internal migration only. Do not use.
|
||||
optional bool weak = 10 [default=false];
|
||||
|
||||
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumOptions {
|
||||
|
||||
// Set this option to true to allow mapping different tag names to the same
|
||||
// value.
|
||||
optional bool allow_alias = 2;
|
||||
|
||||
// Is this enum deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the enum, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating enums.
|
||||
optional bool deprecated = 3 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumValueOptions {
|
||||
// Is this enum value deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the enum value, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating enum values.
|
||||
optional bool deprecated = 1 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message ServiceOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// Is this service deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the service, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating services.
|
||||
optional bool deprecated = 33 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MethodOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// Is this method deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the method, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating methods.
|
||||
optional bool deprecated = 33 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
|
||||
// A message representing a option the parser does not recognize. This only
|
||||
// appears in options protos created by the compiler::Parser class.
|
||||
// DescriptorPool resolves these when building Descriptor objects. Therefore,
|
||||
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
|
||||
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
|
||||
// in them.
|
||||
message UninterpretedOption {
|
||||
// The name of the uninterpreted option. Each string represents a segment in
|
||||
// a dot-separated name. is_extension is true iff a segment represents an
|
||||
// extension (denoted with parentheses in options specs in .proto files).
|
||||
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
|
||||
// "foo.(bar.baz).qux".
|
||||
message NamePart {
|
||||
required string name_part = 1;
|
||||
required bool is_extension = 2;
|
||||
}
|
||||
repeated NamePart name = 2;
|
||||
|
||||
// The value of the uninterpreted option, in whatever type the tokenizer
|
||||
// identified it as during parsing. Exactly one of these should be set.
|
||||
optional string identifier_value = 3;
|
||||
optional uint64 positive_int_value = 4;
|
||||
optional int64 negative_int_value = 5;
|
||||
optional double double_value = 6;
|
||||
optional bytes string_value = 7;
|
||||
optional string aggregate_value = 8;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Optional source code info
|
||||
|
||||
// Encapsulates information about the original source file from which a
|
||||
// FileDescriptorProto was generated.
|
||||
message SourceCodeInfo {
|
||||
// A Location identifies a piece of source code in a .proto file which
|
||||
// corresponds to a particular definition. This information is intended
|
||||
// to be useful to IDEs, code indexers, documentation generators, and similar
|
||||
// tools.
|
||||
//
|
||||
// For example, say we have a file like:
|
||||
// message Foo {
|
||||
// optional string foo = 1;
|
||||
// }
|
||||
// Let's look at just the field definition:
|
||||
// optional string foo = 1;
|
||||
// ^ ^^ ^^ ^ ^^^
|
||||
// a bc de f ghi
|
||||
// We have the following locations:
|
||||
// span path represents
|
||||
// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
|
||||
// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
|
||||
// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
|
||||
// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
|
||||
// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
|
||||
//
|
||||
// Notes:
|
||||
// - A location may refer to a repeated field itself (i.e. not to any
|
||||
// particular index within it). This is used whenever a set of elements are
|
||||
// logically enclosed in a single code segment. For example, an entire
|
||||
// extend block (possibly containing multiple extension definitions) will
|
||||
// have an outer location whose path refers to the "extensions" repeated
|
||||
// field without an index.
|
||||
// - Multiple locations may have the same path. This happens when a single
|
||||
// logical declaration is spread out across multiple places. The most
|
||||
// obvious example is the "extend" block again -- there may be multiple
|
||||
// extend blocks in the same scope, each of which will have the same path.
|
||||
// - A location's span is not always a subset of its parent's span. For
|
||||
// example, the "extendee" of an extension declaration appears at the
|
||||
// beginning of the "extend" block and is shared by all extensions within
|
||||
// the block.
|
||||
// - Just because a location's span is a subset of some other location's span
|
||||
// does not mean that it is a descendent. For example, a "group" defines
|
||||
// both a type and a field in a single declaration. Thus, the locations
|
||||
// corresponding to the type and field and their components will overlap.
|
||||
// - Code which tries to interpret locations should probably be designed to
|
||||
// ignore those that it doesn't understand, as more types of locations could
|
||||
// be recorded in the future.
|
||||
repeated Location location = 1;
|
||||
message Location {
|
||||
// Identifies which part of the FileDescriptorProto was defined at this
|
||||
// location.
|
||||
//
|
||||
// Each element is a field number or an index. They form a path from
|
||||
// the root FileDescriptorProto to the place where the definition. For
|
||||
// example, this path:
|
||||
// [ 4, 3, 2, 7, 1 ]
|
||||
// refers to:
|
||||
// file.message_type(3) // 4, 3
|
||||
// .field(7) // 2, 7
|
||||
// .name() // 1
|
||||
// This is because FileDescriptorProto.message_type has field number 4:
|
||||
// repeated DescriptorProto message_type = 4;
|
||||
// and DescriptorProto.field has field number 2:
|
||||
// repeated FieldDescriptorProto field = 2;
|
||||
// and FieldDescriptorProto.name has field number 1:
|
||||
// optional string name = 1;
|
||||
//
|
||||
// Thus, the above path gives the location of a field name. If we removed
|
||||
// the last element:
|
||||
// [ 4, 3, 2, 7 ]
|
||||
// this path refers to the whole field declaration (from the beginning
|
||||
// of the label to the terminating semicolon).
|
||||
repeated int32 path = 1 [packed=true];
|
||||
|
||||
// Always has exactly three or four elements: start line, start column,
|
||||
// end line (optional, otherwise assumed same as start line), end column.
|
||||
// These are packed into a single field for efficiency. Note that line
|
||||
// and column numbers are zero-based -- typically you will want to add
|
||||
// 1 to each before displaying to a user.
|
||||
repeated int32 span = 2 [packed=true];
|
||||
|
||||
// If this SourceCodeInfo represents a complete declaration, these are any
|
||||
// comments appearing before and after the declaration which appear to be
|
||||
// attached to the declaration.
|
||||
//
|
||||
// A series of line comments appearing on consecutive lines, with no other
|
||||
// tokens appearing on those lines, will be treated as a single comment.
|
||||
//
|
||||
// Only the comment content is provided; comment markers (e.g. //) are
|
||||
// stripped out. For block comments, leading whitespace and an asterisk
|
||||
// will be stripped from the beginning of each line other than the first.
|
||||
// Newlines are included in the output.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// optional int32 foo = 1; // Comment attached to foo.
|
||||
// // Comment attached to bar.
|
||||
// optional int32 bar = 2;
|
||||
//
|
||||
// optional string baz = 3;
|
||||
// // Comment attached to baz.
|
||||
// // Another line attached to baz.
|
||||
//
|
||||
// // Comment attached to qux.
|
||||
// //
|
||||
// // Another line attached to qux.
|
||||
// optional double qux = 4;
|
||||
//
|
||||
// optional string corge = 5;
|
||||
// /* Block comment attached
|
||||
// * to corge. Leading asterisks
|
||||
// * will be removed. */
|
||||
// /* Block comment attached to
|
||||
// * grault. */
|
||||
// optional int32 grault = 6;
|
||||
optional string leading_comments = 3;
|
||||
optional string trailing_comments = 4;
|
||||
}
|
||||
}
|
|
@ -1,543 +0,0 @@
|
|||
// 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/descriptor_database.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
#include <google/protobuf/stubs/map_util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
DescriptorDatabase::~DescriptorDatabase() {}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
|
||||
const FileDescriptorProto& file,
|
||||
Value value) {
|
||||
if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
|
||||
GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must be careful here -- calling file.package() if file.has_package() is
|
||||
// false could access an uninitialized static-storage variable if we are being
|
||||
// run at startup time.
|
||||
string path = file.has_package() ? file.package() : string();
|
||||
if (!path.empty()) path += '.';
|
||||
|
||||
for (int i = 0; i < file.message_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
|
||||
if (!AddNestedExtensions(file.message_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.enum_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.extension_size(); i++) {
|
||||
if (!AddSymbol(path + file.extension(i).name(), value)) return false;
|
||||
if (!AddExtension(file.extension(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.service_size(); i++) {
|
||||
if (!AddSymbol(path + file.service(i).name(), value)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
|
||||
const string& name, Value value) {
|
||||
// We need to make sure not to violate our map invariant.
|
||||
|
||||
// If the symbol name is invalid it could break our lookup algorithm (which
|
||||
// relies on the fact that '.' sorts before all other characters that are
|
||||
// valid in symbol names).
|
||||
if (!ValidateSymbolName(name)) {
|
||||
GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to look up the symbol to make sure a super-symbol doesn't already
|
||||
// exist.
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
if (iter == by_symbol_.end()) {
|
||||
// Apparently the map is currently empty. Just insert and be done with it.
|
||||
by_symbol_.insert(typename map<string, Value>::value_type(name, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSubSymbol(iter->first, name)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, that worked. Now we have to make sure that no symbol in the map is
|
||||
// a sub-symbol of the one we are inserting. The only symbol which could
|
||||
// be so is the first symbol that is greater than the new symbol. Since
|
||||
// |iter| points at the last symbol that is less than or equal, we just have
|
||||
// to increment it.
|
||||
++iter;
|
||||
|
||||
if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, no conflicts.
|
||||
|
||||
// Insert the new symbol using the iterator as a hint, the new entry will
|
||||
// appear immediately before the one the iterator is pointing at.
|
||||
by_symbol_.insert(iter, typename map<string, Value>::value_type(name, value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
|
||||
const DescriptorProto& message_type,
|
||||
Value value) {
|
||||
for (int i = 0; i < message_type.nested_type_size(); i++) {
|
||||
if (!AddNestedExtensions(message_type.nested_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < message_type.extension_size(); i++) {
|
||||
if (!AddExtension(message_type.extension(i), value)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
|
||||
const FieldDescriptorProto& field,
|
||||
Value value) {
|
||||
if (!field.extendee().empty() && field.extendee()[0] == '.') {
|
||||
// The extension is fully-qualified. We can use it as a lookup key in
|
||||
// the by_symbol_ table.
|
||||
if (!InsertIfNotPresent(&by_extension_,
|
||||
make_pair(field.extendee().substr(1),
|
||||
field.number()),
|
||||
value)) {
|
||||
GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
|
||||
"extend " << field.extendee() << " { "
|
||||
<< field.name() << " = " << field.number() << " }";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Not fully-qualified. We can't really do anything here, unfortunately.
|
||||
// We don't consider this an error, though, because the descriptor is
|
||||
// valid.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
|
||||
const string& filename) {
|
||||
return FindWithDefault(by_name_, filename, Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
|
||||
const string& name) {
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ?
|
||||
iter->second : Value();
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
|
||||
const string& containing_type,
|
||||
int field_number) {
|
||||
return FindWithDefault(by_extension_,
|
||||
make_pair(containing_type, field_number),
|
||||
Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
|
||||
const string& containing_type,
|
||||
vector<int>* output) {
|
||||
typename map<pair<string, int>, Value >::const_iterator it =
|
||||
by_extension_.lower_bound(make_pair(containing_type, 0));
|
||||
bool success = false;
|
||||
|
||||
for (; it != by_extension_.end() && it->first.first == containing_type;
|
||||
++it) {
|
||||
output->push_back(it->first.second);
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
typename map<string, Value>::iterator
|
||||
SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
|
||||
const string& name) {
|
||||
// Find the last key in the map which sorts less than or equal to the
|
||||
// symbol name. Since upper_bound() returns the *first* key that sorts
|
||||
// *greater* than the input, we want the element immediately before that.
|
||||
typename map<string, Value>::iterator iter = by_symbol_.upper_bound(name);
|
||||
if (iter != by_symbol_.begin()) --iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
|
||||
const string& sub_symbol, const string& super_symbol) {
|
||||
return sub_symbol == super_symbol ||
|
||||
(HasPrefixString(super_symbol, sub_symbol) &&
|
||||
super_symbol[sub_symbol.size()] == '.');
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
|
||||
const string& name) {
|
||||
for (int i = 0; i < name.size(); i++) {
|
||||
// I don't trust ctype.h due to locales. :(
|
||||
if (name[i] != '.' && name[i] != '_' &&
|
||||
(name[i] < '0' || name[i] > '9') &&
|
||||
(name[i] < 'A' || name[i] > 'Z') &&
|
||||
(name[i] < 'a' || name[i] > 'z')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
|
||||
SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
|
||||
STLDeleteElements(&files_to_delete_);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
|
||||
FileDescriptorProto* new_file = new FileDescriptorProto;
|
||||
new_file->CopyFrom(file);
|
||||
return AddAndOwn(new_file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
|
||||
files_to_delete_.push_back(file);
|
||||
return index_.AddFile(*file, file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
|
||||
bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output) {
|
||||
if (file == NULL) return false;
|
||||
output->CopyFrom(*file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
|
||||
EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
|
||||
for (int i = 0; i < files_to_delete_.size(); i++) {
|
||||
operator delete(files_to_delete_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::Add(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
FileDescriptorProto file;
|
||||
if (file.ParseFromArray(encoded_file_descriptor, size)) {
|
||||
return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
|
||||
} else {
|
||||
GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
|
||||
"EncodedDescriptorDatabase::Add().";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::AddCopy(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
void* copy = operator new(size);
|
||||
memcpy(copy, encoded_file_descriptor, size);
|
||||
files_to_delete_.push_back(copy);
|
||||
return Add(copy, size);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
string* output) {
|
||||
pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
|
||||
if (encoded_file.first == NULL) return false;
|
||||
|
||||
// Optimization: The name should be the first field in the encoded message.
|
||||
// Try to just read it directly.
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
|
||||
encoded_file.second);
|
||||
|
||||
const uint32 kNameTag = internal::WireFormatLite::MakeTag(
|
||||
FileDescriptorProto::kNameFieldNumber,
|
||||
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
if (input.ReadTag() == kNameTag) {
|
||||
// Success!
|
||||
return internal::WireFormatLite::ReadString(&input, output);
|
||||
} else {
|
||||
// Slow path. Parse whole message.
|
||||
FileDescriptorProto file_proto;
|
||||
if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
|
||||
return false;
|
||||
}
|
||||
*output = file_proto.name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindExtension(containing_type, field_number),
|
||||
output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::MaybeParse(
|
||||
pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output) {
|
||||
if (encoded_file.first == NULL) return false;
|
||||
return output->ParseFromArray(encoded_file.first, encoded_file.second);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
|
||||
: pool_(pool) {}
|
||||
DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileByName(filename);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
const FieldDescriptor* extension =
|
||||
pool_.FindExtensionByNumber(extendee, field_number);
|
||||
if (extension == NULL) return false;
|
||||
|
||||
output->Clear();
|
||||
extension->file()->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
vector<const FieldDescriptor*> extensions;
|
||||
pool_.FindAllExtensions(extendee, &extensions);
|
||||
|
||||
for (int i = 0; i < extensions.size(); ++i) {
|
||||
output->push_back(extensions[i]->number());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2) {
|
||||
sources_.push_back(source1);
|
||||
sources_.push_back(source2);
|
||||
}
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
const vector<DescriptorDatabase*>& sources)
|
||||
: sources_(sources) {}
|
||||
MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileByName(filename, output)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingExtension(
|
||||
containing_type, field_number, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
set<int> merged_results;
|
||||
vector<int> results;
|
||||
bool success = false;
|
||||
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
|
||||
copy(results.begin(), results.end(),
|
||||
insert_iterator<set<int> >(merged_results, merged_results.begin()));
|
||||
success = true;
|
||||
}
|
||||
results.clear();
|
||||
}
|
||||
|
||||
copy(merged_results.begin(), merged_results.end(),
|
||||
insert_iterator<vector<int> >(*output, output->end()));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,369 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// Interface for manipulating databases of descriptors.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class DescriptorDatabase;
|
||||
class SimpleDescriptorDatabase;
|
||||
class EncodedDescriptorDatabase;
|
||||
class DescriptorPoolDatabase;
|
||||
class MergedDescriptorDatabase;
|
||||
|
||||
// Abstract interface for a database of descriptors.
|
||||
//
|
||||
// This is useful if you want to create a DescriptorPool which loads
|
||||
// descriptors on-demand from some sort of large database. If the database
|
||||
// is large, it may be inefficient to enumerate every .proto file inside it
|
||||
// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool
|
||||
// can be created which wraps a DescriptorDatabase and only builds particular
|
||||
// descriptors when they are needed.
|
||||
class LIBPROTOBUF_EXPORT DescriptorDatabase {
|
||||
public:
|
||||
inline DescriptorDatabase() {}
|
||||
virtual ~DescriptorDatabase();
|
||||
|
||||
// Find a file by file name. Fills in in *output and returns true if found.
|
||||
// Otherwise, returns false, leaving the contents of *output undefined.
|
||||
virtual bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file that declares the given fully-qualified symbol name.
|
||||
// If found, fills in *output and returns true, otherwise returns false
|
||||
// and leaves *output undefined.
|
||||
virtual bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file which defines an extension extending the given message type
|
||||
// with the given field number. If found, fills in *output and returns true,
|
||||
// otherwise returns false and leaves *output undefined. containing_type
|
||||
// must be a fully-qualified type name.
|
||||
virtual bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Finds the tag numbers used by all known extensions of
|
||||
// extendee_type, and appends them to output in an undefined
|
||||
// order. This method is best-effort: it's not guaranteed that the
|
||||
// database will find all extensions, and it's not guaranteed that
|
||||
// FindFileContainingExtension will return true on all of the found
|
||||
// numbers. Returns true if the search was successful, otherwise
|
||||
// returns false and leaves output unchanged.
|
||||
//
|
||||
// This method has a default implementation that always returns
|
||||
// false.
|
||||
virtual bool FindAllExtensionNumbers(const string& /* extendee_type */,
|
||||
vector<int>* /* output */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase into which you can insert files manually.
|
||||
//
|
||||
// FindFileContainingSymbol() is fully-implemented. When you add a file, its
|
||||
// symbols will be indexed for this purpose. Note that the implementation
|
||||
// may return false positives, but only if it isn't possible for the symbol
|
||||
// to be defined in any other file. In particular, if a file defines a symbol
|
||||
// "Foo", then searching for "Foo.[anything]" will match that file. This way,
|
||||
// the database does not need to aggressively index all children of a symbol.
|
||||
//
|
||||
// FindFileContainingExtension() is mostly-implemented. It works if and only
|
||||
// if the original FieldDescriptorProto defining the extension has a
|
||||
// fully-qualified type name in its "extendee" field (i.e. starts with a '.').
|
||||
// If the extendee is a relative name, SimpleDescriptorDatabase will not
|
||||
// attempt to resolve the type, so it will not know what type the extension is
|
||||
// extending. Therefore, calling FindFileContainingExtension() with the
|
||||
// extension's containing type will never actually find that extension. Note
|
||||
// that this is an unlikely problem, as all FileDescriptorProtos created by the
|
||||
// protocol compiler (as well as ones created by calling
|
||||
// FileDescriptor::CopyTo()) will always use fully-qualified names for all
|
||||
// types. You only need to worry if you are constructing FileDescriptorProtos
|
||||
// yourself, or are calling compiler::Parser directly.
|
||||
class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
SimpleDescriptorDatabase();
|
||||
~SimpleDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database, making a copy. The object
|
||||
// can be deleted after Add() returns. Returns false if the file conflicted
|
||||
// with a file already in the database, in which case an error will have
|
||||
// been written to GOOGLE_LOG(ERROR).
|
||||
bool Add(const FileDescriptorProto& file);
|
||||
|
||||
// Adds the FileDescriptorProto to the database and takes ownership of it.
|
||||
bool AddAndOwn(const FileDescriptorProto* file);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
// So that it can use DescriptorIndex.
|
||||
friend class EncodedDescriptorDatabase;
|
||||
|
||||
// An index mapping file names, symbol names, and extension numbers to
|
||||
// some sort of values.
|
||||
template <typename Value>
|
||||
class DescriptorIndex {
|
||||
public:
|
||||
// Helpers to recursively add particular descriptors and all their contents
|
||||
// to the index.
|
||||
bool AddFile(const FileDescriptorProto& file,
|
||||
Value value);
|
||||
bool AddSymbol(const string& name, Value value);
|
||||
bool AddNestedExtensions(const DescriptorProto& message_type,
|
||||
Value value);
|
||||
bool AddExtension(const FieldDescriptorProto& field,
|
||||
Value value);
|
||||
|
||||
Value FindFile(const string& filename);
|
||||
Value FindSymbol(const string& name);
|
||||
Value FindExtension(const string& containing_type, int field_number);
|
||||
bool FindAllExtensionNumbers(const string& containing_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
map<string, Value> by_name_;
|
||||
map<string, Value> by_symbol_;
|
||||
map<pair<string, int>, Value> by_extension_;
|
||||
|
||||
// Invariant: The by_symbol_ map does not contain any symbols which are
|
||||
// prefixes of other symbols in the map. For example, "foo.bar" is a
|
||||
// prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
|
||||
//
|
||||
// This invariant is important because it means that given a symbol name,
|
||||
// we can find a key in the map which is a prefix of the symbol in O(lg n)
|
||||
// time, and we know that there is at most one such key.
|
||||
//
|
||||
// The prefix lookup algorithm works like so:
|
||||
// 1) Find the last key in the map which is less than or equal to the
|
||||
// search key.
|
||||
// 2) If the found key is a prefix of the search key, then return it.
|
||||
// Otherwise, there is no match.
|
||||
//
|
||||
// I am sure this algorithm has been described elsewhere, but since I
|
||||
// wasn't able to find it quickly I will instead prove that it works
|
||||
// myself. The key to the algorithm is that if a match exists, step (1)
|
||||
// will find it. Proof:
|
||||
// 1) Define the "search key" to be the key we are looking for, the "found
|
||||
// key" to be the key found in step (1), and the "match key" to be the
|
||||
// key which actually matches the serach key (i.e. the key we're trying
|
||||
// to find).
|
||||
// 2) The found key must be less than or equal to the search key by
|
||||
// definition.
|
||||
// 3) The match key must also be less than or equal to the search key
|
||||
// (because it is a prefix).
|
||||
// 4) The match key cannot be greater than the found key, because if it
|
||||
// were, then step (1) of the algorithm would have returned the match
|
||||
// key instead (since it finds the *greatest* key which is less than or
|
||||
// equal to the search key).
|
||||
// 5) Therefore, the found key must be between the match key and the search
|
||||
// key, inclusive.
|
||||
// 6) Since the search key must be a sub-symbol of the match key, if it is
|
||||
// not equal to the match key, then search_key[match_key.size()] must
|
||||
// be '.'.
|
||||
// 7) Since '.' sorts before any other character that is valid in a symbol
|
||||
// name, then if the found key is not equal to the match key, then
|
||||
// found_key[match_key.size()] must also be '.', because any other value
|
||||
// would make it sort after the search key.
|
||||
// 8) Therefore, if the found key is not equal to the match key, then the
|
||||
// found key must be a sub-symbol of the match key. However, this would
|
||||
// contradict our map invariant which says that no symbol in the map is
|
||||
// a sub-symbol of any other.
|
||||
// 9) Therefore, the found key must match the match key.
|
||||
//
|
||||
// The above proof assumes the match key exists. In the case that the
|
||||
// match key does not exist, then step (1) will return some other symbol.
|
||||
// That symbol cannot be a super-symbol of the search key since if it were,
|
||||
// then it would be a match, and we're assuming the match key doesn't exist.
|
||||
// Therefore, step 2 will correctly return no match.
|
||||
|
||||
// Find the last entry in the by_symbol_ map whose key is less than or
|
||||
// equal to the given name.
|
||||
typename map<string, Value>::iterator FindLastLessOrEqual(
|
||||
const string& name);
|
||||
|
||||
// True if either the arguments are equal or super_symbol identifies a
|
||||
// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
|
||||
// "foo.bar.baz", but not a parent of "foo.barbaz").
|
||||
bool IsSubSymbol(const string& sub_symbol, const string& super_symbol);
|
||||
|
||||
// Returns true if and only if all characters in the name are alphanumerics,
|
||||
// underscores, or periods.
|
||||
bool ValidateSymbolName(const string& name);
|
||||
};
|
||||
|
||||
|
||||
DescriptorIndex<const FileDescriptorProto*> index_;
|
||||
vector<const FileDescriptorProto*> files_to_delete_;
|
||||
|
||||
// If file is non-NULL, copy it into *output and return true, otherwise
|
||||
// return false.
|
||||
bool MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
|
||||
};
|
||||
|
||||
// Very similar to SimpleDescriptorDatabase, but stores all the descriptors
|
||||
// as raw bytes and generally tries to use as little memory as possible.
|
||||
//
|
||||
// The same caveats regarding FindFileContainingExtension() apply as with
|
||||
// SimpleDescriptorDatabase.
|
||||
class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
EncodedDescriptorDatabase();
|
||||
~EncodedDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database. The descriptor is provided
|
||||
// in encoded form. The database does not make a copy of the bytes, nor
|
||||
// does it take ownership; it's up to the caller to make sure the bytes
|
||||
// remain valid for the life of the database. Returns false and logs an error
|
||||
// if the bytes are not a valid FileDescriptorProto or if the file conflicted
|
||||
// with a file already in the database.
|
||||
bool Add(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like Add(), but makes a copy of the data, so that the caller does not
|
||||
// need to keep it around.
|
||||
bool AddCopy(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like FindFileContainingSymbol but returns only the name of the file.
|
||||
bool FindNameOfFileContainingSymbol(const string& symbol_name,
|
||||
string* output);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
SimpleDescriptorDatabase::DescriptorIndex<pair<const void*, int> > index_;
|
||||
vector<void*> files_to_delete_;
|
||||
|
||||
// If encoded_file.first is non-NULL, parse the data into *output and return
|
||||
// true, otherwise return false.
|
||||
bool MaybeParse(pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that fetches files from a given pool.
|
||||
class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
DescriptorPoolDatabase(const DescriptorPool& pool);
|
||||
~DescriptorPoolDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool& pool_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that wraps two or more others. It first searches the
|
||||
// first database and, if that fails, tries the second, and so on.
|
||||
class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
// Merge just two databases. The sources remain property of the caller.
|
||||
MergedDescriptorDatabase(DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2);
|
||||
// Merge more than two databases. The sources remain property of the caller.
|
||||
// The vector may be deleted after the constructor returns but the
|
||||
// DescriptorDatabases need to stick around.
|
||||
MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
|
||||
~MergedDescriptorDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
// Merges the results of calling all databases. Returns true iff any
|
||||
// of the databases returned true.
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
|
||||
private:
|
||||
vector<DescriptorDatabase*> sources_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
|
@ -1,764 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// DynamicMessage is implemented by constructing a data structure which
|
||||
// has roughly the same memory layout as a generated message would have.
|
||||
// Then, we use GeneratedMessageReflection to implement our reflection
|
||||
// interface. All the other operations we need to implement (e.g.
|
||||
// parsing, copying, etc.) are already implemented in terms of
|
||||
// Reflection, so the rest is easy.
|
||||
//
|
||||
// The up side of this strategy is that it's very efficient. We don't
|
||||
// need to use hash_maps or generic representations of fields. The
|
||||
// down side is that this is a low-level memory management hack which
|
||||
// can be tricky to get right.
|
||||
//
|
||||
// As mentioned in the header, we only expose a DynamicMessageFactory
|
||||
// publicly, not the DynamicMessage class itself. This is because
|
||||
// GenericMessageReflection wants to have a pointer to a "default"
|
||||
// copy of the class, with all fields initialized to their default
|
||||
// values. We only want to construct one of these per message type,
|
||||
// so DynamicMessageFactory stores a cache of default messages for
|
||||
// each type it sees (each unique Descriptor pointer). The code
|
||||
// refers to the "default" copy of the class as the "prototype".
|
||||
//
|
||||
// Note on memory allocation: This module often calls "operator new()"
|
||||
// to allocate untyped memory, rather than calling something like
|
||||
// "new uint8[]". This is because "operator new()" means "Give me some
|
||||
// space which I can use as I please." while "new uint8[]" means "Give
|
||||
// me an array of 8-bit integers.". In practice, the later may return
|
||||
// a pointer that is not aligned correctly for general use. I believe
|
||||
// Item 8 of "More Effective C++" discusses this in more detail, though
|
||||
// I don't have the book on me right now so I'm not sure.
|
||||
|
||||
#include <algorithm>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ExtensionSet;
|
||||
using internal::GeneratedMessageReflection;
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Some helper tables and functions...
|
||||
|
||||
namespace {
|
||||
|
||||
// Compute the byte size of the in-memory representation of the field.
|
||||
int FieldSpaceUsed(const FieldDescriptor* field) {
|
||||
typedef FieldDescriptor FD; // avoid line wrapping
|
||||
if (field->label() == FD::LABEL_REPEATED) {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(RepeatedField<int32 >);
|
||||
case FD::CPPTYPE_INT64 : return sizeof(RepeatedField<int64 >);
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField<uint32 >);
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField<uint64 >);
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(RepeatedField<double >);
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField<float >);
|
||||
case FD::CPPTYPE_BOOL : return sizeof(RepeatedField<bool >);
|
||||
case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >);
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(RepeatedPtrField<string>);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(int32 );
|
||||
case FD::CPPTYPE_INT64 : return sizeof(int64 );
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(double );
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(float );
|
||||
case FD::CPPTYPE_BOOL : return sizeof(bool );
|
||||
case FD::CPPTYPE_ENUM : return sizeof(int );
|
||||
|
||||
case FD::CPPTYPE_MESSAGE:
|
||||
return sizeof(Message*);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(string*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_LOG(DFATAL) << "Can't get here.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compute the byte size of in-memory representation of the oneof fields
|
||||
// in default oneof instance.
|
||||
int OneofFieldSpaceUsed(const FieldDescriptor* field) {
|
||||
typedef FieldDescriptor FD; // avoid line wrapping
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(int32 );
|
||||
case FD::CPPTYPE_INT64 : return sizeof(int64 );
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(double );
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(float );
|
||||
case FD::CPPTYPE_BOOL : return sizeof(bool );
|
||||
case FD::CPPTYPE_ENUM : return sizeof(int );
|
||||
|
||||
case FD::CPPTYPE_MESSAGE:
|
||||
return sizeof(Message*);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default:
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(string*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
GOOGLE_LOG(DFATAL) << "Can't get here.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int DivideRoundingUp(int i, int j) {
|
||||
return (i + (j - 1)) / j;
|
||||
}
|
||||
|
||||
static const int kSafeAlignment = sizeof(uint64);
|
||||
static const int kMaxOneofUnionSize = sizeof(uint64);
|
||||
|
||||
inline int AlignTo(int offset, int alignment) {
|
||||
return DivideRoundingUp(offset, alignment) * alignment;
|
||||
}
|
||||
|
||||
// Rounds the given byte offset up to the next offset aligned such that any
|
||||
// type may be stored at it.
|
||||
inline int AlignOffset(int offset) {
|
||||
return AlignTo(offset, kSafeAlignment);
|
||||
}
|
||||
|
||||
#define bitsizeof(T) (sizeof(T) * 8)
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class DynamicMessage : public Message {
|
||||
public:
|
||||
struct TypeInfo {
|
||||
int size;
|
||||
int has_bits_offset;
|
||||
int oneof_case_offset;
|
||||
int unknown_fields_offset;
|
||||
int extensions_offset;
|
||||
|
||||
// Not owned by the TypeInfo.
|
||||
DynamicMessageFactory* factory; // The factory that created this object.
|
||||
const DescriptorPool* pool; // The factory's DescriptorPool.
|
||||
const Descriptor* type; // Type of this DynamicMessage.
|
||||
|
||||
// Warning: The order in which the following pointers are defined is
|
||||
// important (the prototype must be deleted *before* the offsets).
|
||||
scoped_array<int> offsets;
|
||||
scoped_ptr<const GeneratedMessageReflection> reflection;
|
||||
// Don't use a scoped_ptr to hold the prototype: the destructor for
|
||||
// DynamicMessage needs to know whether it is the prototype, and does so by
|
||||
// looking back at this field. This would assume details about the
|
||||
// implementation of scoped_ptr.
|
||||
const DynamicMessage* prototype;
|
||||
void* default_oneof_instance;
|
||||
|
||||
TypeInfo() : prototype(NULL), default_oneof_instance(NULL) {}
|
||||
|
||||
~TypeInfo() {
|
||||
delete prototype;
|
||||
operator delete(default_oneof_instance);
|
||||
}
|
||||
};
|
||||
|
||||
DynamicMessage(const TypeInfo* type_info);
|
||||
~DynamicMessage();
|
||||
|
||||
// Called on the prototype after construction to initialize message fields.
|
||||
void CrossLinkPrototypes();
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
Message* New() const;
|
||||
|
||||
int GetCachedSize() const;
|
||||
void SetCachedSize(int size) const;
|
||||
|
||||
Metadata GetMetadata() const;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
|
||||
|
||||
inline bool is_prototype() const {
|
||||
return type_info_->prototype == this ||
|
||||
// If type_info_->prototype is NULL, then we must be constructing
|
||||
// the prototype now, which means we must be the prototype.
|
||||
type_info_->prototype == NULL;
|
||||
}
|
||||
|
||||
inline void* OffsetToPointer(int offset) {
|
||||
return reinterpret_cast<uint8*>(this) + offset;
|
||||
}
|
||||
inline const void* OffsetToPointer(int offset) const {
|
||||
return reinterpret_cast<const uint8*>(this) + offset;
|
||||
}
|
||||
|
||||
const TypeInfo* type_info_;
|
||||
|
||||
// TODO(kenton): Make this an atomic<int> when C++ supports it.
|
||||
mutable int cached_byte_size_;
|
||||
};
|
||||
|
||||
DynamicMessage::DynamicMessage(const TypeInfo* type_info)
|
||||
: type_info_(type_info),
|
||||
cached_byte_size_(0) {
|
||||
// We need to call constructors for various fields manually and set
|
||||
// default values where appropriate. We use placement new to call
|
||||
// constructors. If you haven't heard of placement new, I suggest Googling
|
||||
// it now. We use placement new even for primitive types that don't have
|
||||
// constructors for consistency. (In theory, placement new should be used
|
||||
// any time you are trying to convert untyped memory to typed memory, though
|
||||
// in practice that's not strictly necessary for types that don't have a
|
||||
// constructor.)
|
||||
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
// Initialize oneof cases.
|
||||
for (int i = 0 ; i < descriptor->oneof_decl_count(); ++i) {
|
||||
new(OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32) * i))
|
||||
uint32(0);
|
||||
}
|
||||
|
||||
new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet;
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
if (field->containing_oneof()) {
|
||||
continue;
|
||||
}
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, TYPE) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
if (!field->is_repeated()) { \
|
||||
new(field_ptr) TYPE(field->default_value_##TYPE()); \
|
||||
} else { \
|
||||
new(field_ptr) RepeatedField<TYPE>(); \
|
||||
} \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , int32 );
|
||||
HANDLE_TYPE(INT64 , int64 );
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE(FLOAT , float );
|
||||
HANDLE_TYPE(BOOL , bool );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) int(field->default_value_enum()->number());
|
||||
} else {
|
||||
new(field_ptr) RepeatedField<int>();
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
if (!field->is_repeated()) {
|
||||
if (is_prototype()) {
|
||||
new(field_ptr) const string*(&field->default_value_string());
|
||||
} else {
|
||||
string* default_value =
|
||||
*reinterpret_cast<string* const*>(
|
||||
type_info_->prototype->OffsetToPointer(
|
||||
type_info_->offsets[i]));
|
||||
new(field_ptr) string*(default_value);
|
||||
}
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<string>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) Message*(NULL);
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<Message>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMessage::~DynamicMessage() {
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
reinterpret_cast<UnknownFieldSet*>(
|
||||
OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet();
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
reinterpret_cast<ExtensionSet*>(
|
||||
OffsetToPointer(type_info_->extensions_offset))->~ExtensionSet();
|
||||
}
|
||||
|
||||
// We need to manually run the destructors for repeated fields and strings,
|
||||
// just as we ran their constructors in the the DynamicMessage constructor.
|
||||
// We also need to manually delete oneof fields if it is set and is string
|
||||
// or message.
|
||||
// Additionally, if any singular embedded messages have been allocated, we
|
||||
// need to delete them, UNLESS we are the prototype message of this type,
|
||||
// in which case any embedded messages are other prototypes and shouldn't
|
||||
// be touched.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
if (field->containing_oneof()) {
|
||||
void* field_ptr = OffsetToPointer(
|
||||
type_info_->oneof_case_offset
|
||||
+ sizeof(uint32) * field->containing_oneof()->index());
|
||||
if (*(reinterpret_cast<const uint32*>(field_ptr)) ==
|
||||
field->number()) {
|
||||
field_ptr = OffsetToPointer(type_info_->offsets[
|
||||
descriptor->field_count() + field->containing_oneof()->index()]);
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
switch (field->options().ctype()) {
|
||||
default:
|
||||
case FieldOptions::STRING:
|
||||
delete *reinterpret_cast<string**>(field_ptr);
|
||||
break;
|
||||
}
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
delete *reinterpret_cast<Message**>(field_ptr);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
|
||||
reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
|
||||
->~RepeatedField<LOWERCASE>(); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, int);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
|
||||
->~RepeatedPtrField<string>();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
|
||||
->~RepeatedPtrField<Message>();
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING: {
|
||||
string* ptr = *reinterpret_cast<string**>(field_ptr);
|
||||
if (ptr != &field->default_value_string()) {
|
||||
delete ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (!is_prototype()) {
|
||||
Message* message = *reinterpret_cast<Message**>(field_ptr);
|
||||
if (message != NULL) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMessage::CrossLinkPrototypes() {
|
||||
// This should only be called on the prototype message.
|
||||
GOOGLE_CHECK(is_prototype());
|
||||
|
||||
DynamicMessageFactory* factory = type_info_->factory;
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
// Cross-link default messages.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
if (field->containing_oneof()) {
|
||||
field_ptr = reinterpret_cast<uint8*>(
|
||||
type_info_->default_oneof_instance) + type_info_->offsets[i];
|
||||
}
|
||||
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
!field->is_repeated()) {
|
||||
// For fields with message types, we need to cross-link with the
|
||||
// prototype for the field's type.
|
||||
// For singular fields, the field is just a pointer which should
|
||||
// point to the prototype.
|
||||
*reinterpret_cast<const Message**>(field_ptr) =
|
||||
factory->GetPrototypeNoLock(field->message_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message* DynamicMessage::New() const {
|
||||
void* new_base = operator new(type_info_->size);
|
||||
memset(new_base, 0, type_info_->size);
|
||||
return new(new_base) DynamicMessage(type_info_);
|
||||
}
|
||||
|
||||
int DynamicMessage::GetCachedSize() const {
|
||||
return cached_byte_size_;
|
||||
}
|
||||
|
||||
void DynamicMessage::SetCachedSize(int size) const {
|
||||
// This is theoretically not thread-compatible, but in practice it works
|
||||
// because if multiple threads write this simultaneously, they will be
|
||||
// writing the exact same value.
|
||||
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
|
||||
cached_byte_size_ = size;
|
||||
GOOGLE_SAFE_CONCURRENT_WRITES_END();
|
||||
}
|
||||
|
||||
Metadata DynamicMessage::GetMetadata() const {
|
||||
Metadata metadata;
|
||||
metadata.descriptor = type_info_->type;
|
||||
metadata.reflection = type_info_->reflection.get();
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
struct DynamicMessageFactory::PrototypeMap {
|
||||
typedef hash_map<const Descriptor*, const DynamicMessage::TypeInfo*> Map;
|
||||
Map map_;
|
||||
};
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory()
|
||||
: pool_(NULL), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
|
||||
: pool_(pool), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::~DynamicMessageFactory() {
|
||||
for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
|
||||
iter != prototypes_->map_.end(); ++iter) {
|
||||
DeleteDefaultOneofInstance(iter->second->type,
|
||||
iter->second->offsets.get(),
|
||||
iter->second->default_oneof_instance);
|
||||
delete iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
MutexLock lock(&prototypes_mutex_);
|
||||
return GetPrototypeNoLock(type);
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototypeNoLock(
|
||||
const Descriptor* type) {
|
||||
if (delegate_to_generated_factory_ &&
|
||||
type->file()->pool() == DescriptorPool::generated_pool()) {
|
||||
return MessageFactory::generated_factory()->GetPrototype(type);
|
||||
}
|
||||
|
||||
const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
|
||||
if (*target != NULL) {
|
||||
// Already exists.
|
||||
return (*target)->prototype;
|
||||
}
|
||||
|
||||
DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
|
||||
*target = type_info;
|
||||
|
||||
type_info->type = type;
|
||||
type_info->pool = (pool_ == NULL) ? type->file()->pool() : pool_;
|
||||
type_info->factory = this;
|
||||
|
||||
// We need to construct all the structures passed to
|
||||
// GeneratedMessageReflection's constructor. This includes:
|
||||
// - A block of memory that contains space for all the message's fields.
|
||||
// - An array of integers indicating the byte offset of each field within
|
||||
// this block.
|
||||
// - A big bitfield containing a bit for each field indicating whether
|
||||
// or not that field is set.
|
||||
|
||||
// Compute size and offsets.
|
||||
int* offsets = new int[type->field_count() + type->oneof_decl_count()];
|
||||
type_info->offsets.reset(offsets);
|
||||
|
||||
// Decide all field offsets by packing in order.
|
||||
// We place the DynamicMessage object itself at the beginning of the allocated
|
||||
// space.
|
||||
int size = sizeof(DynamicMessage);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// Next the has_bits, which is an array of uint32s.
|
||||
type_info->has_bits_offset = size;
|
||||
int has_bits_array_size =
|
||||
DivideRoundingUp(type->field_count(), bitsizeof(uint32));
|
||||
size += has_bits_array_size * sizeof(uint32);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// The oneof_case, if any. It is an array of uint32s.
|
||||
if (type->oneof_decl_count() > 0) {
|
||||
type_info->oneof_case_offset = size;
|
||||
size += type->oneof_decl_count() * sizeof(uint32);
|
||||
size = AlignOffset(size);
|
||||
}
|
||||
|
||||
// The ExtensionSet, if any.
|
||||
if (type->extension_range_count() > 0) {
|
||||
type_info->extensions_offset = size;
|
||||
size += sizeof(ExtensionSet);
|
||||
size = AlignOffset(size);
|
||||
} else {
|
||||
// No extensions.
|
||||
type_info->extensions_offset = -1;
|
||||
}
|
||||
|
||||
// All the fields.
|
||||
for (int i = 0; i < type->field_count(); i++) {
|
||||
// Make sure field is aligned to avoid bus errors.
|
||||
// Oneof fields do not use any space.
|
||||
if (!type->field(i)->containing_oneof()) {
|
||||
int field_size = FieldSpaceUsed(type->field(i));
|
||||
size = AlignTo(size, min(kSafeAlignment, field_size));
|
||||
offsets[i] = size;
|
||||
size += field_size;
|
||||
}
|
||||
}
|
||||
|
||||
// The oneofs.
|
||||
for (int i = 0; i < type->oneof_decl_count(); i++) {
|
||||
size = AlignTo(size, kSafeAlignment);
|
||||
offsets[type->field_count() + i] = size;
|
||||
size += kMaxOneofUnionSize;
|
||||
}
|
||||
|
||||
// Add the UnknownFieldSet to the end.
|
||||
size = AlignOffset(size);
|
||||
type_info->unknown_fields_offset = size;
|
||||
size += sizeof(UnknownFieldSet);
|
||||
|
||||
// Align the final size to make sure no clever allocators think that
|
||||
// alignment is not necessary.
|
||||
size = AlignOffset(size);
|
||||
type_info->size = size;
|
||||
|
||||
// Allocate the prototype.
|
||||
void* base = operator new(size);
|
||||
memset(base, 0, size);
|
||||
DynamicMessage* prototype = new(base) DynamicMessage(type_info);
|
||||
type_info->prototype = prototype;
|
||||
|
||||
// Construct the reflection object.
|
||||
if (type->oneof_decl_count() > 0) {
|
||||
// Compute the size of default oneof instance and offsets of default
|
||||
// oneof fields.
|
||||
int oneof_size = 0;
|
||||
for (int i = 0; i < type->oneof_decl_count(); i++) {
|
||||
for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
|
||||
const FieldDescriptor* field = type->oneof_decl(i)->field(j);
|
||||
int field_size = OneofFieldSpaceUsed(field);
|
||||
oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size));
|
||||
offsets[field->index()] = oneof_size;
|
||||
oneof_size += field_size;
|
||||
}
|
||||
}
|
||||
// Construct default oneof instance.
|
||||
type_info->default_oneof_instance = ::operator new(oneof_size);
|
||||
ConstructDefaultOneofInstance(type_info->type,
|
||||
type_info->offsets.get(),
|
||||
type_info->default_oneof_instance);
|
||||
type_info->reflection.reset(
|
||||
new GeneratedMessageReflection(
|
||||
type_info->type,
|
||||
type_info->prototype,
|
||||
type_info->offsets.get(),
|
||||
type_info->has_bits_offset,
|
||||
type_info->unknown_fields_offset,
|
||||
type_info->extensions_offset,
|
||||
type_info->default_oneof_instance,
|
||||
type_info->oneof_case_offset,
|
||||
type_info->pool,
|
||||
this,
|
||||
type_info->size));
|
||||
} else {
|
||||
type_info->reflection.reset(
|
||||
new GeneratedMessageReflection(
|
||||
type_info->type,
|
||||
type_info->prototype,
|
||||
type_info->offsets.get(),
|
||||
type_info->has_bits_offset,
|
||||
type_info->unknown_fields_offset,
|
||||
type_info->extensions_offset,
|
||||
type_info->pool,
|
||||
this,
|
||||
type_info->size));
|
||||
}
|
||||
// Cross link prototypes.
|
||||
prototype->CrossLinkPrototypes();
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
void DynamicMessageFactory::ConstructDefaultOneofInstance(
|
||||
const Descriptor* type,
|
||||
const int offsets[],
|
||||
void* default_oneof_instance) {
|
||||
for (int i = 0; i < type->oneof_decl_count(); i++) {
|
||||
for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
|
||||
const FieldDescriptor* field = type->oneof_decl(i)->field(j);
|
||||
void* field_ptr = reinterpret_cast<uint8*>(
|
||||
default_oneof_instance) + offsets[field->index()];
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, TYPE) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
new(field_ptr) TYPE(field->default_value_##TYPE()); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , int32 );
|
||||
HANDLE_TYPE(INT64 , int64 );
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE(FLOAT , float );
|
||||
HANDLE_TYPE(BOOL , bool );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
new(field_ptr) int(field->default_value_enum()->number());
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default:
|
||||
case FieldOptions::STRING:
|
||||
if (field->has_default_value()) {
|
||||
new(field_ptr) const string*(&field->default_value_string());
|
||||
} else {
|
||||
new(field_ptr) string*(
|
||||
const_cast<string*>(&internal::GetEmptyString()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
new(field_ptr) Message*(NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMessageFactory::DeleteDefaultOneofInstance(
|
||||
const Descriptor* type,
|
||||
const int offsets[],
|
||||
void* default_oneof_instance) {
|
||||
for (int i = 0; i < type->oneof_decl_count(); i++) {
|
||||
for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) {
|
||||
const FieldDescriptor* field = type->oneof_decl(i)->field(j);
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
switch (field->options().ctype()) {
|
||||
default:
|
||||
case FieldOptions::STRING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,148 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines an implementation of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
|
||||
// Constructs implementations of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
//
|
||||
// Sometimes you want to be able to manipulate protocol types that you don't
|
||||
// know about at compile time. It would be nice to be able to construct
|
||||
// a Message object which implements the message type given by any arbitrary
|
||||
// Descriptor. DynamicMessage provides this.
|
||||
//
|
||||
// As it turns out, a DynamicMessage needs to construct extra
|
||||
// information about its type in order to operate. Most of this information
|
||||
// can be shared between all DynamicMessages of the same type. But, caching
|
||||
// this information in some sort of global map would be a bad idea, since
|
||||
// the cached information for a particular descriptor could outlive the
|
||||
// descriptor itself. To avoid this problem, DynamicMessageFactory
|
||||
// encapsulates this "cache". All DynamicMessages of the same type created
|
||||
// from the same factory will share the same support data. Any Descriptors
|
||||
// used with a particular factory must outlive the factory.
|
||||
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
|
||||
public:
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the DescriptorPool in which the extendee is defined.
|
||||
DynamicMessageFactory();
|
||||
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the given DescriptorPool.
|
||||
//
|
||||
// DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the
|
||||
// parser to look for extensions in an alternate pool. However, note that
|
||||
// this is almost never what you want to do. Almost all users should use
|
||||
// the zero-arg constructor.
|
||||
DynamicMessageFactory(const DescriptorPool* pool);
|
||||
|
||||
~DynamicMessageFactory();
|
||||
|
||||
// Call this to tell the DynamicMessageFactory that if it is given a
|
||||
// Descriptor d for which:
|
||||
// d->file()->pool() == DescriptorPool::generated_pool(),
|
||||
// then it should delegate to MessageFactory::generated_factory() instead
|
||||
// of constructing a dynamic implementation of the message. In theory there
|
||||
// is no down side to doing this, so it may become the default in the future.
|
||||
void SetDelegateToGeneratedFactory(bool enable) {
|
||||
delegate_to_generated_factory_ = enable;
|
||||
}
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
|
||||
// Given a Descriptor, constructs the default (prototype) Message of that
|
||||
// type. You can then call that message's New() method to construct a
|
||||
// mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory and will
|
||||
// be destroyed when the factory is destroyed. Also, any objects created
|
||||
// by calling the prototype's New() method share some data with the
|
||||
// prototype, so these must be destroyed before the DynamicMessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the DynamicMessageFactory.
|
||||
//
|
||||
// The method is thread-safe.
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
bool delegate_to_generated_factory_;
|
||||
|
||||
// This struct just contains a hash_map. We can't #include <google/protobuf/stubs/hash.h> from
|
||||
// this header due to hacks needed for hash_map portability in the open source
|
||||
// release. Namely, stubs/hash.h, which defines hash_map portably, is not a
|
||||
// public header (for good reason), but dynamic_message.h is, and public
|
||||
// headers may only #include other public headers.
|
||||
struct PrototypeMap;
|
||||
scoped_ptr<PrototypeMap> prototypes_;
|
||||
mutable Mutex prototypes_mutex_;
|
||||
|
||||
friend class DynamicMessage;
|
||||
const Message* GetPrototypeNoLock(const Descriptor* type);
|
||||
|
||||
// Construct default oneof instance for reflection usage if oneof
|
||||
// is defined.
|
||||
static void ConstructDefaultOneofInstance(const Descriptor* type,
|
||||
const int offsets[],
|
||||
void* default_oneof_instance);
|
||||
// Delete default oneof instance. Called by ~DynamicMessageFactory.
|
||||
static void DeleteDefaultOneofInstance(const Descriptor* type,
|
||||
const int offsets[],
|
||||
void* default_oneof_instance);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
|
@ -1,734 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// Contains methods defined in extension_set.h which cannot be part of the
|
||||
// lite library because they use descriptors or reflection.
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// A FieldSkipper used to store unknown MessageSet fields into UnknownFieldSet.
|
||||
class MessageSetFieldSkipper
|
||||
: public UnknownFieldSetFieldSkipper {
|
||||
public:
|
||||
explicit MessageSetFieldSkipper(UnknownFieldSet* unknown_fields)
|
||||
: UnknownFieldSetFieldSkipper(unknown_fields) {}
|
||||
virtual ~MessageSetFieldSkipper() {}
|
||||
|
||||
virtual bool SkipMessageSetField(io::CodedInputStream* input,
|
||||
int field_number);
|
||||
};
|
||||
bool MessageSetFieldSkipper::SkipMessageSetField(
|
||||
io::CodedInputStream* input, int field_number) {
|
||||
uint32 length;
|
||||
if (!input->ReadVarint32(&length)) return false;
|
||||
if (unknown_fields_ == NULL) {
|
||||
return input->Skip(length);
|
||||
} else {
|
||||
return input->ReadString(
|
||||
unknown_fields_->AddLengthDelimited(field_number), length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Implementation of ExtensionFinder which finds extensions in a given
|
||||
// DescriptorPool, using the given MessageFactory to construct sub-objects.
|
||||
// This class is implemented in extension_set_heavy.cc.
|
||||
class DescriptorPoolExtensionFinder : public ExtensionFinder {
|
||||
public:
|
||||
DescriptorPoolExtensionFinder(const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
const Descriptor* containing_type)
|
||||
: pool_(pool), factory_(factory), containing_type_(containing_type) {}
|
||||
virtual ~DescriptorPoolExtensionFinder() {}
|
||||
|
||||
virtual bool Find(int number, ExtensionInfo* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
MessageFactory* factory_;
|
||||
const Descriptor* containing_type_;
|
||||
};
|
||||
|
||||
void ExtensionSet::AppendToList(const Descriptor* containing_type,
|
||||
const DescriptorPool* pool,
|
||||
vector<const FieldDescriptor*>* output) const {
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
bool has = false;
|
||||
if (iter->second.is_repeated) {
|
||||
has = iter->second.GetSize() > 0;
|
||||
} else {
|
||||
has = !iter->second.is_cleared;
|
||||
}
|
||||
|
||||
if (has) {
|
||||
// TODO(kenton): Looking up each field by number is somewhat unfortunate.
|
||||
// Is there a better way? The problem is that descriptors are lazily-
|
||||
// initialized, so they might not even be constructed until
|
||||
// AppendToList() is called.
|
||||
|
||||
if (iter->second.descriptor == NULL) {
|
||||
output->push_back(pool->FindExtensionByNumber(
|
||||
containing_type, iter->first));
|
||||
} else {
|
||||
output->push_back(iter->second.descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline FieldDescriptor::Type real_type(FieldType type) {
|
||||
GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE);
|
||||
return static_cast<FieldDescriptor::Type>(type);
|
||||
}
|
||||
|
||||
inline FieldDescriptor::CppType cpp_type(FieldType type) {
|
||||
return FieldDescriptor::TypeToCppType(
|
||||
static_cast<FieldDescriptor::Type>(type));
|
||||
}
|
||||
|
||||
inline WireFormatLite::FieldType field_type(FieldType type) {
|
||||
GOOGLE_DCHECK(type > 0 && type <= WireFormatLite::MAX_FIELD_TYPE);
|
||||
return static_cast<WireFormatLite::FieldType>(type);
|
||||
}
|
||||
|
||||
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
|
||||
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
|
||||
: FieldDescriptor::LABEL_OPTIONAL, \
|
||||
FieldDescriptor::LABEL_##LABEL); \
|
||||
GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
|
||||
|
||||
const MessageLite& ExtensionSet::GetMessage(int number,
|
||||
const Descriptor* message_type,
|
||||
MessageFactory* factory) const {
|
||||
map<int, Extension>::const_iterator iter = extensions_.find(number);
|
||||
if (iter == extensions_.end() || iter->second.is_cleared) {
|
||||
// Not present. Return the default value.
|
||||
return *factory->GetPrototype(message_type);
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
|
||||
if (iter->second.is_lazy) {
|
||||
return iter->second.lazymessage_value->GetMessage(
|
||||
*factory->GetPrototype(message_type));
|
||||
} else {
|
||||
return *iter->second.message_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
|
||||
extension->type = descriptor->type();
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = false;
|
||||
extension->is_packed = false;
|
||||
const MessageLite* prototype =
|
||||
factory->GetPrototype(descriptor->message_type());
|
||||
extension->is_lazy = false;
|
||||
extension->message_value = prototype->New();
|
||||
extension->is_cleared = false;
|
||||
return extension->message_value;
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
|
||||
extension->is_cleared = false;
|
||||
if (extension->is_lazy) {
|
||||
return extension->lazymessage_value->MutableMessage(
|
||||
*factory->GetPrototype(descriptor->message_type()));
|
||||
} else {
|
||||
return extension->message_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
map<int, Extension>::iterator iter = extensions_.find(descriptor->number());
|
||||
if (iter == extensions_.end()) {
|
||||
// Not present. Return NULL.
|
||||
return NULL;
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
|
||||
MessageLite* ret = NULL;
|
||||
if (iter->second.is_lazy) {
|
||||
ret = iter->second.lazymessage_value->ReleaseMessage(
|
||||
*factory->GetPrototype(descriptor->message_type()));
|
||||
delete iter->second.lazymessage_value;
|
||||
} else {
|
||||
ret = iter->second.message_value;
|
||||
}
|
||||
extensions_.erase(descriptor->number());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
|
||||
extension->type = descriptor->type();
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = true;
|
||||
extension->repeated_message_value =
|
||||
new RepeatedPtrField<MessageLite>();
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
|
||||
}
|
||||
|
||||
// RepeatedPtrField<Message> does not know how to Add() since it cannot
|
||||
// allocate an abstract object, so we have to be tricky.
|
||||
MessageLite* result = extension->repeated_message_value
|
||||
->AddFromCleared<GenericTypeHandler<MessageLite> >();
|
||||
if (result == NULL) {
|
||||
const MessageLite* prototype;
|
||||
if (extension->repeated_message_value->size() == 0) {
|
||||
prototype = factory->GetPrototype(descriptor->message_type());
|
||||
GOOGLE_CHECK(prototype != NULL);
|
||||
} else {
|
||||
prototype = &extension->repeated_message_value->Get(0);
|
||||
}
|
||||
result = prototype->New();
|
||||
extension->repeated_message_value->AddAllocated(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
|
||||
return reinterpret_cast<const EnumDescriptor*>(arg)
|
||||
->FindValueByNumber(number) != NULL;
|
||||
}
|
||||
|
||||
bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
|
||||
const FieldDescriptor* extension =
|
||||
pool_->FindExtensionByNumber(containing_type_, number);
|
||||
if (extension == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
output->type = extension->type();
|
||||
output->is_repeated = extension->is_repeated();
|
||||
output->is_packed = extension->options().packed();
|
||||
output->descriptor = extension;
|
||||
if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
output->message_prototype =
|
||||
factory_->GetPrototype(extension->message_type());
|
||||
GOOGLE_CHECK(output->message_prototype != NULL)
|
||||
<< "Extension factory's GetPrototype() returned NULL for extension: "
|
||||
<< extension->full_name();
|
||||
} else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
|
||||
output->enum_validity_check.func = ValidateEnumUsingDescriptor;
|
||||
output->enum_validity_check.arg = extension->enum_type();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields) {
|
||||
UnknownFieldSetFieldSkipper skipper(unknown_fields);
|
||||
if (input->GetExtensionPool() == NULL) {
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
} else {
|
||||
DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
|
||||
input->GetExtensionFactory(),
|
||||
containing_type->GetDescriptor());
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields) {
|
||||
MessageSetFieldSkipper skipper(unknown_fields);
|
||||
if (input->GetExtensionPool() == NULL) {
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
} else {
|
||||
DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
|
||||
input->GetExtensionFactory(),
|
||||
containing_type->GetDescriptor());
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
}
|
||||
}
|
||||
|
||||
int ExtensionSet::SpaceUsedExcludingSelf() const {
|
||||
int total_size =
|
||||
extensions_.size() * sizeof(map<int, Extension>::value_type);
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin(),
|
||||
end = extensions_.end();
|
||||
iter != end;
|
||||
++iter) {
|
||||
total_size += iter->second.SpaceUsedExcludingSelf();
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
inline int ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelf(
|
||||
RepeatedPtrFieldBase* field) {
|
||||
return field->SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
|
||||
int total_size = 0;
|
||||
if (is_repeated) {
|
||||
switch (cpp_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE: \
|
||||
total_size += sizeof(*repeated_##LOWERCASE##_value) + \
|
||||
repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE( UINT32, uint32);
|
||||
HANDLE_TYPE( UINT64, uint64);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( DOUBLE, double);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, enum);
|
||||
HANDLE_TYPE( STRING, string);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
// repeated_message_value is actually a RepeatedPtrField<MessageLite>,
|
||||
// but MessageLite has no SpaceUsed(), so we must directly call
|
||||
// RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type
|
||||
// handler.
|
||||
total_size += sizeof(*repeated_message_value) +
|
||||
RepeatedMessage_SpaceUsedExcludingSelf(repeated_message_value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (cpp_type(type)) {
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
total_size += sizeof(*string_value) +
|
||||
StringSpaceUsedExcludingSelf(*string_value);
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
if (is_lazy) {
|
||||
total_size += lazymessage_value->SpaceUsed();
|
||||
} else {
|
||||
total_size += down_cast<Message*>(message_value)->SpaceUsed();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// No extra storage costs for primitive types.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
// The Serialize*ToArray methods are only needed in the heavy library, as
|
||||
// the lite library only generates SerializeWithCachedSizes.
|
||||
uint8* ExtensionSet::SerializeWithCachedSizesToArray(
|
||||
int start_field_number, int end_field_number,
|
||||
uint8* target) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.lower_bound(start_field_number);
|
||||
iter != extensions_.end() && iter->first < end_field_number;
|
||||
++iter) {
|
||||
target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first,
|
||||
target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
|
||||
uint8* target) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
|
||||
target = iter->second.SerializeMessageSetItemWithCachedSizesToArray(
|
||||
iter->first, target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
|
||||
int number, uint8* target) const {
|
||||
if (is_repeated) {
|
||||
if (is_packed) {
|
||||
if (cached_size == 0) return target;
|
||||
|
||||
target = WireFormatLite::WriteTagToArray(number,
|
||||
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
|
||||
target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
|
||||
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
|
||||
target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \
|
||||
repeated_##LOWERCASE##_value->Get(i), target); \
|
||||
} \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32);
|
||||
HANDLE_TYPE( INT64, Int64, int64);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64);
|
||||
HANDLE_TYPE( FLOAT, Float, float);
|
||||
HANDLE_TYPE( DOUBLE, Double, double);
|
||||
HANDLE_TYPE( BOOL, Bool, bool);
|
||||
HANDLE_TYPE( ENUM, Enum, enum);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
case WireFormatLite::TYPE_BYTES:
|
||||
case WireFormatLite::TYPE_GROUP:
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
|
||||
target = WireFormatLite::Write##CAMELCASE##ToArray(number, \
|
||||
repeated_##LOWERCASE##_value->Get(i), target); \
|
||||
} \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32);
|
||||
HANDLE_TYPE( INT64, Int64, int64);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64);
|
||||
HANDLE_TYPE( FLOAT, Float, float);
|
||||
HANDLE_TYPE( DOUBLE, Double, double);
|
||||
HANDLE_TYPE( BOOL, Bool, bool);
|
||||
HANDLE_TYPE( STRING, String, string);
|
||||
HANDLE_TYPE( BYTES, Bytes, string);
|
||||
HANDLE_TYPE( ENUM, Enum, enum);
|
||||
HANDLE_TYPE( GROUP, Group, message);
|
||||
HANDLE_TYPE( MESSAGE, Message, message);
|
||||
#undef HANDLE_TYPE
|
||||
}
|
||||
}
|
||||
} else if (!is_cleared) {
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
target = WireFormatLite::Write##CAMELCASE##ToArray( \
|
||||
number, VALUE, target); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32_value);
|
||||
HANDLE_TYPE( INT64, Int64, int64_value);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32_value);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64_value);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32_value);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64_value);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32_value);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64_value);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
|
||||
HANDLE_TYPE( FLOAT, Float, float_value);
|
||||
HANDLE_TYPE( DOUBLE, Double, double_value);
|
||||
HANDLE_TYPE( BOOL, Bool, bool_value);
|
||||
HANDLE_TYPE( STRING, String, *string_value);
|
||||
HANDLE_TYPE( BYTES, Bytes, *string_value);
|
||||
HANDLE_TYPE( ENUM, Enum, enum_value);
|
||||
HANDLE_TYPE( GROUP, Group, *message_value);
|
||||
#undef HANDLE_TYPE
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
if (is_lazy) {
|
||||
target = lazymessage_value->WriteMessageToArray(number, target);
|
||||
} else {
|
||||
target = WireFormatLite::WriteMessageToArray(
|
||||
number, *message_value, target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but serialize it the normal way.
|
||||
GOOGLE_LOG(WARNING) << "Invalid message set extension.";
|
||||
return SerializeFieldWithCachedSizesToArray(number, target);
|
||||
}
|
||||
|
||||
if (is_cleared) return target;
|
||||
|
||||
// Start group.
|
||||
target = io::CodedOutputStream::WriteTagToArray(
|
||||
WireFormatLite::kMessageSetItemStartTag, target);
|
||||
// Write type ID.
|
||||
target = WireFormatLite::WriteUInt32ToArray(
|
||||
WireFormatLite::kMessageSetTypeIdNumber, number, target);
|
||||
// Write message.
|
||||
if (is_lazy) {
|
||||
target = lazymessage_value->WriteMessageToArray(
|
||||
WireFormatLite::kMessageSetMessageNumber, target);
|
||||
} else {
|
||||
target = WireFormatLite::WriteMessageToArray(
|
||||
WireFormatLite::kMessageSetMessageNumber, *message_value, target);
|
||||
}
|
||||
// End group.
|
||||
target = io::CodedOutputStream::WriteTagToArray(
|
||||
WireFormatLite::kMessageSetItemEndTag, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
bool ExtensionSet::ParseFieldMaybeLazily(
|
||||
int wire_type, int field_number, io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
MessageSetFieldSkipper* field_skipper) {
|
||||
return ParseField(WireFormatLite::MakeTag(
|
||||
field_number, static_cast<WireFormatLite::WireType>(wire_type)),
|
||||
input, extension_finder, field_skipper);
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
MessageSetFieldSkipper* field_skipper) {
|
||||
while (true) {
|
||||
const uint32 tag = input->ReadTag();
|
||||
switch (tag) {
|
||||
case 0:
|
||||
return true;
|
||||
case WireFormatLite::kMessageSetItemStartTag:
|
||||
if (!ParseMessageSetItem(input, extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!ParseField(tag, input, extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
const MessageLite* containing_type) {
|
||||
MessageSetFieldSkipper skipper(NULL);
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
MessageSetFieldSkipper* field_skipper) {
|
||||
// TODO(kenton): It would be nice to share code between this and
|
||||
// WireFormatLite::ParseAndMergeMessageSetItem(), but I think the
|
||||
// differences would be hard to factor out.
|
||||
|
||||
// This method parses a group which should contain two fields:
|
||||
// required int32 type_id = 2;
|
||||
// required data message = 3;
|
||||
|
||||
uint32 last_type_id = 0;
|
||||
|
||||
// If we see message data before the type_id, we'll append it to this so
|
||||
// we can parse it later.
|
||||
string message_data;
|
||||
|
||||
while (true) {
|
||||
const uint32 tag = input->ReadTag();
|
||||
if (tag == 0) return false;
|
||||
|
||||
switch (tag) {
|
||||
case WireFormatLite::kMessageSetTypeIdTag: {
|
||||
uint32 type_id;
|
||||
if (!input->ReadVarint32(&type_id)) return false;
|
||||
last_type_id = type_id;
|
||||
|
||||
if (!message_data.empty()) {
|
||||
// We saw some message data before the type_id. Have to parse it
|
||||
// now.
|
||||
io::CodedInputStream sub_input(
|
||||
reinterpret_cast<const uint8*>(message_data.data()),
|
||||
message_data.size());
|
||||
if (!ParseFieldMaybeLazily(WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
|
||||
last_type_id, &sub_input,
|
||||
extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
message_data.clear();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WireFormatLite::kMessageSetMessageTag: {
|
||||
if (last_type_id == 0) {
|
||||
// We haven't seen a type_id yet. Append this data to message_data.
|
||||
string temp;
|
||||
uint32 length;
|
||||
if (!input->ReadVarint32(&length)) return false;
|
||||
if (!input->ReadString(&temp, length)) return false;
|
||||
io::StringOutputStream output_stream(&message_data);
|
||||
io::CodedOutputStream coded_output(&output_stream);
|
||||
coded_output.WriteVarint32(length);
|
||||
coded_output.WriteString(temp);
|
||||
} else {
|
||||
// Already saw type_id, so we can parse this directly.
|
||||
if (!ParseFieldMaybeLazily(WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
|
||||
last_type_id, input,
|
||||
extension_finder, field_skipper)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WireFormatLite::kMessageSetItemEndTag: {
|
||||
return true;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!field_skipper->SkipField(input, tag)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes(
|
||||
int number,
|
||||
io::CodedOutputStream* output) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but serialize it the normal way.
|
||||
SerializeFieldWithCachedSizes(number, output);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_cleared) return;
|
||||
|
||||
// Start group.
|
||||
output->WriteTag(WireFormatLite::kMessageSetItemStartTag);
|
||||
|
||||
// Write type ID.
|
||||
WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber,
|
||||
number,
|
||||
output);
|
||||
// Write message.
|
||||
if (is_lazy) {
|
||||
lazymessage_value->WriteMessage(
|
||||
WireFormatLite::kMessageSetMessageNumber, output);
|
||||
} else {
|
||||
WireFormatLite::WriteMessageMaybeToArray(
|
||||
WireFormatLite::kMessageSetMessageNumber,
|
||||
*message_value,
|
||||
output);
|
||||
}
|
||||
|
||||
// End group.
|
||||
output->WriteTag(WireFormatLite::kMessageSetItemEndTag);
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but compute the byte size for it the
|
||||
// normal way.
|
||||
return ByteSize(number);
|
||||
}
|
||||
|
||||
if (is_cleared) return 0;
|
||||
|
||||
int our_size = WireFormatLite::kMessageSetItemTagsSize;
|
||||
|
||||
// type_id
|
||||
our_size += io::CodedOutputStream::VarintSize32(number);
|
||||
|
||||
// message
|
||||
int message_size = 0;
|
||||
if (is_lazy) {
|
||||
message_size = lazymessage_value->ByteSize();
|
||||
} else {
|
||||
message_size = message_value->ByteSize();
|
||||
}
|
||||
|
||||
our_size += io::CodedOutputStream::VarintSize32(message_size);
|
||||
our_size += message_size;
|
||||
|
||||
return our_size;
|
||||
}
|
||||
|
||||
void ExtensionSet::SerializeMessageSetWithCachedSizes(
|
||||
io::CodedOutputStream* output) const {
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
|
||||
}
|
||||
}
|
||||
|
||||
int ExtensionSet::MessageSetByteSize() const {
|
||||
int total_size = 0;
|
||||
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
total_size += iter->second.MessageSetItemByteSize(iter->first);
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,91 +0,0 @@
|
|||
// 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)
|
||||
//
|
||||
// This header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
// It provides reflection support for generated enums, and is included in
|
||||
// generated .pb.h files and should have minimal dependencies. The methods are
|
||||
// implemented in generated_message_reflection.cc.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
|
||||
#define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/template_util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class EnumDescriptor;
|
||||
} // namespace protobuf
|
||||
|
||||
namespace protobuf {
|
||||
|
||||
// This type trait can be used to cause templates to only match proto2 enum
|
||||
// types.
|
||||
template <typename T> struct is_proto_enum : ::google::protobuf::internal::false_type {};
|
||||
|
||||
// Returns the EnumDescriptor for enum type E, which must be a
|
||||
// proto-declared enum type. Code generated by the protocol compiler
|
||||
// will include specializations of this template for each enum type declared.
|
||||
template <typename E>
|
||||
const EnumDescriptor* GetEnumDescriptor();
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Helper for EnumType_Parse functions: try to parse the string 'name' as an
|
||||
// enum name of the given type, returning true and filling in value on success,
|
||||
// or returning false and leaving value unchanged on failure.
|
||||
LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
|
||||
const string& name,
|
||||
int* value);
|
||||
|
||||
template<typename EnumType>
|
||||
bool ParseNamedEnum(const EnumDescriptor* descriptor,
|
||||
const string& name,
|
||||
EnumType* value) {
|
||||
int tmp;
|
||||
if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
|
||||
*value = static_cast<EnumType>(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Just a wrapper around printing the name of a value. The main point of this
|
||||
// function is not to be inlined, so that you can do this without including
|
||||
// descriptor.h.
|
||||
LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,504 +0,0 @@
|
|||
// 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 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_GENERATED_MESSAGE_REFLECTION_H__
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
// TODO(jasonh): Remove this once the compiler change to directly include this
|
||||
// is released to components.
|
||||
#include <google/protobuf/generated_enum_reflection.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace upb {
|
||||
namespace google_opensource {
|
||||
class GMR_Handlers;
|
||||
} // namespace google_opensource
|
||||
} // namespace upb
|
||||
|
||||
namespace protobuf {
|
||||
class DescriptorPool;
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
class DefaultEmptyOneof;
|
||||
|
||||
// Defined in this file.
|
||||
class GeneratedMessageReflection;
|
||||
|
||||
// Defined in other files.
|
||||
class ExtensionSet; // extension_set.h
|
||||
|
||||
// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use
|
||||
// by generated code. This class is just a big hack that reduces code
|
||||
// size.
|
||||
//
|
||||
// A GeneratedMessageReflection is an implementation of Reflection
|
||||
// which expects all fields to be backed by simple variables located in
|
||||
// memory. The locations are given using a base pointer and a set of
|
||||
// offsets.
|
||||
//
|
||||
// It is required that the user represents fields of each type in a standard
|
||||
// way, so that GeneratedMessageReflection can cast the void* pointer to
|
||||
// the appropriate type. For primitive fields and string fields, each field
|
||||
// should be represented using the obvious C++ primitive type. Enums and
|
||||
// Messages are different:
|
||||
// - Singular Message fields are stored as a pointer to a Message. These
|
||||
// should start out NULL, except for in the default instance where they
|
||||
// should start out pointing to other default instances.
|
||||
// - Enum fields are stored as an int. This int must always contain
|
||||
// a valid value, such that EnumDescriptor::FindValueByNumber() would
|
||||
// not return NULL.
|
||||
// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields
|
||||
// of whatever type the individual field would be. Strings and
|
||||
// Messages use RepeatedPtrFields while everything else uses
|
||||
// RepeatedFields.
|
||||
class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
|
||||
public:
|
||||
// Constructs a GeneratedMessageReflection.
|
||||
// Parameters:
|
||||
// descriptor: The descriptor for the message type being implemented.
|
||||
// default_instance: The default instance of the message. This is only
|
||||
// used to obtain pointers to default instances of embedded
|
||||
// messages, which GetMessage() will return if the particular
|
||||
// sub-message has not been initialized yet. (Thus, all
|
||||
// embedded message fields *must* have non-NULL pointers
|
||||
// in the default instance.)
|
||||
// offsets: An array of ints giving the byte offsets, relative to
|
||||
// the start of the message object, of each field. These can
|
||||
// be computed at compile time using the
|
||||
// GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro, defined
|
||||
// below.
|
||||
// has_bits_offset: Offset in the message of an array of uint32s of size
|
||||
// descriptor->field_count()/32, rounded up. This is a
|
||||
// bitfield where each bit indicates whether or not the
|
||||
// corresponding field of the message has been initialized.
|
||||
// The bit for field index i is obtained by the expression:
|
||||
// has_bits[i / 32] & (1 << (i % 32))
|
||||
// unknown_fields_offset: Offset in the message of the UnknownFieldSet for
|
||||
// the message.
|
||||
// extensions_offset: Offset in the message of the ExtensionSet for the
|
||||
// message, or -1 if the message type has no extension
|
||||
// ranges.
|
||||
// pool: DescriptorPool to search for extension definitions. Only
|
||||
// used by FindKnownExtensionByName() and
|
||||
// FindKnownExtensionByNumber().
|
||||
// factory: MessageFactory to use to construct extension messages.
|
||||
// object_size: The size of a message object of this type, as measured
|
||||
// by sizeof().
|
||||
GeneratedMessageReflection(const Descriptor* descriptor,
|
||||
const Message* default_instance,
|
||||
const int offsets[],
|
||||
int has_bits_offset,
|
||||
int unknown_fields_offset,
|
||||
int extensions_offset,
|
||||
const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
int object_size);
|
||||
|
||||
// Similar with the construction above. Call this construction if the
|
||||
// message has oneof definition.
|
||||
// Parameters:
|
||||
// offsets: An array of ints giving the byte offsets.
|
||||
// For each oneof field, the offset is relative to the
|
||||
// default_oneof_instance. These can be computed at compile
|
||||
// time using the
|
||||
// PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET() macro.
|
||||
// For each none oneof field, the offset is related to
|
||||
// the start of the message object. These can be computed
|
||||
// at compile time using the
|
||||
// GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro.
|
||||
// Besides offsets for all fields, this array also contains
|
||||
// offsets for oneof unions. The offset of the i-th oneof
|
||||
// union is offsets[descriptor->field_count() + i].
|
||||
// default_oneof_instance: The default instance of the oneofs. It is a
|
||||
// struct holding the default value of all oneof fields
|
||||
// for this message. It is only used to obtain pointers
|
||||
// to default instances of oneof fields, which Get
|
||||
// methods will return if the field is not set.
|
||||
// oneof_case_offset: Offset in the message of an array of uint32s of
|
||||
// size descriptor->oneof_decl_count(). Each uint32
|
||||
// indicates what field is set for each oneof.
|
||||
// other parameters are the same with the construction above.
|
||||
GeneratedMessageReflection(const Descriptor* descriptor,
|
||||
const Message* default_instance,
|
||||
const int offsets[],
|
||||
int has_bits_offset,
|
||||
int unknown_fields_offset,
|
||||
int extensions_offset,
|
||||
const void* default_oneof_instance,
|
||||
int oneof_case_offset,
|
||||
const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
int object_size);
|
||||
~GeneratedMessageReflection();
|
||||
|
||||
// implements Reflection -------------------------------------------
|
||||
|
||||
const UnknownFieldSet& GetUnknownFields(const Message& message) const;
|
||||
UnknownFieldSet* MutableUnknownFields(Message* message) const;
|
||||
|
||||
int SpaceUsed(const Message& message) const;
|
||||
|
||||
bool HasField(const Message& message, const FieldDescriptor* field) const;
|
||||
int FieldSize(const Message& message, const FieldDescriptor* field) const;
|
||||
void ClearField(Message* message, const FieldDescriptor* field) const;
|
||||
bool HasOneof(const Message& message,
|
||||
const OneofDescriptor* oneof_descriptor) const;
|
||||
void ClearOneof(Message* message, const OneofDescriptor* field) const;
|
||||
void RemoveLast(Message* message, const FieldDescriptor* field) const;
|
||||
Message* ReleaseLast(Message* message, const FieldDescriptor* field) const;
|
||||
void Swap(Message* message1, Message* message2) const;
|
||||
void SwapFields(Message* message1, Message* message2,
|
||||
const vector<const FieldDescriptor*>& fields) const;
|
||||
void SwapElements(Message* message, const FieldDescriptor* field,
|
||||
int index1, int index2) const;
|
||||
void ListFields(const Message& message,
|
||||
vector<const FieldDescriptor*>* output) const;
|
||||
|
||||
int32 GetInt32 (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
int64 GetInt64 (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
uint32 GetUInt32(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
uint64 GetUInt64(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
float GetFloat (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
double GetDouble(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
bool GetBool (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
string GetString(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
const string& GetStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
string* scratch) const;
|
||||
const EnumValueDescriptor* GetEnum(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
const Message& GetMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
const FieldDescriptor* GetOneofFieldDescriptor(
|
||||
const Message& message,
|
||||
const OneofDescriptor* oneof_descriptor) const;
|
||||
|
||||
public:
|
||||
void SetInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const;
|
||||
void SetInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const;
|
||||
void SetUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const;
|
||||
void SetUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const;
|
||||
void SetFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const;
|
||||
void SetDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const;
|
||||
void SetBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const;
|
||||
void SetString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const;
|
||||
void SetEnum (Message* message, const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const;
|
||||
Message* MutableMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
void SetAllocatedMessage(Message* message,
|
||||
Message* sub_message,
|
||||
const FieldDescriptor* field) const;
|
||||
Message* ReleaseMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
int32 GetRepeatedInt32 (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
int64 GetRepeatedInt64 (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
uint32 GetRepeatedUInt32(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
uint64 GetRepeatedUInt64(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
float GetRepeatedFloat (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
double GetRepeatedDouble(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
bool GetRepeatedBool (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
string GetRepeatedString(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
const string& GetRepeatedStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index, string* scratch) const;
|
||||
const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
const Message& GetRepeatedMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
|
||||
// Set the value of a field.
|
||||
void SetRepeatedInt32 (Message* message,
|
||||
const FieldDescriptor* field, int index, int32 value) const;
|
||||
void SetRepeatedInt64 (Message* message,
|
||||
const FieldDescriptor* field, int index, int64 value) const;
|
||||
void SetRepeatedUInt32(Message* message,
|
||||
const FieldDescriptor* field, int index, uint32 value) const;
|
||||
void SetRepeatedUInt64(Message* message,
|
||||
const FieldDescriptor* field, int index, uint64 value) const;
|
||||
void SetRepeatedFloat (Message* message,
|
||||
const FieldDescriptor* field, int index, float value) const;
|
||||
void SetRepeatedDouble(Message* message,
|
||||
const FieldDescriptor* field, int index, double value) const;
|
||||
void SetRepeatedBool (Message* message,
|
||||
const FieldDescriptor* field, int index, bool value) const;
|
||||
void SetRepeatedString(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
const string& value) const;
|
||||
void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
|
||||
int index, const EnumValueDescriptor* value) const;
|
||||
// Get a mutable pointer to a field with a message type.
|
||||
Message* MutableRepeatedMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
|
||||
void AddInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const;
|
||||
void AddInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const;
|
||||
void AddUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const;
|
||||
void AddUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const;
|
||||
void AddFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const;
|
||||
void AddDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const;
|
||||
void AddBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const;
|
||||
void AddString(Message* message,
|
||||
const FieldDescriptor* field, const string& value) const;
|
||||
void AddEnum(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const;
|
||||
Message* AddMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
|
||||
const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
|
||||
|
||||
protected:
|
||||
virtual void* MutableRawRepeatedField(
|
||||
Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
|
||||
int ctype, const Descriptor* desc) const;
|
||||
|
||||
private:
|
||||
friend class GeneratedMessage;
|
||||
|
||||
// To parse directly into a proto2 generated class, the class GMR_Handlers
|
||||
// needs access to member offsets and hasbits.
|
||||
friend class LIBPROTOBUF_EXPORT upb::google_opensource::GMR_Handlers;
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
const Message* default_instance_;
|
||||
const void* default_oneof_instance_;
|
||||
const int* offsets_;
|
||||
|
||||
int has_bits_offset_;
|
||||
int oneof_case_offset_;
|
||||
int unknown_fields_offset_;
|
||||
int extensions_offset_;
|
||||
int object_size_;
|
||||
|
||||
const DescriptorPool* descriptor_pool_;
|
||||
MessageFactory* message_factory_;
|
||||
|
||||
template <typename Type>
|
||||
inline const Type& GetRaw(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableRaw(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& DefaultRaw(const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& DefaultOneofRaw(const FieldDescriptor* field) const;
|
||||
|
||||
inline const uint32* GetHasBits(const Message& message) const;
|
||||
inline uint32* MutableHasBits(Message* message) const;
|
||||
inline uint32 GetOneofCase(
|
||||
const Message& message,
|
||||
const OneofDescriptor* oneof_descriptor) const;
|
||||
inline uint32* MutableOneofCase(
|
||||
Message* message,
|
||||
const OneofDescriptor* oneof_descriptor) const;
|
||||
inline const ExtensionSet& GetExtensionSet(const Message& message) const;
|
||||
inline ExtensionSet* MutableExtensionSet(Message* message) const;
|
||||
|
||||
inline bool HasBit(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void SetBit(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void ClearBit(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void SwapBit(Message* message1,
|
||||
Message* message2,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
// This function only swaps the field. Should swap corresponding has_bit
|
||||
// before or after using this function.
|
||||
void SwapField(Message* message1,
|
||||
Message* message2,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
void SwapOneofField(Message* message1,
|
||||
Message* message2,
|
||||
const OneofDescriptor* oneof_descriptor) const;
|
||||
|
||||
inline bool HasOneofField(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void SetOneofCase(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void ClearOneofField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
template <typename Type>
|
||||
inline const Type& GetField(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline void SetField(Message* message,
|
||||
const FieldDescriptor* field, const Type& value) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& GetRepeatedField(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline const Type& GetRepeatedPtrField(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline void SetRepeatedField(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
Type value) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableRepeatedField(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline void AddField(Message* message,
|
||||
const FieldDescriptor* field, const Type& value) const;
|
||||
template <typename Type>
|
||||
inline Type* AddField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
int GetExtensionNumberOrDie(const Descriptor* type) const;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
|
||||
};
|
||||
|
||||
// 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.
|
||||
//
|
||||
// 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<int>( \
|
||||
reinterpret_cast<const char*>( \
|
||||
&reinterpret_cast<const TYPE*>(16)->FIELD) - \
|
||||
reinterpret_cast<const char*>(16))
|
||||
|
||||
#define PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ONEOF, FIELD) \
|
||||
static_cast<int>( \
|
||||
reinterpret_cast<const char*>(&(ONEOF->FIELD)) \
|
||||
- reinterpret_cast<const char*>(ONEOF))
|
||||
|
||||
// There are some places in proto2 where dynamic_cast would be useful as an
|
||||
// optimization. For example, take Message::MergeFrom(const Message& other).
|
||||
// For a given generated message FooMessage, we generate these two methods:
|
||||
// void MergeFrom(const FooMessage& other);
|
||||
// void MergeFrom(const Message& other);
|
||||
// The former method can be implemented directly in terms of FooMessage's
|
||||
// inline accessors, but the latter method must work with the reflection
|
||||
// interface. However, if the parameter to the latter method is actually of
|
||||
// type FooMessage, then we'd like to be able to just call the other method
|
||||
// as an optimization. So, we use dynamic_cast to check this.
|
||||
//
|
||||
// That said, dynamic_cast requires RTTI, which many people like to disable
|
||||
// for performance and code size reasons. When RTTI is not available, we
|
||||
// still need to produce correct results. So, in this case we have to fall
|
||||
// back to using reflection, which is what we would have done anyway if the
|
||||
// objects were not of the exact same class.
|
||||
//
|
||||
// dynamic_cast_if_available() implements this logic. If RTTI is
|
||||
// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns
|
||||
// NULL.
|
||||
//
|
||||
// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI.
|
||||
// On MSVC, this should be detected automatically.
|
||||
template<typename To, typename From>
|
||||
inline To dynamic_cast_if_available(From from) {
|
||||
#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
|
||||
return NULL;
|
||||
#else
|
||||
return dynamic_cast<To>(from);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
|
@ -1,113 +0,0 @@
|
|||
// 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 <string>
|
||||
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
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
|
||||
|
||||
|
||||
// Constants for special floating point values.
|
||||
LIBPROTOBUF_EXPORT double Infinity();
|
||||
LIBPROTOBUF_EXPORT double NaN();
|
||||
|
||||
// TODO(jieluo): Change to template. We have tried to use template,
|
||||
// but it causes net/rpc/python:rpcutil_test fail (the empty string will
|
||||
// init twice). It may related to swig. Change to template after we
|
||||
// found the solution.
|
||||
|
||||
// Default empty string object. Don't use the pointer directly. Instead, call
|
||||
// GetEmptyString() to get the reference.
|
||||
LIBPROTOBUF_EXPORT extern const ::std::string* empty_string_;
|
||||
LIBPROTOBUF_EXPORT extern ProtobufOnceType empty_string_once_init_;
|
||||
LIBPROTOBUF_EXPORT void InitEmptyString();
|
||||
|
||||
|
||||
LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyStringAlreadyInited() {
|
||||
assert(empty_string_ != NULL);
|
||||
return *empty_string_;
|
||||
}
|
||||
LIBPROTOBUF_EXPORT inline const ::std::string& GetEmptyString() {
|
||||
::google::protobuf::GoogleOnceInit(&empty_string_once_init_, &InitEmptyString);
|
||||
return GetEmptyStringAlreadyInited();
|
||||
}
|
||||
|
||||
// Defined in generated_message_reflection.cc -- not actually part of the lite
|
||||
// library.
|
||||
//
|
||||
// TODO(jasonh): The various callers get this declaration from a variety of
|
||||
// places: probably in most cases repeated_field.h. Clean these up so they all
|
||||
// get the declaration from this file.
|
||||
LIBPROTOBUF_EXPORT int StringSpaceUsedExcludingSelf(const string& str);
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
|
@ -1,325 +0,0 @@
|
|||
// 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: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the implementation of classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
|
||||
|
||||
#if HAVE_ZLIB
|
||||
#include <google/protobuf/io/gzip_stream.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
static const int kDefaultBufferSize = 65536;
|
||||
|
||||
GzipInputStream::GzipInputStream(
|
||||
ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
|
||||
: format_(format), sub_stream_(sub_stream), zerror_(Z_OK) {
|
||||
zcontext_.zalloc = Z_NULL;
|
||||
zcontext_.zfree = Z_NULL;
|
||||
zcontext_.opaque = Z_NULL;
|
||||
zcontext_.total_out = 0;
|
||||
zcontext_.next_in = NULL;
|
||||
zcontext_.avail_in = 0;
|
||||
zcontext_.total_in = 0;
|
||||
zcontext_.msg = NULL;
|
||||
if (buffer_size == -1) {
|
||||
output_buffer_length_ = kDefaultBufferSize;
|
||||
} else {
|
||||
output_buffer_length_ = buffer_size;
|
||||
}
|
||||
output_buffer_ = operator new(output_buffer_length_);
|
||||
GOOGLE_CHECK(output_buffer_ != NULL);
|
||||
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
|
||||
zcontext_.avail_out = output_buffer_length_;
|
||||
output_position_ = output_buffer_;
|
||||
}
|
||||
GzipInputStream::~GzipInputStream() {
|
||||
operator delete(output_buffer_);
|
||||
zerror_ = inflateEnd(&zcontext_);
|
||||
}
|
||||
|
||||
static inline int internalInflateInit2(
|
||||
z_stream* zcontext, GzipInputStream::Format format) {
|
||||
int windowBitsFormat = 0;
|
||||
switch (format) {
|
||||
case GzipInputStream::GZIP: windowBitsFormat = 16; break;
|
||||
case GzipInputStream::AUTO: windowBitsFormat = 32; break;
|
||||
case GzipInputStream::ZLIB: windowBitsFormat = 0; break;
|
||||
}
|
||||
return inflateInit2(zcontext, /* windowBits */15 | windowBitsFormat);
|
||||
}
|
||||
|
||||
int GzipInputStream::Inflate(int flush) {
|
||||
if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
|
||||
// previous inflate filled output buffer. don't change input params yet.
|
||||
} else if (zcontext_.avail_in == 0) {
|
||||
const void* in;
|
||||
int in_size;
|
||||
bool first = zcontext_.next_in == NULL;
|
||||
bool ok = sub_stream_->Next(&in, &in_size);
|
||||
if (!ok) {
|
||||
zcontext_.next_out = NULL;
|
||||
zcontext_.avail_out = 0;
|
||||
return Z_STREAM_END;
|
||||
}
|
||||
zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
|
||||
zcontext_.avail_in = in_size;
|
||||
if (first) {
|
||||
int error = internalInflateInit2(&zcontext_, format_);
|
||||
if (error != Z_OK) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
|
||||
zcontext_.avail_out = output_buffer_length_;
|
||||
output_position_ = output_buffer_;
|
||||
int error = inflate(&zcontext_, flush);
|
||||
return error;
|
||||
}
|
||||
|
||||
void GzipInputStream::DoNextOutput(const void** data, int* size) {
|
||||
*data = output_position_;
|
||||
*size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
|
||||
output_position_ = zcontext_.next_out;
|
||||
}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool GzipInputStream::Next(const void** data, int* size) {
|
||||
bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|
||||
|| (zerror_ == Z_BUF_ERROR);
|
||||
if ((!ok) || (zcontext_.next_out == NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (zcontext_.next_out != output_position_) {
|
||||
DoNextOutput(data, size);
|
||||
return true;
|
||||
}
|
||||
if (zerror_ == Z_STREAM_END) {
|
||||
if (zcontext_.next_out != NULL) {
|
||||
// sub_stream_ may have concatenated streams to follow
|
||||
zerror_ = inflateEnd(&zcontext_);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
zerror_ = internalInflateInit2(&zcontext_, format_);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
*data = NULL;
|
||||
*size = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
zerror_ = Inflate(Z_NO_FLUSH);
|
||||
if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
|
||||
// The underlying stream's Next returned false inside Inflate.
|
||||
return false;
|
||||
}
|
||||
ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|
||||
|| (zerror_ == Z_BUF_ERROR);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
DoNextOutput(data, size);
|
||||
return true;
|
||||
}
|
||||
void GzipInputStream::BackUp(int count) {
|
||||
output_position_ = reinterpret_cast<void*>(
|
||||
reinterpret_cast<uintptr_t>(output_position_) - count);
|
||||
}
|
||||
bool GzipInputStream::Skip(int count) {
|
||||
const void* data;
|
||||
int size;
|
||||
bool ok = Next(&data, &size);
|
||||
while (ok && (size < count)) {
|
||||
count -= size;
|
||||
ok = Next(&data, &size);
|
||||
}
|
||||
if (size > count) {
|
||||
BackUp(size - count);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
int64 GzipInputStream::ByteCount() const {
|
||||
return zcontext_.total_out +
|
||||
(((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
GzipOutputStream::Options::Options()
|
||||
: format(GZIP),
|
||||
buffer_size(kDefaultBufferSize),
|
||||
compression_level(Z_DEFAULT_COMPRESSION),
|
||||
compression_strategy(Z_DEFAULT_STRATEGY) {}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
|
||||
Init(sub_stream, Options());
|
||||
}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options) {
|
||||
Init(sub_stream, options);
|
||||
}
|
||||
|
||||
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options) {
|
||||
sub_stream_ = sub_stream;
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
|
||||
input_buffer_length_ = options.buffer_size;
|
||||
input_buffer_ = operator new(input_buffer_length_);
|
||||
GOOGLE_CHECK(input_buffer_ != NULL);
|
||||
|
||||
zcontext_.zalloc = Z_NULL;
|
||||
zcontext_.zfree = Z_NULL;
|
||||
zcontext_.opaque = Z_NULL;
|
||||
zcontext_.next_out = NULL;
|
||||
zcontext_.avail_out = 0;
|
||||
zcontext_.total_out = 0;
|
||||
zcontext_.next_in = NULL;
|
||||
zcontext_.avail_in = 0;
|
||||
zcontext_.total_in = 0;
|
||||
zcontext_.msg = NULL;
|
||||
// default to GZIP format
|
||||
int windowBitsFormat = 16;
|
||||
if (options.format == ZLIB) {
|
||||
windowBitsFormat = 0;
|
||||
}
|
||||
zerror_ = deflateInit2(
|
||||
&zcontext_,
|
||||
options.compression_level,
|
||||
Z_DEFLATED,
|
||||
/* windowBits */15 | windowBitsFormat,
|
||||
/* memLevel (default) */8,
|
||||
options.compression_strategy);
|
||||
}
|
||||
|
||||
GzipOutputStream::~GzipOutputStream() {
|
||||
Close();
|
||||
if (input_buffer_ != NULL) {
|
||||
operator delete(input_buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
// private
|
||||
int GzipOutputStream::Deflate(int flush) {
|
||||
int error = Z_OK;
|
||||
do {
|
||||
if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
|
||||
bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
|
||||
if (!ok) {
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
return Z_BUF_ERROR;
|
||||
}
|
||||
GOOGLE_CHECK_GT(sub_data_size_, 0);
|
||||
zcontext_.next_out = static_cast<Bytef*>(sub_data_);
|
||||
zcontext_.avail_out = sub_data_size_;
|
||||
}
|
||||
error = deflate(&zcontext_, flush);
|
||||
} while (error == Z_OK && zcontext_.avail_out == 0);
|
||||
if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) {
|
||||
// Notify lower layer of data.
|
||||
sub_stream_->BackUp(zcontext_.avail_out);
|
||||
// We don't own the buffer anymore.
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool GzipOutputStream::Next(void** data, int* size) {
|
||||
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
if (zcontext_.avail_in != 0) {
|
||||
zerror_ = Deflate(Z_NO_FLUSH);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (zcontext_.avail_in == 0) {
|
||||
// all input was consumed. reset the buffer.
|
||||
zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
|
||||
zcontext_.avail_in = input_buffer_length_;
|
||||
*data = input_buffer_;
|
||||
*size = input_buffer_length_;
|
||||
} else {
|
||||
// The loop in Deflate should consume all avail_in
|
||||
GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void GzipOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(zcontext_.avail_in, count);
|
||||
zcontext_.avail_in -= count;
|
||||
}
|
||||
int64 GzipOutputStream::ByteCount() const {
|
||||
return zcontext_.total_in + zcontext_.avail_in;
|
||||
}
|
||||
|
||||
bool GzipOutputStream::Flush() {
|
||||
zerror_ = Deflate(Z_FULL_FLUSH);
|
||||
// Return true if the flush succeeded or if it was a no-op.
|
||||
return (zerror_ == Z_OK) ||
|
||||
(zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
|
||||
zcontext_.avail_out != 0);
|
||||
}
|
||||
|
||||
bool GzipOutputStream::Close() {
|
||||
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
zerror_ = Deflate(Z_FINISH);
|
||||
} while (zerror_ == Z_OK);
|
||||
zerror_ = deflateEnd(&zcontext_);
|
||||
bool ok = zerror_ == Z_OK;
|
||||
zerror_ = Z_STREAM_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // HAVE_ZLIB
|
|
@ -1,209 +0,0 @@
|
|||
// 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: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the definition for classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
//
|
||||
// GzipInputStream decompresses data from an underlying
|
||||
// ZeroCopyInputStream and provides the decompressed data as a
|
||||
// ZeroCopyInputStream.
|
||||
//
|
||||
// GzipOutputStream is an ZeroCopyOutputStream that compresses data to
|
||||
// an underlying ZeroCopyOutputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
||||
#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// A ZeroCopyInputStream that reads compressed data through zlib
|
||||
class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Format key for constructor
|
||||
enum Format {
|
||||
// zlib will autodetect gzip header or deflate stream
|
||||
AUTO = 0,
|
||||
|
||||
// GZIP streams have some extra header data for file attributes.
|
||||
GZIP = 1,
|
||||
|
||||
// Simpler zlib stream format.
|
||||
ZLIB = 2,
|
||||
};
|
||||
|
||||
// buffer_size and format may be -1 for default of 64kB and GZIP format
|
||||
explicit GzipInputStream(
|
||||
ZeroCopyInputStream* sub_stream,
|
||||
Format format = AUTO,
|
||||
int buffer_size = -1);
|
||||
virtual ~GzipInputStream();
|
||||
|
||||
// Return last error message or NULL if no error.
|
||||
inline const char* ZlibErrorMessage() const {
|
||||
return zcontext_.msg;
|
||||
}
|
||||
inline int ZlibErrorCode() const {
|
||||
return zerror_;
|
||||
}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
Format format_;
|
||||
|
||||
ZeroCopyInputStream* sub_stream_;
|
||||
|
||||
z_stream zcontext_;
|
||||
int zerror_;
|
||||
|
||||
void* output_buffer_;
|
||||
void* output_position_;
|
||||
size_t output_buffer_length_;
|
||||
|
||||
int Inflate(int flush);
|
||||
void DoNextOutput(const void** data, int* size);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
|
||||
};
|
||||
|
||||
|
||||
class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Format key for constructor
|
||||
enum Format {
|
||||
// GZIP streams have some extra header data for file attributes.
|
||||
GZIP = 1,
|
||||
|
||||
// Simpler zlib stream format.
|
||||
ZLIB = 2,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
// Defaults to GZIP.
|
||||
Format format;
|
||||
|
||||
// What size buffer to use internally. Defaults to 64kB.
|
||||
int buffer_size;
|
||||
|
||||
// A number between 0 and 9, where 0 is no compression and 9 is best
|
||||
// compression. Defaults to Z_DEFAULT_COMPRESSION (see zlib.h).
|
||||
int compression_level;
|
||||
|
||||
// Defaults to Z_DEFAULT_STRATEGY. Can also be set to Z_FILTERED,
|
||||
// Z_HUFFMAN_ONLY, or Z_RLE. See the documentation for deflateInit2 in
|
||||
// zlib.h for definitions of these constants.
|
||||
int compression_strategy;
|
||||
|
||||
Options(); // Initializes with default values.
|
||||
};
|
||||
|
||||
// Create a GzipOutputStream with default options.
|
||||
explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream);
|
||||
|
||||
// Create a GzipOutputStream with the given options.
|
||||
GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options);
|
||||
|
||||
virtual ~GzipOutputStream();
|
||||
|
||||
// Return last error message or NULL if no error.
|
||||
inline const char* ZlibErrorMessage() const {
|
||||
return zcontext_.msg;
|
||||
}
|
||||
inline int ZlibErrorCode() const {
|
||||
return zerror_;
|
||||
}
|
||||
|
||||
// Flushes data written so far to zipped data in the underlying stream.
|
||||
// It is the caller's responsibility to flush the underlying stream if
|
||||
// necessary.
|
||||
// Compression may be less efficient stopping and starting around flushes.
|
||||
// Returns true if no error.
|
||||
//
|
||||
// Please ensure that block size is > 6. Here is an excerpt from the zlib
|
||||
// doc that explains why:
|
||||
//
|
||||
// In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out
|
||||
// is greater than six to avoid repeated flush markers due to
|
||||
// avail_out == 0 on return.
|
||||
bool Flush();
|
||||
|
||||
// Writes out all data and closes the gzip stream.
|
||||
// It is the caller's responsibility to close the underlying stream if
|
||||
// necessary.
|
||||
// Returns true if no error.
|
||||
bool Close();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
ZeroCopyOutputStream* sub_stream_;
|
||||
// Result from calling Next() on sub_stream_
|
||||
void* sub_data_;
|
||||
int sub_data_size_;
|
||||
|
||||
z_stream zcontext_;
|
||||
int zerror_;
|
||||
void* input_buffer_;
|
||||
size_t input_buffer_length_;
|
||||
|
||||
// Shared constructor code.
|
||||
void Init(ZeroCopyOutputStream* sub_stream, const Options& options);
|
||||
|
||||
// Do some compression.
|
||||
// Takes zlib flush mode.
|
||||
// Returns zlib error code.
|
||||
int Deflate(int flush);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
|
@ -1,198 +0,0 @@
|
|||
// 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/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
|
||||
: variable_delimiter_(variable_delimiter),
|
||||
output_(output),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
at_start_of_line_(true),
|
||||
failed_(false) {
|
||||
}
|
||||
|
||||
Printer::~Printer() {
|
||||
// Only BackUp() if we have called Next() at least once and never failed.
|
||||
if (buffer_size_ > 0 && !failed_) {
|
||||
output_->BackUp(buffer_size_);
|
||||
}
|
||||
}
|
||||
|
||||
void Printer::Print(const map<string, string>& variables, const char* text) {
|
||||
int size = strlen(text);
|
||||
int pos = 0; // The number of bytes we've written so far.
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (text[i] == '\n') {
|
||||
// Saw newline. If there is more text, we may need to insert an indent
|
||||
// here. So, write what we have so far, including the '\n'.
|
||||
WriteRaw(text + pos, i - pos + 1);
|
||||
pos = i + 1;
|
||||
|
||||
// Setting this true will cause the next WriteRaw() to insert an indent
|
||||
// first.
|
||||
at_start_of_line_ = true;
|
||||
|
||||
} else if (text[i] == variable_delimiter_) {
|
||||
// Saw the start of a variable name.
|
||||
|
||||
// Write what we have so far.
|
||||
WriteRaw(text + pos, i - pos);
|
||||
pos = i + 1;
|
||||
|
||||
// Find closing delimiter.
|
||||
const char* end = strchr(text + pos, variable_delimiter_);
|
||||
if (end == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
|
||||
end = text + pos;
|
||||
}
|
||||
int endpos = end - text;
|
||||
|
||||
string varname(text + pos, endpos - pos);
|
||||
if (varname.empty()) {
|
||||
// Two delimiters in a row reduce to a literal delimiter character.
|
||||
WriteRaw(&variable_delimiter_, 1);
|
||||
} else {
|
||||
// Replace with the variable's value.
|
||||
map<string, string>::const_iterator iter = variables.find(varname);
|
||||
if (iter == variables.end()) {
|
||||
GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
|
||||
} else {
|
||||
WriteRaw(iter->second.data(), iter->second.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Advance past this variable.
|
||||
i = endpos;
|
||||
pos = endpos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the rest.
|
||||
WriteRaw(text + pos, size - pos);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text) {
|
||||
static map<string, string> empty;
|
||||
Print(empty, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable, const string& value) {
|
||||
map<string, string> vars;
|
||||
vars[variable] = value;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2) {
|
||||
map<string, string> vars;
|
||||
vars[variable1] = value1;
|
||||
vars[variable2] = value2;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2,
|
||||
const char* variable3, const string& value3) {
|
||||
map<string, string> vars;
|
||||
vars[variable1] = value1;
|
||||
vars[variable2] = value2;
|
||||
vars[variable3] = value3;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Indent() {
|
||||
indent_ += " ";
|
||||
}
|
||||
|
||||
void Printer::Outdent() {
|
||||
if (indent_.empty()) {
|
||||
GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
|
||||
return;
|
||||
}
|
||||
|
||||
indent_.resize(indent_.size() - 2);
|
||||
}
|
||||
|
||||
void Printer::PrintRaw(const string& data) {
|
||||
WriteRaw(data.data(), data.size());
|
||||
}
|
||||
|
||||
void Printer::PrintRaw(const char* data) {
|
||||
if (failed_) return;
|
||||
WriteRaw(data, strlen(data));
|
||||
}
|
||||
|
||||
void Printer::WriteRaw(const char* data, int size) {
|
||||
if (failed_) return;
|
||||
if (size == 0) return;
|
||||
|
||||
if (at_start_of_line_ && (size > 0) && (data[0] != '\n')) {
|
||||
// Insert an indent.
|
||||
at_start_of_line_ = false;
|
||||
WriteRaw(indent_.data(), indent_.size());
|
||||
if (failed_) return;
|
||||
}
|
||||
|
||||
while (size > buffer_size_) {
|
||||
// Data exceeds space in the buffer. Copy what we can and request a
|
||||
// new buffer.
|
||||
memcpy(buffer_, data, buffer_size_);
|
||||
data += buffer_size_;
|
||||
size -= buffer_size_;
|
||||
void* void_buffer;
|
||||
failed_ = !output_->Next(&void_buffer, &buffer_size_);
|
||||
if (failed_) return;
|
||||
buffer_ = reinterpret_cast<char*>(void_buffer);
|
||||
}
|
||||
|
||||
// Buffer is big enough to receive the data; copy it.
|
||||
memcpy(buffer_, data, size);
|
||||
buffer_ += size;
|
||||
buffer_size_ -= size;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,136 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// Utility class for writing text to a ZeroCopyOutputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
|
||||
#define GOOGLE_PROTOBUF_IO_PRINTER_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
class ZeroCopyOutputStream; // zero_copy_stream.h
|
||||
|
||||
// This simple utility class assists in code generation. It basically
|
||||
// allows the caller to define a set of variables and then output some
|
||||
// text with variable substitutions. Example usage:
|
||||
//
|
||||
// Printer printer(output, '$');
|
||||
// map<string, string> vars;
|
||||
// vars["name"] = "Bob";
|
||||
// printer.Print(vars, "My name is $name$.");
|
||||
//
|
||||
// The above writes "My name is Bob." to the output stream.
|
||||
//
|
||||
// Printer aggressively enforces correct usage, crashing (with assert failures)
|
||||
// in the case of undefined variables in debug builds. This helps greatly in
|
||||
// debugging code which uses it.
|
||||
class LIBPROTOBUF_EXPORT Printer {
|
||||
public:
|
||||
// Create a printer that writes text to the given output stream. Use the
|
||||
// given character as the delimiter for variables.
|
||||
Printer(ZeroCopyOutputStream* output, char variable_delimiter);
|
||||
~Printer();
|
||||
|
||||
// Print some text after applying variable substitutions. If a particular
|
||||
// variable in the text is not defined, this will crash. Variables to be
|
||||
// substituted are identified by their names surrounded by delimiter
|
||||
// characters (as given to the constructor). The variable bindings are
|
||||
// defined by the given map.
|
||||
void Print(const map<string, string>& variables, const char* text);
|
||||
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable, const string& value);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2,
|
||||
const char* variable3, const string& value3);
|
||||
// TODO(kenton): Overloaded versions with more variables? Three seems
|
||||
// to be enough.
|
||||
|
||||
// Indent text by two spaces. After calling Indent(), two spaces will be
|
||||
// inserted at the beginning of each line of text. Indent() may be called
|
||||
// multiple times to produce deeper indents.
|
||||
void Indent();
|
||||
|
||||
// Reduces the current indent level by two spaces, or crashes if the indent
|
||||
// level is zero.
|
||||
void Outdent();
|
||||
|
||||
// Write a string to the output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void PrintRaw(const string& data);
|
||||
|
||||
// Write a zero-delimited string to output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void PrintRaw(const char* data);
|
||||
|
||||
// Write some bytes to the output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void WriteRaw(const char* data, int size);
|
||||
|
||||
// True if any write to the underlying stream failed. (We don't just
|
||||
// crash in this case because this is an I/O failure, not a programming
|
||||
// error.)
|
||||
bool failed() const { return failed_; }
|
||||
|
||||
private:
|
||||
const char variable_delimiter_;
|
||||
|
||||
ZeroCopyOutputStream* const output_;
|
||||
char* buffer_;
|
||||
int buffer_size_;
|
||||
|
||||
string indent_;
|
||||
bool at_start_of_line_;
|
||||
bool failed_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_PRINTER_H__
|
|
@ -1,113 +0,0 @@
|
|||
// 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/io/strtod.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// NoLocaleStrtod()
|
||||
// This code will make you cry.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns a string identical to *input except that the character pointed to
|
||||
// by radix_pos (which should be '.') is replaced with the locale-specific
|
||||
// radix character.
|
||||
string LocalizeRadix(const char* input, const char* radix_pos) {
|
||||
// Determine the locale-specific radix character by calling sprintf() to
|
||||
// print the number 1.5, then stripping off the digits. As far as I can
|
||||
// tell, this is the only portable, thread-safe way to get the C library
|
||||
// to divuldge the locale's radix character. No, localeconv() is NOT
|
||||
// thread-safe.
|
||||
char temp[16];
|
||||
int size = sprintf(temp, "%.1f", 1.5);
|
||||
GOOGLE_CHECK_EQ(temp[0], '1');
|
||||
GOOGLE_CHECK_EQ(temp[size-1], '5');
|
||||
GOOGLE_CHECK_LE(size, 6);
|
||||
|
||||
// Now replace the '.' in the input with it.
|
||||
string result;
|
||||
result.reserve(strlen(input) + size - 3);
|
||||
result.append(input, radix_pos);
|
||||
result.append(temp + 1, size - 2);
|
||||
result.append(radix_pos + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
double NoLocaleStrtod(const char* text, char** original_endptr) {
|
||||
// We cannot simply set the locale to "C" temporarily with setlocale()
|
||||
// as this is not thread-safe. Instead, we try to parse in the current
|
||||
// locale first. If parsing stops at a '.' character, then this is a
|
||||
// pretty good hint that we're actually in some other locale in which
|
||||
// '.' is not the radix character.
|
||||
|
||||
char* temp_endptr;
|
||||
double result = strtod(text, &temp_endptr);
|
||||
if (original_endptr != NULL) *original_endptr = temp_endptr;
|
||||
if (*temp_endptr != '.') return result;
|
||||
|
||||
// Parsing halted on a '.'. Perhaps we're in a different locale? Let's
|
||||
// try to replace the '.' with a locale-specific radix character and
|
||||
// try again.
|
||||
string localized = LocalizeRadix(text, temp_endptr);
|
||||
const char* localized_cstr = localized.c_str();
|
||||
char* localized_endptr;
|
||||
result = strtod(localized_cstr, &localized_endptr);
|
||||
if ((localized_endptr - localized_cstr) >
|
||||
(temp_endptr - text)) {
|
||||
// This attempt got further, so replacing the decimal must have helped.
|
||||
// Update original_endptr to point at the right location.
|
||||
if (original_endptr != NULL) {
|
||||
// size_diff is non-zero if the localized radix has multiple bytes.
|
||||
int size_diff = localized.size() - strlen(text);
|
||||
// const_cast is necessary to match the strtod() interface.
|
||||
*original_endptr = const_cast<char*>(
|
||||
text + (localized_endptr - localized_cstr - size_diff));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,50 +0,0 @@
|
|||
// 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 locale-independent version of strtod(), used to parse floating
|
||||
// point default values in .proto files, where the decimal separator
|
||||
// is always a dot.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_STRTOD_H__
|
||||
#define GOOGLE_PROTOBUF_IO_STRTOD_H__
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// A locale-independent version of the standard strtod(), which always
|
||||
// uses a dot as the decimal separator.
|
||||
double NoLocaleStrtod(const char* str, char** endptr);
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_STRTOD_H__
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,402 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// Class for parsing tokenized text from a ZeroCopyInputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
||||
#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
class ZeroCopyInputStream; // zero_copy_stream.h
|
||||
|
||||
// Defined in this file.
|
||||
class ErrorCollector;
|
||||
class Tokenizer;
|
||||
|
||||
// Abstract interface for an object which collects the errors that occur
|
||||
// during parsing. A typical implementation might simply print the errors
|
||||
// to stdout.
|
||||
class LIBPROTOBUF_EXPORT ErrorCollector {
|
||||
public:
|
||||
inline ErrorCollector() {}
|
||||
virtual ~ErrorCollector();
|
||||
|
||||
// Indicates that there was an error in the input at the given line and
|
||||
// column numbers. The numbers are zero-based, so you may want to add
|
||||
// 1 to each before printing them.
|
||||
virtual void AddError(int line, int column, const string& message) = 0;
|
||||
|
||||
// Indicates that there was a warning in the input at the given line and
|
||||
// column numbers. The numbers are zero-based, so you may want to add
|
||||
// 1 to each before printing them.
|
||||
virtual void AddWarning(int /* line */, int /* column */,
|
||||
const string& /* message */) { }
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
|
||||
};
|
||||
|
||||
// This class converts a stream of raw text into a stream of tokens for
|
||||
// the protocol definition parser to parse. The tokens recognized are
|
||||
// similar to those that make up the C language; see the TokenType enum for
|
||||
// precise descriptions. Whitespace and comments are skipped. By default,
|
||||
// C- and C++-style comments are recognized, but other styles can be used by
|
||||
// calling set_comment_style().
|
||||
class LIBPROTOBUF_EXPORT Tokenizer {
|
||||
public:
|
||||
// Construct a Tokenizer that reads and tokenizes text from the given
|
||||
// input stream and writes errors to the given error_collector.
|
||||
// The caller keeps ownership of input and error_collector.
|
||||
Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector);
|
||||
~Tokenizer();
|
||||
|
||||
enum TokenType {
|
||||
TYPE_START, // Next() has not yet been called.
|
||||
TYPE_END, // End of input reached. "text" is empty.
|
||||
|
||||
TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not
|
||||
// starting with a digit. It is an error for a number
|
||||
// to be followed by an identifier with no space in
|
||||
// between.
|
||||
TYPE_INTEGER, // A sequence of digits representing an integer. Normally
|
||||
// the digits are decimal, but a prefix of "0x" indicates
|
||||
// a hex number and a leading zero indicates octal, just
|
||||
// like with C numeric literals. A leading negative sign
|
||||
// is NOT included in the token; it's up to the parser to
|
||||
// interpret the unary minus operator on its own.
|
||||
TYPE_FLOAT, // A floating point literal, with a fractional part and/or
|
||||
// an exponent. Always in decimal. Again, never
|
||||
// negative.
|
||||
TYPE_STRING, // A quoted sequence of escaped characters. Either single
|
||||
// or double quotes can be used, but they must match.
|
||||
// A string literal cannot cross a line break.
|
||||
TYPE_SYMBOL, // Any other printable character, like '!' or '+'.
|
||||
// Symbols are always a single character, so "!+$%" is
|
||||
// four tokens.
|
||||
};
|
||||
|
||||
// Structure representing a token read from the token stream.
|
||||
struct Token {
|
||||
TokenType type;
|
||||
string text; // The exact text of the token as it appeared in
|
||||
// the input. e.g. tokens of TYPE_STRING will still
|
||||
// be escaped and in quotes.
|
||||
|
||||
// "line" and "column" specify the position of the first character of
|
||||
// the token within the input stream. They are zero-based.
|
||||
int line;
|
||||
int column;
|
||||
int end_column;
|
||||
};
|
||||
|
||||
// Get the current token. This is updated when Next() is called. Before
|
||||
// the first call to Next(), current() has type TYPE_START and no contents.
|
||||
const Token& current();
|
||||
|
||||
// Return the previous token -- i.e. what current() returned before the
|
||||
// previous call to Next().
|
||||
const Token& previous();
|
||||
|
||||
// Advance to the next token. Returns false if the end of the input is
|
||||
// reached.
|
||||
bool Next();
|
||||
|
||||
// Like Next(), but also collects comments which appear between the previous
|
||||
// and next tokens.
|
||||
//
|
||||
// Comments which appear to be attached to the previous token are stored
|
||||
// in *prev_tailing_comments. Comments which appear to be attached to the
|
||||
// next token are stored in *next_leading_comments. Comments appearing in
|
||||
// between which do not appear to be attached to either will be added to
|
||||
// detached_comments. Any of these parameters can be NULL to simply discard
|
||||
// the comments.
|
||||
//
|
||||
// A series of line comments appearing on consecutive lines, with no other
|
||||
// tokens appearing on those lines, will be treated as a single comment.
|
||||
//
|
||||
// Only the comment content is returned; comment markers (e.g. //) are
|
||||
// stripped out. For block comments, leading whitespace and an asterisk will
|
||||
// be stripped from the beginning of each line other than the first. Newlines
|
||||
// are included in the output.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// optional int32 foo = 1; // Comment attached to foo.
|
||||
// // Comment attached to bar.
|
||||
// optional int32 bar = 2;
|
||||
//
|
||||
// optional string baz = 3;
|
||||
// // Comment attached to baz.
|
||||
// // Another line attached to baz.
|
||||
//
|
||||
// // Comment attached to qux.
|
||||
// //
|
||||
// // Another line attached to qux.
|
||||
// optional double qux = 4;
|
||||
//
|
||||
// // Detached comment. This is not attached to qux or corge
|
||||
// // because there are blank lines separating it from both.
|
||||
//
|
||||
// optional string corge = 5;
|
||||
// /* Block comment attached
|
||||
// * to corge. Leading asterisks
|
||||
// * will be removed. */
|
||||
// /* Block comment attached to
|
||||
// * grault. */
|
||||
// optional int32 grault = 6;
|
||||
bool NextWithComments(string* prev_trailing_comments,
|
||||
vector<string>* detached_comments,
|
||||
string* next_leading_comments);
|
||||
|
||||
// Parse helpers ---------------------------------------------------
|
||||
|
||||
// Parses a TYPE_FLOAT token. This never fails, so long as the text actually
|
||||
// comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the
|
||||
// result is undefined (possibly an assert failure).
|
||||
static double ParseFloat(const string& text);
|
||||
|
||||
// Parses a TYPE_STRING token. This never fails, so long as the text actually
|
||||
// comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the
|
||||
// result is undefined (possibly an assert failure).
|
||||
static void ParseString(const string& text, string* output);
|
||||
|
||||
// Identical to ParseString, but appends to output.
|
||||
static void ParseStringAppend(const string& text, string* output);
|
||||
|
||||
// Parses a TYPE_INTEGER token. Returns false if the result would be
|
||||
// greater than max_value. Otherwise, returns true and sets *output to the
|
||||
// result. If the text is not from a Token of type TYPE_INTEGER originally
|
||||
// parsed by a Tokenizer, the result is undefined (possibly an assert
|
||||
// failure).
|
||||
static bool ParseInteger(const string& text, uint64 max_value,
|
||||
uint64* output);
|
||||
|
||||
// Options ---------------------------------------------------------
|
||||
|
||||
// Set true to allow floats to be suffixed with the letter 'f'. Tokens
|
||||
// which would otherwise be integers but which have the 'f' suffix will be
|
||||
// forced to be interpreted as floats. For all other purposes, the 'f' is
|
||||
// ignored.
|
||||
void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
|
||||
|
||||
// Valid values for set_comment_style().
|
||||
enum CommentStyle {
|
||||
// Line comments begin with "//", block comments are delimited by "/*" and
|
||||
// "*/".
|
||||
CPP_COMMENT_STYLE,
|
||||
// Line comments begin with "#". No way to write block comments.
|
||||
SH_COMMENT_STYLE
|
||||
};
|
||||
|
||||
// Sets the comment style.
|
||||
void set_comment_style(CommentStyle style) { comment_style_ = style; }
|
||||
|
||||
// Whether to require whitespace between a number and a field name.
|
||||
// Default is true. Do not use this; for Google-internal cleanup only.
|
||||
void set_require_space_after_number(bool require) {
|
||||
require_space_after_number_ = require;
|
||||
}
|
||||
|
||||
// Whether to allow string literals to span multiple lines. Default is false.
|
||||
// Do not use this; for Google-internal cleanup only.
|
||||
void set_allow_multiline_strings(bool allow) {
|
||||
allow_multiline_strings_ = allow;
|
||||
}
|
||||
|
||||
// External helper: validate an identifier.
|
||||
static bool IsIdentifier(const string& text);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
|
||||
|
||||
Token current_; // Returned by current().
|
||||
Token previous_; // Returned by previous().
|
||||
|
||||
ZeroCopyInputStream* input_;
|
||||
ErrorCollector* error_collector_;
|
||||
|
||||
char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
|
||||
const char* buffer_; // Current buffer returned from input_.
|
||||
int buffer_size_; // Size of buffer_.
|
||||
int buffer_pos_; // Current position within the buffer.
|
||||
bool read_error_; // Did we previously encounter a read error?
|
||||
|
||||
// Line and column number of current_char_ within the whole input stream.
|
||||
int line_;
|
||||
int column_;
|
||||
|
||||
// String to which text should be appended as we advance through it.
|
||||
// Call RecordTo(&str) to start recording and StopRecording() to stop.
|
||||
// E.g. StartToken() calls RecordTo(¤t_.text). record_start_ is the
|
||||
// position within the current buffer where recording started.
|
||||
string* record_target_;
|
||||
int record_start_;
|
||||
|
||||
// Options.
|
||||
bool allow_f_after_float_;
|
||||
CommentStyle comment_style_;
|
||||
bool require_space_after_number_;
|
||||
bool allow_multiline_strings_;
|
||||
|
||||
// Since we count columns we need to interpret tabs somehow. We'll take
|
||||
// the standard 8-character definition for lack of any way to do better.
|
||||
static const int kTabWidth = 8;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Helper methods.
|
||||
|
||||
// Consume this character and advance to the next one.
|
||||
void NextChar();
|
||||
|
||||
// Read a new buffer from the input.
|
||||
void Refresh();
|
||||
|
||||
inline void RecordTo(string* target);
|
||||
inline void StopRecording();
|
||||
|
||||
// Called when the current character is the first character of a new
|
||||
// token (not including whitespace or comments).
|
||||
inline void StartToken();
|
||||
// Called when the current character is the first character after the
|
||||
// end of the last token. After this returns, current_.text will
|
||||
// contain all text consumed since StartToken() was called.
|
||||
inline void EndToken();
|
||||
|
||||
// Convenience method to add an error at the current line and column.
|
||||
void AddError(const string& message) {
|
||||
error_collector_->AddError(line_, column_, message);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// The following four methods are used to consume tokens of specific
|
||||
// types. They are actually used to consume all characters *after*
|
||||
// the first, since the calling function consumes the first character
|
||||
// in order to decide what kind of token is being read.
|
||||
|
||||
// Read and consume a string, ending when the given delimiter is
|
||||
// consumed.
|
||||
void ConsumeString(char delimiter);
|
||||
|
||||
// Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
|
||||
// depending on what was read. This needs to know if the first
|
||||
// character was a zero in order to correctly recognize hex and octal
|
||||
// numbers.
|
||||
// It also needs to know if the first characted was a . to parse floating
|
||||
// point correctly.
|
||||
TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
|
||||
|
||||
// Consume the rest of a line.
|
||||
void ConsumeLineComment(string* content);
|
||||
// Consume until "*/".
|
||||
void ConsumeBlockComment(string* content);
|
||||
|
||||
enum NextCommentStatus {
|
||||
// Started a line comment.
|
||||
LINE_COMMENT,
|
||||
|
||||
// Started a block comment.
|
||||
BLOCK_COMMENT,
|
||||
|
||||
// Consumed a slash, then realized it wasn't a comment. current_ has
|
||||
// been filled in with a slash token. The caller should return it.
|
||||
SLASH_NOT_COMMENT,
|
||||
|
||||
// We do not appear to be starting a comment here.
|
||||
NO_COMMENT
|
||||
};
|
||||
|
||||
// If we're at the start of a new comment, consume it and return what kind
|
||||
// of comment it is.
|
||||
NextCommentStatus TryConsumeCommentStart();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// These helper methods make the parsing code more readable. The
|
||||
// "character classes" refered to are defined at the top of the .cc file.
|
||||
// Basically it is a C++ class with one method:
|
||||
// static bool InClass(char c);
|
||||
// The method returns true if c is a member of this "class", like "Letter"
|
||||
// or "Digit".
|
||||
|
||||
// Returns true if the current character is of the given character
|
||||
// class, but does not consume anything.
|
||||
template<typename CharacterClass>
|
||||
inline bool LookingAt();
|
||||
|
||||
// If the current character is in the given class, consume it and return
|
||||
// true. Otherwise return false.
|
||||
// e.g. TryConsumeOne<Letter>()
|
||||
template<typename CharacterClass>
|
||||
inline bool TryConsumeOne();
|
||||
|
||||
// Like above, but try to consume the specific character indicated.
|
||||
inline bool TryConsume(char c);
|
||||
|
||||
// Consume zero or more of the given character class.
|
||||
template<typename CharacterClass>
|
||||
inline void ConsumeZeroOrMore();
|
||||
|
||||
// Consume one or more of the given character class or log the given
|
||||
// error message.
|
||||
// e.g. ConsumeOneOrMore<Digit>("Expected digits.");
|
||||
template<typename CharacterClass>
|
||||
inline void ConsumeOneOrMore(const char* error);
|
||||
};
|
||||
|
||||
// inline methods ====================================================
|
||||
inline const Tokenizer::Token& Tokenizer::current() {
|
||||
return current_;
|
||||
}
|
||||
|
||||
inline const Tokenizer::Token& Tokenizer::previous() {
|
||||
return previous_;
|
||||
}
|
||||
|
||||
inline void Tokenizer::ParseString(const string& text, string* output) {
|
||||
output->clear();
|
||||
ParseStringAppend(text, output);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
|
@ -1,473 +0,0 @@
|
|||
// 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.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Win32 lseek is broken: If invoked on a non-seekable file descriptor, its
|
||||
// return value is undefined. We re-define it to always produce an error.
|
||||
#define lseek(fd, offset, origin) ((off_t)-1)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// EINTR sucks.
|
||||
int close_no_eintr(int fd) {
|
||||
int result;
|
||||
do {
|
||||
result = close(fd);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileInputStream::FileInputStream(int file_descriptor, int block_size)
|
||||
: copying_input_(file_descriptor),
|
||||
impl_(©ing_input_, block_size) {
|
||||
}
|
||||
|
||||
FileInputStream::~FileInputStream() {}
|
||||
|
||||
bool FileInputStream::Close() {
|
||||
return copying_input_.Close();
|
||||
}
|
||||
|
||||
bool FileInputStream::Next(const void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void FileInputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
bool FileInputStream::Skip(int count) {
|
||||
return impl_.Skip(count);
|
||||
}
|
||||
|
||||
int64 FileInputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
|
||||
int file_descriptor)
|
||||
: file_(file_descriptor),
|
||||
close_on_delete_(false),
|
||||
is_closed_(false),
|
||||
errno_(0),
|
||||
previous_seek_failed_(false) {
|
||||
}
|
||||
|
||||
FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
|
||||
if (close_on_delete_) {
|
||||
if (!Close()) {
|
||||
GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileInputStream::CopyingFileInputStream::Close() {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
is_closed_ = true;
|
||||
if (close_no_eintr(file_) != 0) {
|
||||
// The docs on close() do not specify whether a file descriptor is still
|
||||
// open after close() fails with EIO. However, the glibc source code
|
||||
// seems to indicate that it is not.
|
||||
errno_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
int result;
|
||||
do {
|
||||
result = read(file_, buffer, size);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result < 0) {
|
||||
// Read error (not EOF).
|
||||
errno_ = errno;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int FileInputStream::CopyingFileInputStream::Skip(int count) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
if (!previous_seek_failed_ &&
|
||||
lseek(file_, count, SEEK_CUR) != (off_t)-1) {
|
||||
// Seek succeeded.
|
||||
return count;
|
||||
} else {
|
||||
// Failed to seek.
|
||||
|
||||
// Note to self: Don't seek again. This file descriptor doesn't
|
||||
// support it.
|
||||
previous_seek_failed_ = true;
|
||||
|
||||
// Use the default implementation.
|
||||
return CopyingInputStream::Skip(count);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
|
||||
: copying_output_(file_descriptor),
|
||||
impl_(©ing_output_, block_size) {
|
||||
}
|
||||
|
||||
FileOutputStream::~FileOutputStream() {
|
||||
impl_.Flush();
|
||||
}
|
||||
|
||||
bool FileOutputStream::Close() {
|
||||
bool flush_succeeded = impl_.Flush();
|
||||
return copying_output_.Close() && flush_succeeded;
|
||||
}
|
||||
|
||||
bool FileOutputStream::Flush() {
|
||||
return impl_.Flush();
|
||||
}
|
||||
|
||||
bool FileOutputStream::Next(void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void FileOutputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
int64 FileOutputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
|
||||
int file_descriptor)
|
||||
: file_(file_descriptor),
|
||||
close_on_delete_(false),
|
||||
is_closed_(false),
|
||||
errno_(0) {
|
||||
}
|
||||
|
||||
FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
|
||||
if (close_on_delete_) {
|
||||
if (!Close()) {
|
||||
GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileOutputStream::CopyingFileOutputStream::Close() {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
is_closed_ = true;
|
||||
if (close_no_eintr(file_) != 0) {
|
||||
// The docs on close() do not specify whether a file descriptor is still
|
||||
// open after close() fails with EIO. However, the glibc source code
|
||||
// seems to indicate that it is not.
|
||||
errno_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileOutputStream::CopyingFileOutputStream::Write(
|
||||
const void* buffer, int size) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
int total_written = 0;
|
||||
|
||||
const uint8* buffer_base = reinterpret_cast<const uint8*>(buffer);
|
||||
|
||||
while (total_written < size) {
|
||||
int bytes;
|
||||
do {
|
||||
bytes = write(file_, buffer_base + total_written, size - total_written);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
|
||||
if (bytes <= 0) {
|
||||
// Write error.
|
||||
|
||||
// FIXME(kenton): According to the man page, if write() returns zero,
|
||||
// there was no error; write() simply did not write anything. It's
|
||||
// unclear under what circumstances this might happen, but presumably
|
||||
// errno won't be set in this case. I am confused as to how such an
|
||||
// event should be handled. For now I'm treating it as an error, since
|
||||
// retrying seems like it could lead to an infinite loop. I suspect
|
||||
// this never actually happens anyway.
|
||||
|
||||
if (bytes < 0) {
|
||||
errno_ = errno;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
total_written += bytes;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
IstreamInputStream::IstreamInputStream(istream* input, int block_size)
|
||||
: copying_input_(input),
|
||||
impl_(©ing_input_, block_size) {
|
||||
}
|
||||
|
||||
IstreamInputStream::~IstreamInputStream() {}
|
||||
|
||||
bool IstreamInputStream::Next(const void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void IstreamInputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
bool IstreamInputStream::Skip(int count) {
|
||||
return impl_.Skip(count);
|
||||
}
|
||||
|
||||
int64 IstreamInputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
|
||||
istream* input)
|
||||
: input_(input) {
|
||||
}
|
||||
|
||||
IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
|
||||
|
||||
int IstreamInputStream::CopyingIstreamInputStream::Read(
|
||||
void* buffer, int size) {
|
||||
input_->read(reinterpret_cast<char*>(buffer), size);
|
||||
int result = input_->gcount();
|
||||
if (result == 0 && input_->fail() && !input_->eof()) {
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
OstreamOutputStream::OstreamOutputStream(ostream* output, int block_size)
|
||||
: copying_output_(output),
|
||||
impl_(©ing_output_, block_size) {
|
||||
}
|
||||
|
||||
OstreamOutputStream::~OstreamOutputStream() {
|
||||
impl_.Flush();
|
||||
}
|
||||
|
||||
bool OstreamOutputStream::Next(void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void OstreamOutputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
int64 OstreamOutputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
|
||||
ostream* output)
|
||||
: output_(output) {
|
||||
}
|
||||
|
||||
OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
|
||||
}
|
||||
|
||||
bool OstreamOutputStream::CopyingOstreamOutputStream::Write(
|
||||
const void* buffer, int size) {
|
||||
output_->write(reinterpret_cast<const char*>(buffer), size);
|
||||
return output_->good();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ConcatenatingInputStream::ConcatenatingInputStream(
|
||||
ZeroCopyInputStream* const streams[], int count)
|
||||
: streams_(streams), stream_count_(count), bytes_retired_(0) {
|
||||
}
|
||||
|
||||
ConcatenatingInputStream::~ConcatenatingInputStream() {
|
||||
}
|
||||
|
||||
bool ConcatenatingInputStream::Next(const void** data, int* size) {
|
||||
while (stream_count_ > 0) {
|
||||
if (streams_[0]->Next(data, size)) return true;
|
||||
|
||||
// That stream is done. Advance to the next one.
|
||||
bytes_retired_ += streams_[0]->ByteCount();
|
||||
++streams_;
|
||||
--stream_count_;
|
||||
}
|
||||
|
||||
// No more streams.
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConcatenatingInputStream::BackUp(int count) {
|
||||
if (stream_count_ > 0) {
|
||||
streams_[0]->BackUp(count);
|
||||
} else {
|
||||
GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next().";
|
||||
}
|
||||
}
|
||||
|
||||
bool ConcatenatingInputStream::Skip(int count) {
|
||||
while (stream_count_ > 0) {
|
||||
// Assume that ByteCount() can be used to find out how much we actually
|
||||
// skipped when Skip() fails.
|
||||
int64 target_byte_count = streams_[0]->ByteCount() + count;
|
||||
if (streams_[0]->Skip(count)) return true;
|
||||
|
||||
// Hit the end of the stream. Figure out how many more bytes we still have
|
||||
// to skip.
|
||||
int64 final_byte_count = streams_[0]->ByteCount();
|
||||
GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
|
||||
count = target_byte_count - final_byte_count;
|
||||
|
||||
// That stream is done. Advance to the next one.
|
||||
bytes_retired_ += final_byte_count;
|
||||
++streams_;
|
||||
--stream_count_;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int64 ConcatenatingInputStream::ByteCount() const {
|
||||
if (stream_count_ == 0) {
|
||||
return bytes_retired_;
|
||||
} else {
|
||||
return bytes_retired_ + streams_[0]->ByteCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
|
||||
int64 limit)
|
||||
: input_(input), limit_(limit) {
|
||||
prior_bytes_read_ = input_->ByteCount();
|
||||
}
|
||||
|
||||
LimitingInputStream::~LimitingInputStream() {
|
||||
// If we overshot the limit, back up.
|
||||
if (limit_ < 0) input_->BackUp(-limit_);
|
||||
}
|
||||
|
||||
bool LimitingInputStream::Next(const void** data, int* size) {
|
||||
if (limit_ <= 0) return false;
|
||||
if (!input_->Next(data, size)) return false;
|
||||
|
||||
limit_ -= *size;
|
||||
if (limit_ < 0) {
|
||||
// We overshot the limit. Reduce *size to hide the rest of the buffer.
|
||||
*size += limit_;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LimitingInputStream::BackUp(int count) {
|
||||
if (limit_ < 0) {
|
||||
input_->BackUp(count - limit_);
|
||||
limit_ = count;
|
||||
} else {
|
||||
input_->BackUp(count);
|
||||
limit_ += count;
|
||||
}
|
||||
}
|
||||
|
||||
bool LimitingInputStream::Skip(int count) {
|
||||
if (count > limit_) {
|
||||
if (limit_ < 0) return false;
|
||||
input_->Skip(limit_);
|
||||
limit_ = 0;
|
||||
return false;
|
||||
} else {
|
||||
if (!input_->Skip(count)) return false;
|
||||
limit_ -= count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64 LimitingInputStream::ByteCount() const {
|
||||
if (limit_ < 0) {
|
||||
return input_->ByteCount() + limit_ - prior_bytes_read_;
|
||||
} else {
|
||||
return input_->ByteCount() - prior_bytes_read_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,358 +0,0 @@
|
|||
// 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 <iostream>
|
||||
#include <stack>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/map_util.h>
|
||||
#include <google/protobuf/stubs/stl_util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ReflectionOps;
|
||||
|
||||
Message::~Message() {}
|
||||
|
||||
void Message::MergeFrom(const Message& from) {
|
||||
const Descriptor* descriptor = GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
|
||||
<< ": Tried to merge from a message with a different type. "
|
||||
"to: " << descriptor->full_name() << ", "
|
||||
"from:" << from.GetDescriptor()->full_name();
|
||||
ReflectionOps::Merge(from, this);
|
||||
}
|
||||
|
||||
void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
|
||||
MergeFrom(*down_cast<const Message*>(&other));
|
||||
}
|
||||
|
||||
void Message::CopyFrom(const Message& from) {
|
||||
const Descriptor* descriptor = GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
|
||||
<< ": Tried to copy from a message with a different type. "
|
||||
"to: " << descriptor->full_name() << ", "
|
||||
"from:" << from.GetDescriptor()->full_name();
|
||||
ReflectionOps::Copy(from, this);
|
||||
}
|
||||
|
||||
string Message::GetTypeName() const {
|
||||
return GetDescriptor()->full_name();
|
||||
}
|
||||
|
||||
void Message::Clear() {
|
||||
ReflectionOps::Clear(this);
|
||||
}
|
||||
|
||||
bool Message::IsInitialized() const {
|
||||
return ReflectionOps::IsInitialized(*this);
|
||||
}
|
||||
|
||||
void Message::FindInitializationErrors(vector<string>* errors) const {
|
||||
return ReflectionOps::FindInitializationErrors(*this, "", errors);
|
||||
}
|
||||
|
||||
string Message::InitializationErrorString() const {
|
||||
vector<string> errors;
|
||||
FindInitializationErrors(&errors);
|
||||
return Join(errors, ", ");
|
||||
}
|
||||
|
||||
void Message::CheckInitialized() const {
|
||||
GOOGLE_CHECK(IsInitialized())
|
||||
<< "Message of type \"" << GetDescriptor()->full_name()
|
||||
<< "\" is missing required fields: " << InitializationErrorString();
|
||||
}
|
||||
|
||||
void Message::DiscardUnknownFields() {
|
||||
return ReflectionOps::DiscardUnknownFields(this);
|
||||
}
|
||||
|
||||
bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
|
||||
return WireFormat::ParseAndMergePartial(input, this);
|
||||
}
|
||||
|
||||
bool Message::ParseFromFileDescriptor(int file_descriptor) {
|
||||
io::FileInputStream input(file_descriptor);
|
||||
return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
|
||||
}
|
||||
|
||||
bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
|
||||
io::FileInputStream input(file_descriptor);
|
||||
return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
|
||||
}
|
||||
|
||||
bool Message::ParseFromIstream(istream* input) {
|
||||
io::IstreamInputStream zero_copy_input(input);
|
||||
return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
|
||||
}
|
||||
|
||||
bool Message::ParsePartialFromIstream(istream* input) {
|
||||
io::IstreamInputStream zero_copy_input(input);
|
||||
return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
|
||||
}
|
||||
|
||||
|
||||
void Message::SerializeWithCachedSizes(
|
||||
io::CodedOutputStream* output) const {
|
||||
WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output);
|
||||
}
|
||||
|
||||
int Message::ByteSize() const {
|
||||
int size = WireFormat::ByteSize(*this);
|
||||
SetCachedSize(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
void Message::SetCachedSize(int /* size */) const {
|
||||
GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
|
||||
<< "\" implements neither SetCachedSize() nor ByteSize(). "
|
||||
"Must implement one or the other.";
|
||||
}
|
||||
|
||||
int Message::SpaceUsed() const {
|
||||
return GetReflection()->SpaceUsed(*this);
|
||||
}
|
||||
|
||||
bool Message::SerializeToFileDescriptor(int file_descriptor) const {
|
||||
io::FileOutputStream output(file_descriptor);
|
||||
return SerializeToZeroCopyStream(&output);
|
||||
}
|
||||
|
||||
bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
|
||||
io::FileOutputStream output(file_descriptor);
|
||||
return SerializePartialToZeroCopyStream(&output);
|
||||
}
|
||||
|
||||
bool Message::SerializeToOstream(ostream* output) const {
|
||||
{
|
||||
io::OstreamOutputStream zero_copy_output(output);
|
||||
if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
|
||||
}
|
||||
return output->good();
|
||||
}
|
||||
|
||||
bool Message::SerializePartialToOstream(ostream* output) const {
|
||||
io::OstreamOutputStream zero_copy_output(output);
|
||||
return SerializePartialToZeroCopyStream(&zero_copy_output);
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// Reflection and associated Template Specializations
|
||||
|
||||
Reflection::~Reflection() {}
|
||||
|
||||
#define HANDLE_TYPE(TYPE, CPPTYPE, CTYPE) \
|
||||
template<> \
|
||||
const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \
|
||||
const Message& message, const FieldDescriptor* field) const { \
|
||||
return *static_cast<RepeatedField<TYPE>* >( \
|
||||
MutableRawRepeatedField(const_cast<Message*>(&message), \
|
||||
field, CPPTYPE, CTYPE, NULL)); \
|
||||
} \
|
||||
\
|
||||
template<> \
|
||||
RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \
|
||||
Message* message, const FieldDescriptor* field) const { \
|
||||
return static_cast<RepeatedField<TYPE>* >( \
|
||||
MutableRawRepeatedField(message, field, CPPTYPE, CTYPE, NULL)); \
|
||||
}
|
||||
|
||||
HANDLE_TYPE(int32, FieldDescriptor::CPPTYPE_INT32, -1);
|
||||
HANDLE_TYPE(int64, FieldDescriptor::CPPTYPE_INT64, -1);
|
||||
HANDLE_TYPE(uint32, FieldDescriptor::CPPTYPE_UINT32, -1);
|
||||
HANDLE_TYPE(uint64, FieldDescriptor::CPPTYPE_UINT64, -1);
|
||||
HANDLE_TYPE(float, FieldDescriptor::CPPTYPE_FLOAT, -1);
|
||||
HANDLE_TYPE(double, FieldDescriptor::CPPTYPE_DOUBLE, -1);
|
||||
HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1);
|
||||
|
||||
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
void* Reflection::MutableRawRepeatedString(
|
||||
Message* message, const FieldDescriptor* field, bool is_string) const {
|
||||
return MutableRawRepeatedField(message, field,
|
||||
FieldDescriptor::CPPTYPE_STRING, FieldOptions::STRING, NULL);
|
||||
}
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// MessageFactory
|
||||
|
||||
MessageFactory::~MessageFactory() {}
|
||||
|
||||
namespace {
|
||||
|
||||
class GeneratedMessageFactory : public MessageFactory {
|
||||
public:
|
||||
GeneratedMessageFactory();
|
||||
~GeneratedMessageFactory();
|
||||
|
||||
static GeneratedMessageFactory* singleton();
|
||||
|
||||
typedef void RegistrationFunc(const string&);
|
||||
void RegisterFile(const char* file, RegistrationFunc* registration_func);
|
||||
void RegisterType(const Descriptor* descriptor, const Message* prototype);
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
// Only written at static init time, so does not require locking.
|
||||
hash_map<const char*, RegistrationFunc*,
|
||||
hash<const char*>, streq> file_map_;
|
||||
|
||||
// Initialized lazily, so requires locking.
|
||||
Mutex mutex_;
|
||||
hash_map<const Descriptor*, const Message*> type_map_;
|
||||
};
|
||||
|
||||
GeneratedMessageFactory* generated_message_factory_ = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_);
|
||||
|
||||
void ShutdownGeneratedMessageFactory() {
|
||||
delete generated_message_factory_;
|
||||
}
|
||||
|
||||
void InitGeneratedMessageFactory() {
|
||||
generated_message_factory_ = new GeneratedMessageFactory;
|
||||
internal::OnShutdown(&ShutdownGeneratedMessageFactory);
|
||||
}
|
||||
|
||||
GeneratedMessageFactory::GeneratedMessageFactory() {}
|
||||
GeneratedMessageFactory::~GeneratedMessageFactory() {}
|
||||
|
||||
GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
|
||||
::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_,
|
||||
&InitGeneratedMessageFactory);
|
||||
return generated_message_factory_;
|
||||
}
|
||||
|
||||
void GeneratedMessageFactory::RegisterFile(
|
||||
const char* file, RegistrationFunc* registration_func) {
|
||||
if (!InsertIfNotPresent(&file_map_, file, registration_func)) {
|
||||
GOOGLE_LOG(FATAL) << "File is already registered: " << file;
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
|
||||
const Message* prototype) {
|
||||
GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
|
||||
<< "Tried to register a non-generated type with the generated "
|
||||
"type registry.";
|
||||
|
||||
// This should only be called as a result of calling a file registration
|
||||
// function during GetPrototype(), in which case we already have locked
|
||||
// the mutex.
|
||||
mutex_.AssertHeld();
|
||||
if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
|
||||
GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
{
|
||||
ReaderMutexLock lock(&mutex_);
|
||||
const Message* result = FindPtrOrNull(type_map_, type);
|
||||
if (result != NULL) return result;
|
||||
}
|
||||
|
||||
// If the type is not in the generated pool, then we can't possibly handle
|
||||
// it.
|
||||
if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL;
|
||||
|
||||
// Apparently the file hasn't been registered yet. Let's do that now.
|
||||
RegistrationFunc* registration_func =
|
||||
FindPtrOrNull(file_map_, type->file()->name().c_str());
|
||||
if (registration_func == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
|
||||
"registered: " << type->file()->name();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WriterMutexLock lock(&mutex_);
|
||||
|
||||
// Check if another thread preempted us.
|
||||
const Message* result = FindPtrOrNull(type_map_, type);
|
||||
if (result == NULL) {
|
||||
// Nope. OK, register everything.
|
||||
registration_func(type->file()->name());
|
||||
// Should be here now.
|
||||
result = FindPtrOrNull(type_map_, type);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
|
||||
<< "registered: " << type->full_name();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MessageFactory* MessageFactory::generated_factory() {
|
||||
return GeneratedMessageFactory::singleton();
|
||||
}
|
||||
|
||||
void MessageFactory::InternalRegisterGeneratedFile(
|
||||
const char* filename, void (*register_messages)(const string&)) {
|
||||
GeneratedMessageFactory::singleton()->RegisterFile(filename,
|
||||
register_messages);
|
||||
}
|
||||
|
||||
void MessageFactory::InternalRegisterGeneratedMessage(
|
||||
const Descriptor* descriptor, const Message* prototype) {
|
||||
GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
|
||||
}
|
||||
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,866 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines Message, the abstract interface implemented by non-lite
|
||||
// protocol message objects. Although it's possible to implement this
|
||||
// interface manually, most users will use the protocol compiler to
|
||||
// generate implementations.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// Say you have a message defined as:
|
||||
//
|
||||
// message Foo {
|
||||
// optional string text = 1;
|
||||
// repeated int32 numbers = 2;
|
||||
// }
|
||||
//
|
||||
// Then, if you used the protocol compiler to generate a class from the above
|
||||
// definition, you could use it like so:
|
||||
//
|
||||
// string data; // Will store a serialized version of the message.
|
||||
//
|
||||
// {
|
||||
// // Create a message and serialize it.
|
||||
// Foo foo;
|
||||
// foo.set_text("Hello World!");
|
||||
// foo.add_numbers(1);
|
||||
// foo.add_numbers(5);
|
||||
// foo.add_numbers(42);
|
||||
//
|
||||
// foo.SerializeToString(&data);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// // Parse the serialized message and check that it contains the
|
||||
// // correct data.
|
||||
// Foo foo;
|
||||
// foo.ParseFromString(data);
|
||||
//
|
||||
// assert(foo.text() == "Hello World!");
|
||||
// assert(foo.numbers_size() == 3);
|
||||
// assert(foo.numbers(0) == 1);
|
||||
// assert(foo.numbers(1) == 5);
|
||||
// assert(foo.numbers(2) == 42);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// // Same as the last block, but do it dynamically via the Message
|
||||
// // reflection interface.
|
||||
// Message* foo = new Foo;
|
||||
// const Descriptor* descriptor = foo->GetDescriptor();
|
||||
//
|
||||
// // Get the descriptors for the fields we're interested in and verify
|
||||
// // their types.
|
||||
// const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
|
||||
// assert(text_field != NULL);
|
||||
// assert(text_field->type() == FieldDescriptor::TYPE_STRING);
|
||||
// assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
|
||||
// const FieldDescriptor* numbers_field = descriptor->
|
||||
// FindFieldByName("numbers");
|
||||
// assert(numbers_field != NULL);
|
||||
// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
|
||||
// assert(numbers_field->label() == FieldDescriptor::LABEL_REPEATED);
|
||||
//
|
||||
// // Parse the message.
|
||||
// foo->ParseFromString(data);
|
||||
//
|
||||
// // Use the reflection interface to examine the contents.
|
||||
// const Reflection* reflection = foo->GetReflection();
|
||||
// assert(reflection->GetString(foo, text_field) == "Hello World!");
|
||||
// assert(reflection->FieldSize(foo, numbers_field) == 3);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42);
|
||||
//
|
||||
// delete foo;
|
||||
// }
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/message_lite.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
|
||||
#define GOOGLE_PROTOBUF_HAS_ONEOF
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class Message;
|
||||
class Reflection;
|
||||
class MessageFactory;
|
||||
|
||||
// Defined in other files.
|
||||
class UnknownFieldSet; // unknown_field_set.h
|
||||
namespace io {
|
||||
class ZeroCopyInputStream; // zero_copy_stream.h
|
||||
class ZeroCopyOutputStream; // zero_copy_stream.h
|
||||
class CodedInputStream; // coded_stream.h
|
||||
class CodedOutputStream; // coded_stream.h
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class RepeatedField; // repeated_field.h
|
||||
|
||||
template<typename T>
|
||||
class RepeatedPtrField; // repeated_field.h
|
||||
|
||||
// A container to hold message metadata.
|
||||
struct Metadata {
|
||||
const Descriptor* descriptor;
|
||||
const Reflection* reflection;
|
||||
};
|
||||
|
||||
// Abstract interface for protocol messages.
|
||||
//
|
||||
// See also MessageLite, which contains most every-day operations. Message
|
||||
// adds descriptors and reflection on top of that.
|
||||
//
|
||||
// The methods of this class that are virtual but not pure-virtual have
|
||||
// default implementations based on reflection. Message classes which are
|
||||
// optimized for speed will want to override these with faster implementations,
|
||||
// but classes optimized for code size may be happy with keeping them. See
|
||||
// the optimize_for option in descriptor.proto.
|
||||
class LIBPROTOBUF_EXPORT Message : public MessageLite {
|
||||
public:
|
||||
inline Message() {}
|
||||
virtual ~Message();
|
||||
|
||||
// Basic Operations ------------------------------------------------
|
||||
|
||||
// Construct a new instance of the same type. Ownership is passed to the
|
||||
// caller. (This is also defined in MessageLite, but is defined again here
|
||||
// for return-type covariance.)
|
||||
virtual Message* New() const = 0;
|
||||
|
||||
// Make this message into a copy of the given message. The given message
|
||||
// must have the same descriptor, but need not necessarily be the same class.
|
||||
// By default this is just implemented as "Clear(); MergeFrom(from);".
|
||||
virtual void CopyFrom(const Message& from);
|
||||
|
||||
// Merge the fields from the given message into this message. Singular
|
||||
// fields will be overwritten, if specified in from, except for embedded
|
||||
// messages which will be merged. Repeated fields will be concatenated.
|
||||
// The given message must be of the same type as this message (i.e. the
|
||||
// exact same class).
|
||||
virtual void MergeFrom(const Message& from);
|
||||
|
||||
// Verifies that IsInitialized() returns true. GOOGLE_CHECK-fails otherwise, with
|
||||
// a nice error message.
|
||||
void CheckInitialized() const;
|
||||
|
||||
// Slowly build a list of all required fields that are not set.
|
||||
// This is much, much slower than IsInitialized() as it is implemented
|
||||
// purely via reflection. Generally, you should not call this unless you
|
||||
// have already determined that an error exists by calling IsInitialized().
|
||||
void FindInitializationErrors(vector<string>* errors) const;
|
||||
|
||||
// Like FindInitializationErrors, but joins all the strings, delimited by
|
||||
// commas, and returns them.
|
||||
string InitializationErrorString() const;
|
||||
|
||||
// Clears all unknown fields from this message and all embedded messages.
|
||||
// Normally, if unknown tag numbers are encountered when parsing a message,
|
||||
// the tag and value are stored in the message's UnknownFieldSet and
|
||||
// then written back out when the message is serialized. This allows servers
|
||||
// which simply route messages to other servers to pass through messages
|
||||
// that have new field definitions which they don't yet know about. However,
|
||||
// this behavior can have security implications. To avoid it, call this
|
||||
// method after parsing.
|
||||
//
|
||||
// See Reflection::GetUnknownFields() for more on unknown fields.
|
||||
virtual void DiscardUnknownFields();
|
||||
|
||||
// Computes (an estimate of) the total number of bytes currently used for
|
||||
// storing the message in memory. The default implementation calls the
|
||||
// Reflection object's SpaceUsed() method.
|
||||
virtual int SpaceUsed() const;
|
||||
|
||||
// Debugging & Testing----------------------------------------------
|
||||
|
||||
// Generates a human readable form of this message, useful for debugging
|
||||
// and other purposes.
|
||||
string DebugString() const;
|
||||
// Like DebugString(), but with less whitespace.
|
||||
string ShortDebugString() const;
|
||||
// Like DebugString(), but do not escape UTF-8 byte sequences.
|
||||
string Utf8DebugString() const;
|
||||
// Convenience function useful in GDB. Prints DebugString() to stdout.
|
||||
void PrintDebugString() const;
|
||||
|
||||
// Heavy I/O -------------------------------------------------------
|
||||
// Additional parsing and serialization methods not implemented by
|
||||
// MessageLite because they are not supported by the lite library.
|
||||
|
||||
// Parse a protocol buffer from a file descriptor. If successful, the entire
|
||||
// input will be consumed.
|
||||
bool ParseFromFileDescriptor(int file_descriptor);
|
||||
// Like ParseFromFileDescriptor(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromFileDescriptor(int file_descriptor);
|
||||
// Parse a protocol buffer from a C++ istream. If successful, the entire
|
||||
// input will be consumed.
|
||||
bool ParseFromIstream(istream* input);
|
||||
// Like ParseFromIstream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromIstream(istream* input);
|
||||
|
||||
// Serialize the message and write it to the given file descriptor. All
|
||||
// required fields must be set.
|
||||
bool SerializeToFileDescriptor(int file_descriptor) const;
|
||||
// Like SerializeToFileDescriptor(), but allows missing required fields.
|
||||
bool SerializePartialToFileDescriptor(int file_descriptor) const;
|
||||
// Serialize the message and write it to the given C++ ostream. All
|
||||
// required fields must be set.
|
||||
bool SerializeToOstream(ostream* output) const;
|
||||
// Like SerializeToOstream(), but allows missing required fields.
|
||||
bool SerializePartialToOstream(ostream* output) const;
|
||||
|
||||
|
||||
// Reflection-based methods ----------------------------------------
|
||||
// These methods are pure-virtual in MessageLite, but Message provides
|
||||
// reflection-based default implementations.
|
||||
|
||||
virtual string GetTypeName() const;
|
||||
virtual void Clear();
|
||||
virtual bool IsInitialized() const;
|
||||
virtual void CheckTypeAndMergeFrom(const MessageLite& other);
|
||||
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input);
|
||||
virtual int ByteSize() const;
|
||||
virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const;
|
||||
|
||||
private:
|
||||
// This is called only by the default implementation of ByteSize(), to
|
||||
// update the cached size. If you override ByteSize(), you do not need
|
||||
// to override this. If you do not override ByteSize(), you MUST override
|
||||
// this; the default implementation will crash.
|
||||
//
|
||||
// The method is private because subclasses should never call it; only
|
||||
// override it. Yes, C++ lets you do that. Crazy, huh?
|
||||
virtual void SetCachedSize(int size) const;
|
||||
|
||||
public:
|
||||
|
||||
// Introspection ---------------------------------------------------
|
||||
|
||||
// Typedef for backwards-compatibility.
|
||||
typedef google::protobuf::Reflection Reflection;
|
||||
|
||||
// Get a Descriptor for this message's type. This describes what
|
||||
// fields the message contains, the types of those fields, etc.
|
||||
const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; }
|
||||
|
||||
// Get the Reflection interface for this Message, which can be used to
|
||||
// read and modify the fields of the Message dynamically (in other words,
|
||||
// without knowing the message type at compile time). This object remains
|
||||
// property of the Message.
|
||||
//
|
||||
// This method remains virtual in case a subclass does not implement
|
||||
// reflection and wants to override the default behavior.
|
||||
virtual const Reflection* GetReflection() const {
|
||||
return GetMetadata().reflection;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Get a struct containing the metadata for the Message. Most subclasses only
|
||||
// need to implement this method, rather than the GetDescriptor() and
|
||||
// GetReflection() wrappers.
|
||||
virtual Metadata GetMetadata() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
|
||||
};
|
||||
|
||||
// This interface contains methods that can be used to dynamically access
|
||||
// and modify the fields of a protocol message. Their semantics are
|
||||
// similar to the accessors the protocol compiler generates.
|
||||
//
|
||||
// To get the Reflection for a given Message, call Message::GetReflection().
|
||||
//
|
||||
// This interface is separate from Message only for efficiency reasons;
|
||||
// the vast majority of implementations of Message will share the same
|
||||
// implementation of Reflection (GeneratedMessageReflection,
|
||||
// defined in generated_message.h), and all Messages of a particular class
|
||||
// should share the same Reflection object (though you should not rely on
|
||||
// the latter fact).
|
||||
//
|
||||
// There are several ways that these methods can be used incorrectly. For
|
||||
// example, any of the following conditions will lead to undefined
|
||||
// results (probably assertion failures):
|
||||
// - The FieldDescriptor is not a field of this message type.
|
||||
// - The method called is not appropriate for the field's type. For
|
||||
// each field type in FieldDescriptor::TYPE_*, there is only one
|
||||
// Get*() method, one Set*() method, and one Add*() method that is
|
||||
// valid for that type. It should be obvious which (except maybe
|
||||
// for TYPE_BYTES, which are represented using strings in C++).
|
||||
// - A Get*() or Set*() method for singular fields is called on a repeated
|
||||
// field.
|
||||
// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated
|
||||
// field.
|
||||
// - The Message object passed to any method is not of the right type for
|
||||
// this Reflection object (i.e. message.GetReflection() != reflection).
|
||||
//
|
||||
// You might wonder why there is not any abstract representation for a field
|
||||
// of arbitrary type. E.g., why isn't there just a "GetField()" method that
|
||||
// returns "const Field&", where "Field" is some class with accessors like
|
||||
// "GetInt32Value()". The problem is that someone would have to deal with
|
||||
// allocating these Field objects. For generated message classes, having to
|
||||
// allocate space for an additional object to wrap every field would at least
|
||||
// double the message's memory footprint, probably worse. Allocating the
|
||||
// objects on-demand, on the other hand, would be expensive and prone to
|
||||
// memory leaks. So, instead we ended up with this flat interface.
|
||||
//
|
||||
// TODO(kenton): Create a utility class which callers can use to read and
|
||||
// write fields from a Reflection without paying attention to the type.
|
||||
class LIBPROTOBUF_EXPORT Reflection {
|
||||
public:
|
||||
inline Reflection() {}
|
||||
virtual ~Reflection();
|
||||
|
||||
// Get the UnknownFieldSet for the message. This contains fields which
|
||||
// were seen when the Message was parsed but were not recognized according
|
||||
// to the Message's definition.
|
||||
virtual const UnknownFieldSet& GetUnknownFields(
|
||||
const Message& message) const = 0;
|
||||
// Get a mutable pointer to the UnknownFieldSet for the message. This
|
||||
// contains fields which were seen when the Message was parsed but were not
|
||||
// recognized according to the Message's definition.
|
||||
virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0;
|
||||
|
||||
// Estimate the amount of memory used by the message object.
|
||||
virtual int SpaceUsed(const Message& message) const = 0;
|
||||
|
||||
// Check if the given non-repeated field is set.
|
||||
virtual bool HasField(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Get the number of elements of a repeated field.
|
||||
virtual int FieldSize(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Clear the value of a field, so that HasField() returns false or
|
||||
// FieldSize() returns zero.
|
||||
virtual void ClearField(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Check if the oneof is set. Returns ture if any field in oneof
|
||||
// is set, false otherwise.
|
||||
// TODO(jieluo) - make it pure virtual after updating all
|
||||
// the subclasses.
|
||||
virtual bool HasOneof(const Message& message,
|
||||
const OneofDescriptor* oneof_descriptor) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void ClearOneof(Message* message,
|
||||
const OneofDescriptor* oneof_descriptor) const {}
|
||||
|
||||
// Returns the field descriptor if the oneof is set. NULL otherwise.
|
||||
// TODO(jieluo) - make it pure virtual.
|
||||
virtual const FieldDescriptor* GetOneofFieldDescriptor(
|
||||
const Message& message,
|
||||
const OneofDescriptor* oneof_descriptor) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Removes the last element of a repeated field.
|
||||
// We don't provide a way to remove any element other than the last
|
||||
// because it invites inefficient use, such as O(n^2) filtering loops
|
||||
// that should have been O(n). If you want to remove an element other
|
||||
// than the last, the best way to do it is to re-arrange the elements
|
||||
// (using Swap()) so that the one you want removed is at the end, then
|
||||
// call RemoveLast().
|
||||
virtual void RemoveLast(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
// Removes the last element of a repeated message field, and returns the
|
||||
// pointer to the caller. Caller takes ownership of the returned pointer.
|
||||
virtual Message* ReleaseLast(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Swap the complete contents of two messages.
|
||||
virtual void Swap(Message* message1, Message* message2) const = 0;
|
||||
|
||||
// Swap fields listed in fields vector of two messages.
|
||||
virtual void SwapFields(Message* message1,
|
||||
Message* message2,
|
||||
const vector<const FieldDescriptor*>& fields)
|
||||
const = 0;
|
||||
|
||||
// Swap two elements of a repeated field.
|
||||
virtual void SwapElements(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index1,
|
||||
int index2) const = 0;
|
||||
|
||||
// List all fields of the message which are currently set. This includes
|
||||
// extensions. Singular fields will only be listed if HasField(field) would
|
||||
// return true and repeated fields will only be listed if FieldSize(field)
|
||||
// would return non-zero. Fields (both normal fields and extension fields)
|
||||
// will be listed ordered by field number.
|
||||
virtual void ListFields(const Message& message,
|
||||
vector<const FieldDescriptor*>* output) const = 0;
|
||||
|
||||
// Singular field getters ------------------------------------------
|
||||
// These get the value of a non-repeated field. They return the default
|
||||
// value for fields that aren't set.
|
||||
|
||||
virtual int32 GetInt32 (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual int64 GetInt64 (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual uint32 GetUInt32(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual uint64 GetUInt64(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual float GetFloat (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual double GetDouble(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual bool GetBool (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual string GetString(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual const EnumValueDescriptor* GetEnum(
|
||||
const Message& message, const FieldDescriptor* field) const = 0;
|
||||
// See MutableMessage() for the meaning of the "factory" parameter.
|
||||
virtual const Message& GetMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
// Get a string value without copying, if possible.
|
||||
//
|
||||
// GetString() necessarily returns a copy of the string. This can be
|
||||
// inefficient when the string is already stored in a string object in the
|
||||
// underlying message. GetStringReference() will return a reference to the
|
||||
// underlying string in this case. Otherwise, it will copy the string into
|
||||
// *scratch and return that.
|
||||
//
|
||||
// Note: It is perfectly reasonable and useful to write code like:
|
||||
// str = reflection->GetStringReference(field, &str);
|
||||
// This line would ensure that only one copy of the string is made
|
||||
// regardless of the field's underlying representation. When initializing
|
||||
// a newly-constructed string, though, it's just as fast and more readable
|
||||
// to use code like:
|
||||
// string str = reflection->GetString(field);
|
||||
virtual const string& GetStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
string* scratch) const = 0;
|
||||
|
||||
|
||||
// Singular field mutators -----------------------------------------
|
||||
// These mutate the value of a non-repeated field.
|
||||
|
||||
virtual void SetInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const = 0;
|
||||
virtual void SetInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const = 0;
|
||||
virtual void SetUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const = 0;
|
||||
virtual void SetUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const = 0;
|
||||
virtual void SetFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const = 0;
|
||||
virtual void SetDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const = 0;
|
||||
virtual void SetBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const = 0;
|
||||
virtual void SetString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const = 0;
|
||||
virtual void SetEnum (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// Get a mutable pointer to a field with a message type. If a MessageFactory
|
||||
// is provided, it will be used to construct instances of the sub-message;
|
||||
// otherwise, the default factory is used. If the field is an extension that
|
||||
// does not live in the same pool as the containing message's descriptor (e.g.
|
||||
// it lives in an overlay pool), then a MessageFactory must be provided.
|
||||
// If you have no idea what that meant, then you probably don't need to worry
|
||||
// about it (don't provide a MessageFactory). WARNING: If the
|
||||
// FieldDescriptor is for a compiled-in extension, then
|
||||
// factory->GetPrototype(field->message_type() MUST return an instance of the
|
||||
// compiled-in class for this type, NOT DynamicMessage.
|
||||
virtual Message* MutableMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
// Replaces the message specified by 'field' with the already-allocated object
|
||||
// sub_message, passing ownership to the message. If the field contained a
|
||||
// message, that message is deleted. If sub_message is NULL, the field is
|
||||
// cleared.
|
||||
virtual void SetAllocatedMessage(Message* message,
|
||||
Message* sub_message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
// Releases the message specified by 'field' and returns the pointer,
|
||||
// ReleaseMessage() will return the message the message object if it exists.
|
||||
// Otherwise, it may or may not return NULL. In any case, if the return value
|
||||
// is non-NULL, the caller takes ownership of the pointer.
|
||||
// If the field existed (HasField() is true), then the returned pointer will
|
||||
// be the same as the pointer returned by MutableMessage().
|
||||
// This function has the same effect as ClearField().
|
||||
virtual Message* ReleaseMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
|
||||
// Repeated field getters ------------------------------------------
|
||||
// These get the value of one element of a repeated field.
|
||||
|
||||
virtual int32 GetRepeatedInt32 (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual int64 GetRepeatedInt64 (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual uint32 GetRepeatedUInt32(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual uint64 GetRepeatedUInt64(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual float GetRepeatedFloat (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual double GetRepeatedDouble(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual bool GetRepeatedBool (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual string GetRepeatedString(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual const EnumValueDescriptor* GetRepeatedEnum(
|
||||
const Message& message,
|
||||
const FieldDescriptor* field, int index) const = 0;
|
||||
virtual const Message& GetRepeatedMessage(
|
||||
const Message& message,
|
||||
const FieldDescriptor* field, int index) const = 0;
|
||||
|
||||
// See GetStringReference(), above.
|
||||
virtual const string& GetRepeatedStringReference(
|
||||
const Message& message, const FieldDescriptor* field,
|
||||
int index, string* scratch) const = 0;
|
||||
|
||||
|
||||
// Repeated field mutators -----------------------------------------
|
||||
// These mutate the value of one element of a repeated field.
|
||||
|
||||
virtual void SetRepeatedInt32 (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, int32 value) const = 0;
|
||||
virtual void SetRepeatedInt64 (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, int64 value) const = 0;
|
||||
virtual void SetRepeatedUInt32(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, uint32 value) const = 0;
|
||||
virtual void SetRepeatedUInt64(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, uint64 value) const = 0;
|
||||
virtual void SetRepeatedFloat (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, float value) const = 0;
|
||||
virtual void SetRepeatedDouble(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, double value) const = 0;
|
||||
virtual void SetRepeatedBool (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, bool value) const = 0;
|
||||
virtual void SetRepeatedString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, const string& value) const = 0;
|
||||
virtual void SetRepeatedEnum(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// Get a mutable pointer to an element of a repeated field with a message
|
||||
// type.
|
||||
virtual Message* MutableRepeatedMessage(
|
||||
Message* message, const FieldDescriptor* field, int index) const = 0;
|
||||
|
||||
|
||||
// Repeated field adders -------------------------------------------
|
||||
// These add an element to a repeated field.
|
||||
|
||||
virtual void AddInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const = 0;
|
||||
virtual void AddInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const = 0;
|
||||
virtual void AddUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const = 0;
|
||||
virtual void AddUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const = 0;
|
||||
virtual void AddFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const = 0;
|
||||
virtual void AddDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const = 0;
|
||||
virtual void AddBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const = 0;
|
||||
virtual void AddString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const = 0;
|
||||
virtual void AddEnum (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// See MutableMessage() for comments on the "factory" parameter.
|
||||
virtual Message* AddMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
|
||||
// Repeated field accessors -------------------------------------------------
|
||||
// The methods above, e.g. GetRepeatedInt32(msg, fd, index), provide singular
|
||||
// access to the data in a RepeatedField. The methods below provide aggregate
|
||||
// access by exposing the RepeatedField object itself with the Message.
|
||||
// Applying these templates to inappropriate types will lead to an undefined
|
||||
// reference at link time (e.g. GetRepeatedField<***double>), or possibly a
|
||||
// template matching error at compile time (e.g. GetRepeatedPtrField<File>).
|
||||
//
|
||||
// Usage example: my_doubs = refl->GetRepeatedField<double>(msg, fd);
|
||||
|
||||
// for T = Cord and all protobuf scalar types except enums.
|
||||
template<typename T>
|
||||
const RepeatedField<T>& GetRepeatedField(
|
||||
const Message&, const FieldDescriptor*) const;
|
||||
|
||||
// for T = Cord and all protobuf scalar types except enums.
|
||||
template<typename T>
|
||||
RepeatedField<T>* MutableRepeatedField(
|
||||
Message*, const FieldDescriptor*) const;
|
||||
|
||||
// for T = string, google::protobuf::internal::StringPieceField
|
||||
// google::protobuf::Message & descendants.
|
||||
template<typename T>
|
||||
const RepeatedPtrField<T>& GetRepeatedPtrField(
|
||||
const Message&, const FieldDescriptor*) const;
|
||||
|
||||
// for T = string, google::protobuf::internal::StringPieceField
|
||||
// google::protobuf::Message & descendants.
|
||||
template<typename T>
|
||||
RepeatedPtrField<T>* MutableRepeatedPtrField(
|
||||
Message*, const FieldDescriptor*) const;
|
||||
|
||||
// Extensions ----------------------------------------------------------------
|
||||
|
||||
// Try to find an extension of this message type by fully-qualified field
|
||||
// name. Returns NULL if no extension is known for this name or number.
|
||||
virtual const FieldDescriptor* FindKnownExtensionByName(
|
||||
const string& name) const = 0;
|
||||
|
||||
// Try to find an extension of this message type by field number.
|
||||
// Returns NULL if no extension is known for this name or number.
|
||||
virtual const FieldDescriptor* FindKnownExtensionByNumber(
|
||||
int number) const = 0;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
// Obtain a pointer to a Repeated Field Structure and do some type checking:
|
||||
// on field->cpp_type(),
|
||||
// on field->field_option().ctype() (if ctype >= 0)
|
||||
// of field->message_type() (if message_type != NULL).
|
||||
// We use 1 routine rather than 4 (const vs mutable) x (scalar vs pointer).
|
||||
virtual void* MutableRawRepeatedField(
|
||||
Message* message, const FieldDescriptor* field, FieldDescriptor::CppType,
|
||||
int ctype, const Descriptor* message_type) const = 0;
|
||||
|
||||
private:
|
||||
// Special version for specialized implementations of string. We can't call
|
||||
// MutableRawRepeatedField directly here because we don't have access to
|
||||
// FieldOptions::* which are defined in descriptor.pb.h. Including that
|
||||
// file here is not possible because it would cause a circular include cycle.
|
||||
void* MutableRawRepeatedString(
|
||||
Message* message, const FieldDescriptor* field, bool is_string) const;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
|
||||
};
|
||||
|
||||
// Abstract interface for a factory for message objects.
|
||||
class LIBPROTOBUF_EXPORT MessageFactory {
|
||||
public:
|
||||
inline MessageFactory() {}
|
||||
virtual ~MessageFactory();
|
||||
|
||||
// Given a Descriptor, gets or constructs the default (prototype) Message
|
||||
// of that type. You can then call that message's New() method to construct
|
||||
// a mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory. Also, any
|
||||
// objects created by calling the prototype's New() method share some data
|
||||
// with the prototype, so these must be destroyed before the MessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the MessageFactory.
|
||||
//
|
||||
// Some implementations do not support all types. GetPrototype() will
|
||||
// return NULL if the descriptor passed in is not supported.
|
||||
//
|
||||
// This method may or may not be thread-safe depending on the implementation.
|
||||
// Each implementation should document its own degree thread-safety.
|
||||
virtual const Message* GetPrototype(const Descriptor* type) = 0;
|
||||
|
||||
// Gets a MessageFactory which supports all generated, compiled-in messages.
|
||||
// In other words, for any compiled-in type FooMessage, the following is true:
|
||||
// MessageFactory::generated_factory()->GetPrototype(
|
||||
// FooMessage::descriptor()) == FooMessage::default_instance()
|
||||
// This factory supports all types which are found in
|
||||
// DescriptorPool::generated_pool(). If given a descriptor from any other
|
||||
// pool, GetPrototype() will return NULL. (You can also check if a
|
||||
// descriptor is for a generated message by checking if
|
||||
// descriptor->file()->pool() == DescriptorPool::generated_pool().)
|
||||
//
|
||||
// This factory is 100% thread-safe; calling GetPrototype() does not modify
|
||||
// any shared data.
|
||||
//
|
||||
// This factory is a singleton. The caller must not delete the object.
|
||||
static MessageFactory* generated_factory();
|
||||
|
||||
// For internal use only: Registers a .proto file at static initialization
|
||||
// time, to be placed in generated_factory. The first time GetPrototype()
|
||||
// is called with a descriptor from this file, |register_messages| will be
|
||||
// called, with the file name as the parameter. It must call
|
||||
// InternalRegisterGeneratedMessage() (below) to register each message type
|
||||
// in the file. This strange mechanism is necessary because descriptors are
|
||||
// built lazily, so we can't register types by their descriptor until we
|
||||
// know that the descriptor exists. |filename| must be a permanent string.
|
||||
static void InternalRegisterGeneratedFile(
|
||||
const char* filename, void (*register_messages)(const string&));
|
||||
|
||||
// For internal use only: Registers a message type. Called only by the
|
||||
// functions which are registered with InternalRegisterGeneratedFile(),
|
||||
// above.
|
||||
static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
|
||||
const Message* prototype);
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
|
||||
};
|
||||
|
||||
#define DECLARE_GET_REPEATED_FIELD(TYPE) \
|
||||
template<> \
|
||||
LIBPROTOBUF_EXPORT \
|
||||
const RepeatedField<TYPE>& Reflection::GetRepeatedField<TYPE>( \
|
||||
const Message& message, const FieldDescriptor* field) const; \
|
||||
\
|
||||
template<> \
|
||||
RepeatedField<TYPE>* Reflection::MutableRepeatedField<TYPE>( \
|
||||
Message* message, const FieldDescriptor* field) const;
|
||||
|
||||
DECLARE_GET_REPEATED_FIELD(int32)
|
||||
DECLARE_GET_REPEATED_FIELD(int64)
|
||||
DECLARE_GET_REPEATED_FIELD(uint32)
|
||||
DECLARE_GET_REPEATED_FIELD(uint64)
|
||||
DECLARE_GET_REPEATED_FIELD(float)
|
||||
DECLARE_GET_REPEATED_FIELD(double)
|
||||
DECLARE_GET_REPEATED_FIELD(bool)
|
||||
|
||||
#undef DECLARE_GET_REPEATED_FIELD
|
||||
|
||||
// =============================================================================
|
||||
// Implementation details for {Get,Mutable}RawRepeatedPtrField. We provide
|
||||
// specializations for <string>, <StringPieceField> and <Message> and handle
|
||||
// everything else with the default template which will match any type having
|
||||
// a method with signature "static const google::protobuf::Descriptor* descriptor()".
|
||||
// Such a type presumably is a descendant of google::protobuf::Message.
|
||||
|
||||
template<>
|
||||
inline const RepeatedPtrField<string>& Reflection::GetRepeatedPtrField<string>(
|
||||
const Message& message, const FieldDescriptor* field) const {
|
||||
return *static_cast<RepeatedPtrField<string>* >(
|
||||
MutableRawRepeatedString(const_cast<Message*>(&message), field, true));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline RepeatedPtrField<string>* Reflection::MutableRepeatedPtrField<string>(
|
||||
Message* message, const FieldDescriptor* field) const {
|
||||
return static_cast<RepeatedPtrField<string>* >(
|
||||
MutableRawRepeatedString(message, field, true));
|
||||
}
|
||||
|
||||
|
||||
// -----
|
||||
|
||||
template<>
|
||||
inline const RepeatedPtrField<Message>& Reflection::GetRepeatedPtrField(
|
||||
const Message& message, const FieldDescriptor* field) const {
|
||||
return *static_cast<RepeatedPtrField<Message>* >(
|
||||
MutableRawRepeatedField(const_cast<Message*>(&message), field,
|
||||
FieldDescriptor::CPPTYPE_MESSAGE, -1,
|
||||
NULL));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline RepeatedPtrField<Message>* Reflection::MutableRepeatedPtrField(
|
||||
Message* message, const FieldDescriptor* field) const {
|
||||
return static_cast<RepeatedPtrField<Message>* >(
|
||||
MutableRawRepeatedField(message, field,
|
||||
FieldDescriptor::CPPTYPE_MESSAGE, -1,
|
||||
NULL));
|
||||
}
|
||||
|
||||
template<typename PB>
|
||||
inline const RepeatedPtrField<PB>& Reflection::GetRepeatedPtrField(
|
||||
const Message& message, const FieldDescriptor* field) const {
|
||||
return *static_cast<RepeatedPtrField<PB>* >(
|
||||
MutableRawRepeatedField(const_cast<Message*>(&message), field,
|
||||
FieldDescriptor::CPPTYPE_MESSAGE, -1,
|
||||
PB::default_instance().GetDescriptor()));
|
||||
}
|
||||
|
||||
template<typename PB>
|
||||
inline RepeatedPtrField<PB>* Reflection::MutableRepeatedPtrField(
|
||||
Message* message, const FieldDescriptor* field) const {
|
||||
return static_cast<RepeatedPtrField<PB>* >(
|
||||
MutableRawRepeatedField(message, field,
|
||||
FieldDescriptor::CPPTYPE_MESSAGE, -1,
|
||||
PB::default_instance().GetDescriptor()));
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MESSAGE_H__
|
|
@ -1,269 +0,0 @@
|
|||
// 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
void ReflectionOps::Copy(const Message& from, Message* to) {
|
||||
if (&from == to) return;
|
||||
Clear(to);
|
||||
Merge(from, to);
|
||||
}
|
||||
|
||||
void ReflectionOps::Merge(const Message& from, Message* to) {
|
||||
GOOGLE_CHECK_NE(&from, to);
|
||||
|
||||
const Descriptor* descriptor = from.GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
|
||||
<< "Tried to merge messages of different types "
|
||||
<< "(merge " << descriptor->full_name()
|
||||
<< " to " << to->GetDescriptor()->full_name() << ")";
|
||||
|
||||
const Reflection* from_reflection = from.GetReflection();
|
||||
const Reflection* to_reflection = to->GetReflection();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
from_reflection->ListFields(from, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int count = from_reflection->FieldSize(from, field);
|
||||
for (int j = 0; j < count; j++) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
to_reflection->Add##METHOD(to, field, \
|
||||
from_reflection->GetRepeated##METHOD(from, field, j)); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , Int32 );
|
||||
HANDLE_TYPE(INT64 , Int64 );
|
||||
HANDLE_TYPE(UINT32, UInt32);
|
||||
HANDLE_TYPE(UINT64, UInt64);
|
||||
HANDLE_TYPE(FLOAT , Float );
|
||||
HANDLE_TYPE(DOUBLE, Double);
|
||||
HANDLE_TYPE(BOOL , Bool );
|
||||
HANDLE_TYPE(STRING, String);
|
||||
HANDLE_TYPE(ENUM , Enum );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
to_reflection->AddMessage(to, field)->MergeFrom(
|
||||
from_reflection->GetRepeatedMessage(from, field, j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
to_reflection->Set##METHOD(to, field, \
|
||||
from_reflection->Get##METHOD(from, field)); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , Int32 );
|
||||
HANDLE_TYPE(INT64 , Int64 );
|
||||
HANDLE_TYPE(UINT32, UInt32);
|
||||
HANDLE_TYPE(UINT64, UInt64);
|
||||
HANDLE_TYPE(FLOAT , Float );
|
||||
HANDLE_TYPE(DOUBLE, Double);
|
||||
HANDLE_TYPE(BOOL , Bool );
|
||||
HANDLE_TYPE(STRING, String);
|
||||
HANDLE_TYPE(ENUM , Enum );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
to_reflection->MutableMessage(to, field)->MergeFrom(
|
||||
from_reflection->GetMessage(from, field));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_reflection->MutableUnknownFields(to)->MergeFrom(
|
||||
from_reflection->GetUnknownFields(from));
|
||||
}
|
||||
|
||||
void ReflectionOps::Clear(Message* message) {
|
||||
const Reflection* reflection = message->GetReflection();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(*message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
reflection->ClearField(message, fields[i]);
|
||||
}
|
||||
|
||||
reflection->MutableUnknownFields(message)->Clear();
|
||||
}
|
||||
|
||||
bool ReflectionOps::IsInitialized(const Message& message) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Check required fields of this message.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
if (descriptor->field(i)->is_required()) {
|
||||
if (!reflection->HasField(message, descriptor->field(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that sub-messages are initialized.
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(message, field);
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (!reflection->GetRepeatedMessage(message, field, j)
|
||||
.IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!reflection->GetMessage(message, field).IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReflectionOps::DiscardUnknownFields(Message* message) {
|
||||
const Reflection* reflection = message->GetReflection();
|
||||
|
||||
reflection->MutableUnknownFields(message)->Clear();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(*message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(*message, field);
|
||||
for (int j = 0; j < size; j++) {
|
||||
reflection->MutableRepeatedMessage(message, field, j)
|
||||
->DiscardUnknownFields();
|
||||
}
|
||||
} else {
|
||||
reflection->MutableMessage(message, field)->DiscardUnknownFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string SubMessagePrefix(const string& prefix,
|
||||
const FieldDescriptor* field,
|
||||
int index) {
|
||||
string result(prefix);
|
||||
if (field->is_extension()) {
|
||||
result.append("(");
|
||||
result.append(field->full_name());
|
||||
result.append(")");
|
||||
} else {
|
||||
result.append(field->name());
|
||||
}
|
||||
if (index != -1) {
|
||||
result.append("[");
|
||||
result.append(SimpleItoa(index));
|
||||
result.append("]");
|
||||
}
|
||||
result.append(".");
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReflectionOps::FindInitializationErrors(
|
||||
const Message& message,
|
||||
const string& prefix,
|
||||
vector<string>* errors) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Check required fields of this message.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
if (descriptor->field(i)->is_required()) {
|
||||
if (!reflection->HasField(message, descriptor->field(i))) {
|
||||
errors->push_back(prefix + descriptor->field(i)->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check sub-messages.
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(message, field);
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
const Message& sub_message =
|
||||
reflection->GetRepeatedMessage(message, field, j);
|
||||
FindInitializationErrors(sub_message,
|
||||
SubMessagePrefix(prefix, field, j),
|
||||
errors);
|
||||
}
|
||||
} else {
|
||||
const Message& sub_message = reflection->GetMessage(message, field);
|
||||
FindInitializationErrors(sub_message,
|
||||
SubMessagePrefix(prefix, field, -1),
|
||||
errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -1,81 +0,0 @@
|
|||
// 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 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_REFLECTION_OPS_H__
|
||||
#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Basic operations that can be performed using reflection.
|
||||
// These can be used as a cheap way to implement the corresponding
|
||||
// methods of the Message interface, though they are likely to be
|
||||
// slower than implementations tailored for the specific message type.
|
||||
//
|
||||
// This class should stay limited to operations needed to implement
|
||||
// the Message interface.
|
||||
//
|
||||
// This class is really a namespace that contains only static methods.
|
||||
class LIBPROTOBUF_EXPORT ReflectionOps {
|
||||
public:
|
||||
static void Copy(const Message& from, Message* to);
|
||||
static void Merge(const Message& from, Message* to);
|
||||
static void Clear(Message* message);
|
||||
static bool IsInitialized(const Message& message);
|
||||
static void DiscardUnknownFields(Message* message);
|
||||
|
||||
// Finds all unset required fields in the message and adds their full
|
||||
// paths (e.g. "foo.bar[5].baz") to *names. "prefix" will be attached to
|
||||
// the front of each name.
|
||||
static void FindInitializationErrors(const Message& message,
|
||||
const string& prefix,
|
||||
vector<string>* errors);
|
||||
|
||||
private:
|
||||
// All methods are static. No need to construct.
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
|
@ -1,291 +0,0 @@
|
|||
// 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.
|
||||
//
|
||||
// DEPRECATED: This module declares the abstract interfaces underlying proto2
|
||||
// RPC services. These are intented to be independent of any particular RPC
|
||||
// implementation, so that proto2 services can be used on top of a variety
|
||||
// of implementations. Starting with version 2.3.0, RPC implementations should
|
||||
// not try to build on these, but should instead provide code generator plugins
|
||||
// which generate code specific to the particular RPC implementation. This way
|
||||
// the generated code can be more appropriate for the implementation in use
|
||||
// and can avoid unnecessary layers of indirection.
|
||||
//
|
||||
//
|
||||
// When you use the protocol compiler to compile a service definition, it
|
||||
// generates two classes: An abstract interface for the service (with
|
||||
// methods matching the service definition) and a "stub" implementation.
|
||||
// A stub is just a type-safe wrapper around an RpcChannel which emulates a
|
||||
// local implementation of the service.
|
||||
//
|
||||
// For example, the service definition:
|
||||
// service MyService {
|
||||
// rpc Foo(MyRequest) returns(MyResponse);
|
||||
// }
|
||||
// will generate abstract interface "MyService" and class "MyService::Stub".
|
||||
// You could implement a MyService as follows:
|
||||
// class MyServiceImpl : public MyService {
|
||||
// public:
|
||||
// MyServiceImpl() {}
|
||||
// ~MyServiceImpl() {}
|
||||
//
|
||||
// // implements MyService ---------------------------------------
|
||||
//
|
||||
// void Foo(google::protobuf::RpcController* controller,
|
||||
// const MyRequest* request,
|
||||
// MyResponse* response,
|
||||
// Closure* done) {
|
||||
// // ... read request and fill in response ...
|
||||
// done->Run();
|
||||
// }
|
||||
// };
|
||||
// You would then register an instance of MyServiceImpl with your RPC server
|
||||
// implementation. (How to do that depends on the implementation.)
|
||||
//
|
||||
// To call a remote MyServiceImpl, first you need an RpcChannel connected to it.
|
||||
// How to construct a channel depends, again, on your RPC implementation.
|
||||
// Here we use a hypothentical "MyRpcChannel" as an example:
|
||||
// MyRpcChannel channel("rpc:hostname:1234/myservice");
|
||||
// MyRpcController controller;
|
||||
// MyServiceImpl::Stub stub(&channel);
|
||||
// FooRequest request;
|
||||
// FooRespnose response;
|
||||
//
|
||||
// // ... fill in request ...
|
||||
//
|
||||
// stub.Foo(&controller, request, &response, NewCallback(HandleResponse));
|
||||
//
|
||||
// On Thread-Safety:
|
||||
//
|
||||
// Different RPC implementations may make different guarantees about what
|
||||
// threads they may run callbacks on, and what threads the application is
|
||||
// allowed to use to call the RPC system. Portable software should be ready
|
||||
// for callbacks to be called on any thread, but should not try to call the
|
||||
// RPC system from any thread except for the ones on which it received the
|
||||
// callbacks. Realistically, though, simple software will probably want to
|
||||
// use a single-threaded RPC system while high-end software will want to
|
||||
// use multiple threads. RPC implementations should provide multiple
|
||||
// choices.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_SERVICE_H__
|
||||
#define GOOGLE_PROTOBUF_SERVICE_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class Service;
|
||||
class RpcController;
|
||||
class RpcChannel;
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class ServiceDescriptor; // descriptor.h
|
||||
class MethodDescriptor; // descriptor.h
|
||||
class Message; // message.h
|
||||
|
||||
// Abstract base interface for protocol-buffer-based RPC services. Services
|
||||
// themselves are abstract interfaces (implemented either by servers or as
|
||||
// stubs), but they subclass this base interface. The methods of this
|
||||
// interface can be used to call the methods of the Service without knowing
|
||||
// its exact type at compile time (analogous to Reflection).
|
||||
class LIBPROTOBUF_EXPORT Service {
|
||||
public:
|
||||
inline Service() {}
|
||||
virtual ~Service();
|
||||
|
||||
// When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second
|
||||
// parameter to the constructor to tell it to delete its RpcChannel when
|
||||
// destroyed.
|
||||
enum ChannelOwnership {
|
||||
STUB_OWNS_CHANNEL,
|
||||
STUB_DOESNT_OWN_CHANNEL
|
||||
};
|
||||
|
||||
// Get the ServiceDescriptor describing this service and its methods.
|
||||
virtual const ServiceDescriptor* GetDescriptor() = 0;
|
||||
|
||||
// Call a method of the service specified by MethodDescriptor. This is
|
||||
// normally implemented as a simple switch() that calls the standard
|
||||
// definitions of the service's methods.
|
||||
//
|
||||
// Preconditions:
|
||||
// * method->service() == GetDescriptor()
|
||||
// * request and response are of the exact same classes as the objects
|
||||
// returned by GetRequestPrototype(method) and
|
||||
// GetResponsePrototype(method).
|
||||
// * After the call has started, the request must not be modified and the
|
||||
// response must not be accessed at all until "done" is called.
|
||||
// * "controller" is of the correct type for the RPC implementation being
|
||||
// used by this Service. For stubs, the "correct type" depends on the
|
||||
// RpcChannel which the stub is using. Server-side Service
|
||||
// implementations are expected to accept whatever type of RpcController
|
||||
// the server-side RPC implementation uses.
|
||||
//
|
||||
// Postconditions:
|
||||
// * "done" will be called when the method is complete. This may be
|
||||
// before CallMethod() returns or it may be at some point in the future.
|
||||
// * If the RPC succeeded, "response" contains the response returned by
|
||||
// the server.
|
||||
// * If the RPC failed, "response"'s contents are undefined. The
|
||||
// RpcController can be queried to determine if an error occurred and
|
||||
// possibly to get more information about the error.
|
||||
virtual void CallMethod(const MethodDescriptor* method,
|
||||
RpcController* controller,
|
||||
const Message* request,
|
||||
Message* response,
|
||||
Closure* done) = 0;
|
||||
|
||||
// CallMethod() requires that the request and response passed in are of a
|
||||
// particular subclass of Message. GetRequestPrototype() and
|
||||
// GetResponsePrototype() get the default instances of these required types.
|
||||
// You can then call Message::New() on these instances to construct mutable
|
||||
// objects which you can then pass to CallMethod().
|
||||
//
|
||||
// Example:
|
||||
// const MethodDescriptor* method =
|
||||
// service->GetDescriptor()->FindMethodByName("Foo");
|
||||
// Message* request = stub->GetRequestPrototype (method)->New();
|
||||
// Message* response = stub->GetResponsePrototype(method)->New();
|
||||
// request->ParseFromString(input);
|
||||
// service->CallMethod(method, *request, response, callback);
|
||||
virtual const Message& GetRequestPrototype(
|
||||
const MethodDescriptor* method) const = 0;
|
||||
virtual const Message& GetResponsePrototype(
|
||||
const MethodDescriptor* method) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service);
|
||||
};
|
||||
|
||||
// An RpcController mediates a single method call. The primary purpose of
|
||||
// the controller is to provide a way to manipulate settings specific to the
|
||||
// RPC implementation and to find out about RPC-level errors.
|
||||
//
|
||||
// The methods provided by the RpcController interface are intended to be a
|
||||
// "least common denominator" set of features which we expect all
|
||||
// implementations to support. Specific implementations may provide more
|
||||
// advanced features (e.g. deadline propagation).
|
||||
class LIBPROTOBUF_EXPORT RpcController {
|
||||
public:
|
||||
inline RpcController() {}
|
||||
virtual ~RpcController();
|
||||
|
||||
// Client-side methods ---------------------------------------------
|
||||
// These calls may be made from the client side only. Their results
|
||||
// are undefined on the server side (may crash).
|
||||
|
||||
// Resets the RpcController to its initial state so that it may be reused in
|
||||
// a new call. Must not be called while an RPC is in progress.
|
||||
virtual void Reset() = 0;
|
||||
|
||||
// After a call has finished, returns true if the call failed. The possible
|
||||
// reasons for failure depend on the RPC implementation. Failed() must not
|
||||
// be called before a call has finished. If Failed() returns true, the
|
||||
// contents of the response message are undefined.
|
||||
virtual bool Failed() const = 0;
|
||||
|
||||
// If Failed() is true, returns a human-readable description of the error.
|
||||
virtual string ErrorText() const = 0;
|
||||
|
||||
// Advises the RPC system that the caller desires that the RPC call be
|
||||
// canceled. The RPC system may cancel it immediately, may wait awhile and
|
||||
// then cancel it, or may not even cancel the call at all. If the call is
|
||||
// canceled, the "done" callback will still be called and the RpcController
|
||||
// will indicate that the call failed at that time.
|
||||
virtual void StartCancel() = 0;
|
||||
|
||||
// Server-side methods ---------------------------------------------
|
||||
// These calls may be made from the server side only. Their results
|
||||
// are undefined on the client side (may crash).
|
||||
|
||||
// Causes Failed() to return true on the client side. "reason" will be
|
||||
// incorporated into the message returned by ErrorText(). If you find
|
||||
// you need to return machine-readable information about failures, you
|
||||
// should incorporate it into your response protocol buffer and should
|
||||
// NOT call SetFailed().
|
||||
virtual void SetFailed(const string& reason) = 0;
|
||||
|
||||
// If true, indicates that the client canceled the RPC, so the server may
|
||||
// as well give up on replying to it. The server should still call the
|
||||
// final "done" callback.
|
||||
virtual bool IsCanceled() const = 0;
|
||||
|
||||
// Asks that the given callback be called when the RPC is canceled. The
|
||||
// callback will always be called exactly once. If the RPC completes without
|
||||
// being canceled, the callback will be called after completion. If the RPC
|
||||
// has already been canceled when NotifyOnCancel() is called, the callback
|
||||
// will be called immediately.
|
||||
//
|
||||
// NotifyOnCancel() must be called no more than once per request.
|
||||
virtual void NotifyOnCancel(Closure* callback) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController);
|
||||
};
|
||||
|
||||
// Abstract interface for an RPC channel. An RpcChannel represents a
|
||||
// communication line to a Service which can be used to call that Service's
|
||||
// methods. The Service may be running on another machine. Normally, you
|
||||
// should not call an RpcChannel directly, but instead construct a stub Service
|
||||
// wrapping it. Example:
|
||||
// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234");
|
||||
// MyService* service = new MyService::Stub(channel);
|
||||
// service->MyMethod(request, &response, callback);
|
||||
class LIBPROTOBUF_EXPORT RpcChannel {
|
||||
public:
|
||||
inline RpcChannel() {}
|
||||
virtual ~RpcChannel();
|
||||
|
||||
// Call the given method of the remote service. The signature of this
|
||||
// procedure looks the same as Service::CallMethod(), but the requirements
|
||||
// are less strict in one important way: the request and response objects
|
||||
// need not be of any specific class as long as their descriptors are
|
||||
// method->input_type() and method->output_type().
|
||||
virtual void CallMethod(const MethodDescriptor* method,
|
||||
RpcController* controller,
|
||||
const Message* request,
|
||||
Message* response,
|
||||
Closure* done) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_SERVICE_H__
|
|
@ -1,227 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// The routines exported by this module are subtle. If you use them, even if
|
||||
// you get the code right, it will depend on careful reasoning about atomicity
|
||||
// and memory ordering; it will be less readable, and harder to maintain. If
|
||||
// you plan to use these routines, you should have a good reason, such as solid
|
||||
// evidence that performance would otherwise suffer, or there being no
|
||||
// alternative. You should assume only properties explicitly guaranteed by the
|
||||
// specifications in this file. You are almost certainly _not_ writing code
|
||||
// just for the x86; if you assume x86 semantics, x86 hardware bugs and
|
||||
// implementations on other archtectures will cause your code to break. If you
|
||||
// do not know what you are doing, avoid these routines, and use a Mutex.
|
||||
//
|
||||
// It is incorrect to make direct assignments to/from an atomic variable.
|
||||
// You should use one of the Load or Store routines. The NoBarrier
|
||||
// versions are provided when no barriers are needed:
|
||||
// NoBarrier_Store()
|
||||
// NoBarrier_Load()
|
||||
// Although there are currently no compiler enforcement, you are encouraged
|
||||
// to use these.
|
||||
|
||||
// This header and the implementations for each platform (located in
|
||||
// atomicops_internals_*) must be kept in sync with the upstream code (V8).
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_H_
|
||||
|
||||
// Don't include this file for people not concerned about thread safety.
|
||||
#ifndef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
|
||||
|
||||
#include <google/protobuf/stubs/platform_macros.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
typedef int32 Atomic32;
|
||||
#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
|
||||
// We need to be able to go between Atomic64 and AtomicWord implicitly. This
|
||||
// means Atomic64 and AtomicWord should be the same type on 64-bit.
|
||||
#if defined(__ILP32__) || defined(GOOGLE_PROTOBUF_OS_NACL) || defined(GOOGLE_PROTOBUF_ARCH_SPARC)
|
||||
// NaCl's intptr_t is not actually 64-bits on 64-bit!
|
||||
// http://code.google.com/p/nativeclient/issues/detail?id=1162
|
||||
// sparcv9's pointer type is 32bits
|
||||
typedef int64 Atomic64;
|
||||
#else
|
||||
typedef intptr_t Atomic64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
|
||||
// Atomic64 routines below, depending on your architecture.
|
||||
typedef intptr_t AtomicWord;
|
||||
|
||||
// Atomically execute:
|
||||
// result = *ptr;
|
||||
// if (*ptr == old_value)
|
||||
// *ptr = new_value;
|
||||
// return result;
|
||||
//
|
||||
// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
|
||||
// Always return the old value of "*ptr"
|
||||
//
|
||||
// This routine implies no memory barriers.
|
||||
Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
|
||||
// Atomically store new_value into *ptr, returning the previous value held in
|
||||
// *ptr. This routine implies no memory barriers.
|
||||
Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
|
||||
|
||||
// Atomically increment *ptr by "increment". Returns the new value of
|
||||
// *ptr with the increment applied. This routine implies no memory barriers.
|
||||
Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
|
||||
|
||||
Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment);
|
||||
|
||||
// These following lower-level operations are typically useful only to people
|
||||
// implementing higher-level synchronization operations like spinlocks,
|
||||
// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
|
||||
// a store with appropriate memory-ordering instructions. "Acquire" operations
|
||||
// ensure that no later memory access can be reordered ahead of the operation.
|
||||
// "Release" operations ensure that no previous memory access can be reordered
|
||||
// after the operation. "Barrier" operations have both "Acquire" and "Release"
|
||||
// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
|
||||
// access.
|
||||
Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
|
||||
#if defined(__MINGW32__) && defined(MemoryBarrier)
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
void MemoryBarrier();
|
||||
void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
void Release_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
|
||||
Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
|
||||
Atomic32 Acquire_Load(volatile const Atomic32* ptr);
|
||||
Atomic32 Release_Load(volatile const Atomic32* ptr);
|
||||
|
||||
// 64-bit atomic operations (only available on 64-bit processors).
|
||||
#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
|
||||
Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value);
|
||||
Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
|
||||
Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
|
||||
Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
|
||||
|
||||
Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value);
|
||||
Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value);
|
||||
void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
|
||||
void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
|
||||
void Release_Store(volatile Atomic64* ptr, Atomic64 value);
|
||||
Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
|
||||
Atomic64 Acquire_Load(volatile const Atomic64* ptr);
|
||||
Atomic64 Release_Load(volatile const Atomic64* ptr);
|
||||
#endif // GOOGLE_PROTOBUF_ARCH_64_BIT
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
// Include our platform specific implementation.
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_ERROR \
|
||||
#error "Atomic operations are not supported on your platform"
|
||||
|
||||
// ThreadSanitizer, http://clang.llvm.org/docs/ThreadSanitizer.html.
|
||||
#if defined(THREAD_SANITIZER)
|
||||
#include <google/protobuf/stubs/atomicops_internals_tsan.h>
|
||||
// MSVC.
|
||||
#elif defined(_MSC_VER)
|
||||
#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
|
||||
#include <google/protobuf/stubs/atomicops_internals_x86_msvc.h>
|
||||
#else
|
||||
GOOGLE_PROTOBUF_ATOMICOPS_ERROR
|
||||
#endif
|
||||
|
||||
// Solaris
|
||||
#elif defined(GOOGLE_PROTOBUF_OS_SOLARIS)
|
||||
#include <google/protobuf/stubs/atomicops_internals_solaris.h>
|
||||
|
||||
// Apple.
|
||||
#elif defined(GOOGLE_PROTOBUF_OS_APPLE)
|
||||
#include <google/protobuf/stubs/atomicops_internals_macosx.h>
|
||||
|
||||
// GCC.
|
||||
#elif defined(__GNUC__)
|
||||
#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
|
||||
#include <google/protobuf/stubs/atomicops_internals_x86_gcc.h>
|
||||
#elif defined(GOOGLE_PROTOBUF_ARCH_ARM) && defined(__linux__)
|
||||
#include <google/protobuf/stubs/atomicops_internals_arm_gcc.h>
|
||||
#elif defined(GOOGLE_PROTOBUF_ARCH_AARCH64)
|
||||
#include <google/protobuf/stubs/atomicops_internals_arm64_gcc.h>
|
||||
#elif defined(GOOGLE_PROTOBUF_ARCH_ARM_QNX)
|
||||
#include <google/protobuf/stubs/atomicops_internals_arm_qnx.h>
|
||||
#elif defined(GOOGLE_PROTOBUF_ARCH_MIPS) || defined(GOOGLE_PROTOBUF_ARCH_MIPS64)
|
||||
#include <google/protobuf/stubs/atomicops_internals_mips_gcc.h>
|
||||
#elif defined(__native_client__)
|
||||
#include <google/protobuf/stubs/atomicops_internals_pnacl.h>
|
||||
#elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
|
||||
#include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
|
||||
#elif defined(__clang__)
|
||||
#if __has_extension(c_atomic)
|
||||
#include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
|
||||
#else
|
||||
GOOGLE_PROTOBUF_ATOMICOPS_ERROR
|
||||
#endif
|
||||
#else
|
||||
GOOGLE_PROTOBUF_ATOMICOPS_ERROR
|
||||
#endif
|
||||
|
||||
// Unknown.
|
||||
#else
|
||||
GOOGLE_PROTOBUF_ATOMICOPS_ERROR
|
||||
#endif
|
||||
|
||||
// On some platforms we need additional declarations to make AtomicWord
|
||||
// compatible with our other Atomic* types.
|
||||
#if defined(GOOGLE_PROTOBUF_OS_APPLE)
|
||||
#include <google/protobuf/stubs/atomicops_internals_atomicword_compat.h>
|
||||
#endif
|
||||
|
||||
#undef GOOGLE_PROTOBUF_ATOMICOPS_ERROR
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_H_
|
|
@ -1,325 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM64_GCC_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM64_GCC_H_
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__asm__ __volatile__ ("dmb ish" ::: "memory"); // NOLINT
|
||||
}
|
||||
|
||||
// NoBarrier versions of the operation include "memory" in the clobber list.
|
||||
// This is not required for direct usage of the NoBarrier versions of the
|
||||
// operations. However this is required for correctness when they are used as
|
||||
// part of the Acquire or Release versions, to ensure that nothing from outside
|
||||
// the call is reordered between the operation and the memory barrier. This does
|
||||
// not change the code generated, so has no or minimal impact on the
|
||||
// NoBarrier operations.
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev;
|
||||
int32_t temp;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"0: \n\t"
|
||||
"ldxr %w[prev], %[ptr] \n\t" // Load the previous value.
|
||||
"cmp %w[prev], %w[old_value] \n\t"
|
||||
"bne 1f \n\t"
|
||||
"stxr %w[temp], %w[new_value], %[ptr] \n\t" // Try to store the new value.
|
||||
"cbnz %w[temp], 0b \n\t" // Retry if it did not work.
|
||||
"1: \n\t"
|
||||
: [prev]"=&r" (prev),
|
||||
[temp]"=&r" (temp),
|
||||
[ptr]"+Q" (*ptr)
|
||||
: [old_value]"IJr" (old_value),
|
||||
[new_value]"r" (new_value)
|
||||
: "cc", "memory"
|
||||
); // NOLINT
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 result;
|
||||
int32_t temp;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"0: \n\t"
|
||||
"ldxr %w[result], %[ptr] \n\t" // Load the previous value.
|
||||
"stxr %w[temp], %w[new_value], %[ptr] \n\t" // Try to store the new value.
|
||||
"cbnz %w[temp], 0b \n\t" // Retry if it did not work.
|
||||
: [result]"=&r" (result),
|
||||
[temp]"=&r" (temp),
|
||||
[ptr]"+Q" (*ptr)
|
||||
: [new_value]"r" (new_value)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 result;
|
||||
int32_t temp;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"0: \n\t"
|
||||
"ldxr %w[result], %[ptr] \n\t" // Load the previous value.
|
||||
"add %w[result], %w[result], %w[increment]\n\t"
|
||||
"stxr %w[temp], %w[result], %[ptr] \n\t" // Try to store the result.
|
||||
"cbnz %w[temp], 0b \n\t" // Retry on failure.
|
||||
: [result]"=&r" (result),
|
||||
[temp]"=&r" (temp),
|
||||
[ptr]"+Q" (*ptr)
|
||||
: [increment]"IJr" (increment)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
MemoryBarrier();
|
||||
Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
MemoryBarrier();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
MemoryBarrier();
|
||||
Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"stlr %w[value], %[ptr] \n\t"
|
||||
: [ptr]"=Q" (*ptr)
|
||||
: [value]"r" (value)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"ldar %w[value], %[ptr] \n\t"
|
||||
: [value]"=r" (value)
|
||||
: [ptr]"Q" (*ptr)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
// 64-bit versions of the operations.
|
||||
// See the 32-bit versions for comments.
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev;
|
||||
int32_t temp;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"0: \n\t"
|
||||
"ldxr %[prev], %[ptr] \n\t"
|
||||
"cmp %[prev], %[old_value] \n\t"
|
||||
"bne 1f \n\t"
|
||||
"stxr %w[temp], %[new_value], %[ptr] \n\t"
|
||||
"cbnz %w[temp], 0b \n\t"
|
||||
"1: \n\t"
|
||||
: [prev]"=&r" (prev),
|
||||
[temp]"=&r" (temp),
|
||||
[ptr]"+Q" (*ptr)
|
||||
: [old_value]"IJr" (old_value),
|
||||
[new_value]"r" (new_value)
|
||||
: "cc", "memory"
|
||||
); // NOLINT
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 result;
|
||||
int32_t temp;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"0: \n\t"
|
||||
"ldxr %[result], %[ptr] \n\t"
|
||||
"stxr %w[temp], %[new_value], %[ptr] \n\t"
|
||||
"cbnz %w[temp], 0b \n\t"
|
||||
: [result]"=&r" (result),
|
||||
[temp]"=&r" (temp),
|
||||
[ptr]"+Q" (*ptr)
|
||||
: [new_value]"r" (new_value)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 result;
|
||||
int32_t temp;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"0: \n\t"
|
||||
"ldxr %[result], %[ptr] \n\t"
|
||||
"add %[result], %[result], %[increment] \n\t"
|
||||
"stxr %w[temp], %[result], %[ptr] \n\t"
|
||||
"cbnz %w[temp], 0b \n\t"
|
||||
: [result]"=&r" (result),
|
||||
[temp]"=&r" (temp),
|
||||
[ptr]"+Q" (*ptr)
|
||||
: [increment]"IJr" (increment)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
MemoryBarrier();
|
||||
Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
MemoryBarrier();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
MemoryBarrier();
|
||||
Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"stlr %x[value], %[ptr] \n\t"
|
||||
: [ptr]"=Q" (*ptr)
|
||||
: [value]"r" (value)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value;
|
||||
|
||||
__asm__ __volatile__ ( // NOLINT
|
||||
"ldar %x[value], %[ptr] \n\t"
|
||||
: [value]"=r" (value)
|
||||
: [ptr]"Q" (*ptr)
|
||||
: "memory"
|
||||
); // NOLINT
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM64_GCC_H_
|
|
@ -1,151 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
//
|
||||
// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// 0xffff0fc0 is the hard coded address of a function provided by
|
||||
// the kernel which implements an atomic compare-exchange. On older
|
||||
// ARM architecture revisions (pre-v6) this may be implemented using
|
||||
// a syscall. This address is stable, and in active use (hard coded)
|
||||
// by at least glibc-2.7 and the Android C library.
|
||||
typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
|
||||
Atomic32 new_value,
|
||||
volatile Atomic32* ptr);
|
||||
LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
|
||||
(LinuxKernelCmpxchgFunc) 0xffff0fc0;
|
||||
|
||||
typedef void (*LinuxKernelMemoryBarrierFunc)(void);
|
||||
LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
|
||||
(LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
|
||||
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value = *ptr;
|
||||
do {
|
||||
if (!pLinuxKernelCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (pLinuxKernelCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
for (;;) {
|
||||
// Atomic exchange the old value with an incremented one.
|
||||
Atomic32 old_value = *ptr;
|
||||
Atomic32 new_value = old_value + increment;
|
||||
if (pLinuxKernelCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)) == 0) {
|
||||
// The exchange took place as expected.
|
||||
return new_value;
|
||||
}
|
||||
// Otherwise, *ptr changed mid-loop and we need to retry.
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
pLinuxKernelMemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_GCC_H_
|
|
@ -1,146 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
|
||||
|
||||
// For _smp_cmpxchg()
|
||||
#include <pthread.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline Atomic32 QNXCmpxchg(Atomic32 old_value,
|
||||
Atomic32 new_value,
|
||||
volatile Atomic32* ptr) {
|
||||
return static_cast<Atomic32>(
|
||||
_smp_cmpxchg((volatile unsigned *)ptr,
|
||||
(unsigned)old_value,
|
||||
(unsigned)new_value));
|
||||
}
|
||||
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value = *ptr;
|
||||
do {
|
||||
if (!QNXCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (QNXCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
for (;;) {
|
||||
// Atomic exchange the old value with an incremented one.
|
||||
Atomic32 old_value = *ptr;
|
||||
Atomic32 new_value = old_value + increment;
|
||||
if (QNXCmpxchg(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)) == 0) {
|
||||
// The exchange took place as expected.
|
||||
return new_value;
|
||||
}
|
||||
// Otherwise, *ptr changed mid-loop and we need to retry.
|
||||
}
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ARM_QNX_H_
|
|
@ -1,122 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
|
||||
|
||||
// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
|
||||
// which in turn means int. On some LP32 platforms, intptr_t is an int, but
|
||||
// on others, it's a long. When AtomicWord and Atomic32 are based on different
|
||||
// fundamental types, their pointers are incompatible.
|
||||
//
|
||||
// This file defines function overloads to allow both AtomicWord and Atomic32
|
||||
// data to be used with this interface.
|
||||
//
|
||||
// On LP64 platforms, AtomicWord and Atomic64 are both always long,
|
||||
// so this problem doesn't occur.
|
||||
|
||||
#if !defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
|
||||
AtomicWord old_value,
|
||||
AtomicWord new_value) {
|
||||
return NoBarrier_CompareAndSwap(
|
||||
reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
|
||||
}
|
||||
|
||||
inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
|
||||
AtomicWord new_value) {
|
||||
return NoBarrier_AtomicExchange(
|
||||
reinterpret_cast<volatile Atomic32*>(ptr), new_value);
|
||||
}
|
||||
|
||||
inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
|
||||
AtomicWord increment) {
|
||||
return NoBarrier_AtomicIncrement(
|
||||
reinterpret_cast<volatile Atomic32*>(ptr), increment);
|
||||
}
|
||||
|
||||
inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
|
||||
AtomicWord increment) {
|
||||
return Barrier_AtomicIncrement(
|
||||
reinterpret_cast<volatile Atomic32*>(ptr), increment);
|
||||
}
|
||||
|
||||
inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
|
||||
AtomicWord old_value,
|
||||
AtomicWord new_value) {
|
||||
return Acquire_CompareAndSwap(
|
||||
reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
|
||||
}
|
||||
|
||||
inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
|
||||
AtomicWord old_value,
|
||||
AtomicWord new_value) {
|
||||
return Release_CompareAndSwap(
|
||||
reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
|
||||
NoBarrier_Store(reinterpret_cast<volatile Atomic32*>(ptr), value);
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
|
||||
return Acquire_Store(reinterpret_cast<volatile Atomic32*>(ptr), value);
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
|
||||
return Release_Store(reinterpret_cast<volatile Atomic32*>(ptr), value);
|
||||
}
|
||||
|
||||
inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
|
||||
return NoBarrier_Load(reinterpret_cast<volatile const Atomic32*>(ptr));
|
||||
}
|
||||
|
||||
inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
|
||||
return Acquire_Load(reinterpret_cast<volatile const Atomic32*>(ptr));
|
||||
}
|
||||
|
||||
inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
|
||||
return Release_Load(reinterpret_cast<volatile const Atomic32*>(ptr));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // !defined(GOOGLE_PROTOBUF_ARCH_64_BIT)
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
|
|
@ -1,137 +0,0 @@
|
|||
// Copyright 2013 Red Hat 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 Red Hat 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 is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
|
||||
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
return __atomic_exchange_n(ptr, new_value, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return __atomic_add_fetch(ptr, increment, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return __atomic_add_fetch(ptr, increment, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
__atomic_compare_exchange(ptr, &old_value, &new_value, true,
|
||||
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
|
||||
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
__atomic_store_n(ptr, value, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
__atomic_store_n(ptr, value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
__atomic_store_n(ptr, value, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return __atomic_load_n(ptr, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
__atomic_store_n(ptr, value, __ATOMIC_RELEASE);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
|
||||
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
|
||||
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
|
||||
return old_value;
|
||||
}
|
||||
|
||||
#endif // defined(__LP64__)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_GCC_H_
|
|
@ -1,225 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
do {
|
||||
if (OSAtomicCompareAndSwap32(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (!OSAtomicCompareAndSwap32(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr)));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev_value;
|
||||
do {
|
||||
if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
|
||||
const_cast<Atomic32*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return Acquire_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
|
||||
// 64-bit implementation on 64-bit platform
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev_value;
|
||||
do {
|
||||
if (OSAtomicCompareAndSwap64(old_value, new_value,
|
||||
reinterpret_cast<volatile int64_t*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 old_value;
|
||||
do {
|
||||
old_value = *ptr;
|
||||
} while (!OSAtomicCompareAndSwap64(old_value, new_value,
|
||||
reinterpret_cast<volatile int64_t*>(ptr)));
|
||||
return old_value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
return OSAtomicAdd64Barrier(increment,
|
||||
reinterpret_cast<volatile int64_t*>(ptr));
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev_value;
|
||||
do {
|
||||
if (OSAtomicCompareAndSwap64Barrier(
|
||||
old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
|
||||
return old_value;
|
||||
}
|
||||
prev_value = *ptr;
|
||||
} while (prev_value == old_value);
|
||||
return prev_value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
// The lib kern interface does not distinguish between
|
||||
// Acquire and Release memory barriers; they are equivalent.
|
||||
return Acquire_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#endif // defined(__LP64__)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MACOSX_H_
|
|
@ -1,313 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
|
||||
|
||||
#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Atomically execute:
|
||||
// result = *ptr;
|
||||
// if (*ptr == old_value)
|
||||
// *ptr = new_value;
|
||||
// return result;
|
||||
//
|
||||
// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
|
||||
// Always return the old value of "*ptr"
|
||||
//
|
||||
// This routine implies no memory barriers.
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 prev, tmp;
|
||||
__asm__ __volatile__(".set push\n"
|
||||
".set noreorder\n"
|
||||
"1:\n"
|
||||
"ll %0, %5\n" // prev = *ptr
|
||||
"bne %0, %3, 2f\n" // if (prev != old_value) goto 2
|
||||
"move %2, %4\n" // tmp = new_value
|
||||
"sc %2, %1\n" // *ptr = tmp (with atomic check)
|
||||
"beqz %2, 1b\n" // start again on atomic error
|
||||
"nop\n" // delay slot nop
|
||||
"2:\n"
|
||||
".set pop\n"
|
||||
: "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
|
||||
: "Ir" (old_value), "r" (new_value), "m" (*ptr)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
// Atomically store new_value into *ptr, returning the previous value held in
|
||||
// *ptr. This routine implies no memory barriers.
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 temp, old;
|
||||
__asm__ __volatile__(".set push\n"
|
||||
".set noreorder\n"
|
||||
"1:\n"
|
||||
"ll %1, %4\n" // old = *ptr
|
||||
"move %0, %3\n" // temp = new_value
|
||||
"sc %0, %2\n" // *ptr = temp (with atomic check)
|
||||
"beqz %0, 1b\n" // start again on atomic error
|
||||
"nop\n" // delay slot nop
|
||||
".set pop\n"
|
||||
: "=&r" (temp), "=&r" (old), "=m" (*ptr)
|
||||
: "r" (new_value), "m" (*ptr)
|
||||
: "memory");
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
// Atomically increment *ptr by "increment". Returns the new value of
|
||||
// *ptr with the increment applied. This routine implies no memory barriers.
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
Atomic32 temp, temp2;
|
||||
|
||||
__asm__ __volatile__(".set push\n"
|
||||
".set noreorder\n"
|
||||
"1:\n"
|
||||
"ll %0, %4\n" // temp = *ptr
|
||||
"addu %1, %0, %3\n" // temp2 = temp + increment
|
||||
"sc %1, %2\n" // *ptr = temp2 (with atomic check)
|
||||
"beqz %1, 1b\n" // start again on atomic error
|
||||
"addu %1, %0, %3\n" // temp2 = temp + increment
|
||||
".set pop\n"
|
||||
: "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
|
||||
: "Ir" (increment), "m" (*ptr)
|
||||
: "memory");
|
||||
// temp2 now holds the final value.
|
||||
return temp2;
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return res;
|
||||
}
|
||||
|
||||
// "Acquire" operations
|
||||
// ensure that no later memory access can be reordered ahead of the operation.
|
||||
// "Release" operations ensure that no previous memory access can be reordered
|
||||
// after the operation. "Barrier" operations have both "Acquire" and "Release"
|
||||
// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
|
||||
// access.
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
ATOMICOPS_COMPILER_BARRIER();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__asm__ __volatile__("sync" : : : "memory");
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#if defined(__LP64__)
|
||||
// 64-bit versions of the atomic ops.
|
||||
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 prev, tmp;
|
||||
__asm__ __volatile__(".set push\n"
|
||||
".set noreorder\n"
|
||||
"1:\n"
|
||||
"lld %0, %5\n" // prev = *ptr
|
||||
"bne %0, %3, 2f\n" // if (prev != old_value) goto 2
|
||||
"move %2, %4\n" // tmp = new_value
|
||||
"scd %2, %1\n" // *ptr = tmp (with atomic check)
|
||||
"beqz %2, 1b\n" // start again on atomic error
|
||||
"nop\n" // delay slot nop
|
||||
"2:\n"
|
||||
".set pop\n"
|
||||
: "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
|
||||
: "Ir" (old_value), "r" (new_value), "m" (*ptr)
|
||||
: "memory");
|
||||
return prev;
|
||||
}
|
||||
|
||||
// Atomically store new_value into *ptr, returning the previous value held in
|
||||
// *ptr. This routine implies no memory barriers.
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 temp, old;
|
||||
__asm__ __volatile__(".set push\n"
|
||||
".set noreorder\n"
|
||||
"1:\n"
|
||||
"lld %1, %4\n" // old = *ptr
|
||||
"move %0, %3\n" // temp = new_value
|
||||
"scd %0, %2\n" // *ptr = temp (with atomic check)
|
||||
"beqz %0, 1b\n" // start again on atomic error
|
||||
"nop\n" // delay slot nop
|
||||
".set pop\n"
|
||||
: "=&r" (temp), "=&r" (old), "=m" (*ptr)
|
||||
: "r" (new_value), "m" (*ptr)
|
||||
: "memory");
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
// Atomically increment *ptr by "increment". Returns the new value of
|
||||
// *ptr with the increment applied. This routine implies no memory barriers.
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
Atomic64 temp, temp2;
|
||||
|
||||
__asm__ __volatile__(".set push\n"
|
||||
".set noreorder\n"
|
||||
"1:\n"
|
||||
"lld %0, %4\n" // temp = *ptr
|
||||
"daddu %1, %0, %3\n" // temp2 = temp + increment
|
||||
"scd %1, %2\n" // *ptr = temp2 (with atomic check)
|
||||
"beqz %1, 1b\n" // start again on atomic error
|
||||
"daddu %1, %0, %3\n" // temp2 = temp + increment
|
||||
".set pop\n"
|
||||
: "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
|
||||
: "Ir" (increment), "m" (*ptr)
|
||||
: "memory");
|
||||
// temp2 now holds the final value.
|
||||
return temp2;
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
|
||||
Atomic64 increment) {
|
||||
MemoryBarrier();
|
||||
Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
MemoryBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
// "Acquire" operations
|
||||
// ensure that no later memory access can be reordered ahead of the operation.
|
||||
// "Release" operations ensure that no previous memory access can be reordered
|
||||
// after the operation. "Barrier" operations have both "Acquire" and "Release"
|
||||
// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
|
||||
// access.
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
MemoryBarrier();
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#undef ATOMICOPS_COMPILER_BARRIER
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_MIPS_GCC_H_
|
|
@ -1,73 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return __sync_val_compare_and_swap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
MemoryBarrier();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 value = *ptr;
|
||||
MemoryBarrier();
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
|
|
@ -1,188 +0,0 @@
|
|||
// 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.
|
||||
|
||||
// This file is an internal atomic implementation, use atomicops.h instead.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
|
||||
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
|
||||
|
||||
#include <atomic.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
return (Atomic32)atomic_cas_32((volatile uint32_t*)ptr, (uint32_t)old_value, (uint32_t)new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
|
||||
Atomic32 new_value) {
|
||||
return (Atomic32)atomic_swap_32((volatile uint32_t*)ptr, (uint32_t)new_value);
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
return (Atomic32)atomic_add_32_nv((volatile uint32_t*)ptr, (uint32_t)increment);
|
||||
}
|
||||
|
||||
inline void MemoryBarrier(void) {
|
||||
membar_producer();
|
||||
membar_consumer();
|
||||
}
|
||||
|
||||
inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
||||
Atomic32 increment) {
|
||||
MemoryBarrier();
|
||||
Atomic32 ret = NoBarrier_AtomicIncrement(ptr, increment);
|
||||
MemoryBarrier();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
Atomic32 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
MemoryBarrier();
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
*ptr = value;
|
||||
membar_producer();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
membar_consumer();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
||||
Atomic32 val = *ptr;
|
||||
membar_consumer();
|
||||
return val;
|
||||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
membar_producer();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
#ifdef GOOGLE_PROTOBUF_ARCH_64_BIT
|
||||
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
return atomic_cas_64((volatile uint64_t*)ptr, (uint64_t)old_value, (uint64_t)new_value);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value) {
|
||||
return atomic_swap_64((volatile uint64_t*)ptr, (uint64_t)new_value);
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) {
|
||||
return atomic_add_64_nv((volatile uint64_t*)ptr, increment);
|
||||
}
|
||||
|
||||
inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment) {
|
||||
MemoryBarrier();
|
||||
Atomic64 ret = atomic_add_64_nv((volatile uint64_t*)ptr, increment);
|
||||
MemoryBarrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
Atomic64 ret = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
MemoryBarrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
|
||||
Atomic64 old_value,
|
||||
Atomic64 new_value) {
|
||||
MemoryBarrier();
|
||||
return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
|
||||
}
|
||||
|
||||
inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
*ptr = value;
|
||||
membar_producer();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
membar_consumer();
|
||||
*ptr = value;
|
||||
}
|
||||
|
||||
inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
||||
Atomic64 ret = *ptr;
|
||||
membar_consumer();
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
membar_producer();
|
||||
return *ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_SPARC_GCC_H_
|
||||
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче