Merge mozilla-central to b2g-inbound on a CLOSED TREE

This commit is contained in:
Carsten "Tomcat" Book 2015-04-23 08:50:44 +02:00
Родитель d54a73b8ac bab9dbe9c4
Коммит 997a9dedca
155 изменённых файлов: 2744 добавлений и 74763 удалений

Просмотреть файл

@ -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(&current_.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_(&copying_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_(&copying_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_(&copying_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_(&copying_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_

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше