Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink).pull/13171/head
parent
ea198bdcf9
commit
7d3e2bd2c4
88 changed files with 11187 additions and 7007 deletions
@ -1,39 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
|
||||
#include "bytestream.hpp" |
||||
|
||||
namespace upb { |
||||
|
||||
upb_bytesrc_vtbl* ByteSourceBase::vtable() { |
||||
static upb_bytesrc_vtbl vtbl = { |
||||
&ByteSourceBase::VFetch, |
||||
&ByteSourceBase::VDiscard, |
||||
&ByteSourceBase::VCopy, |
||||
&ByteSourceBase::VGetPtr, |
||||
}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
upb_bytesuccess_t ByteSourceBase::VFetch(void *src, uint64_t ofs, size_t *len) { |
||||
return static_cast<ByteSourceBase*>(src)->Fetch(ofs, len); |
||||
} |
||||
|
||||
void ByteSourceBase::VCopy( |
||||
const void *src, uint64_t ofs, size_t len, char* dest) { |
||||
static_cast<const ByteSourceBase*>(src)->Copy(ofs, len, dest); |
||||
} |
||||
|
||||
void ByteSourceBase::VDiscard(void *src, uint64_t ofs) { |
||||
static_cast<ByteSourceBase*>(src)->Discard(ofs); |
||||
} |
||||
|
||||
const char * ByteSourceBase::VGetPtr( |
||||
const void *src, uint64_t ofs, size_t* len) { |
||||
return static_cast<const ByteSourceBase*>(src)->GetPtr(ofs, len); |
||||
} |
||||
|
||||
} // namespace upb
|
@ -1,276 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// This file defines three core interfaces:
|
||||
// - upb::ByteSink: for writing streams of data.
|
||||
// - upb::ByteSource: for reading streams of data.
|
||||
// - upb::ByteRegion: for reading from a specific region of a ByteSource;
|
||||
// should be used by decoders instead of using a ByteSource directly.
|
||||
//
|
||||
// These interfaces are used by streaming encoders and decoders: for example, a
|
||||
// protobuf parser gets its input from a upb::ByteRegion. They are virtual
|
||||
// base classes so concrete implementations can get the data from a fd, a
|
||||
// FILE*, a string, etc.
|
||||
//
|
||||
// A ByteRegion represents a region of data from a ByteSource.
|
||||
//
|
||||
// Parsers get data from this interface instead of a bytesrc because we often
|
||||
// want to parse only a specific region of the input. For example, if we parse
|
||||
// a string from our input but know that the string represents a protobuf, we
|
||||
// can pass its ByteRegion to an appropriate protobuf parser.
|
||||
//
|
||||
// Since the bytes may be coming from a file or network socket, bytes must be
|
||||
// fetched before they can be read (though in some cases this fetch may be a
|
||||
// no-op). "fetch" is the only operation on a byteregion that could fail or
|
||||
// block, because it is the only operation that actually performs I/O.
|
||||
//
|
||||
// Bytes can be discarded when they are no longer needed. Parsers should
|
||||
// always discard bytes they no longer need, both so the buffers can be freed
|
||||
// when possible and to give better visibility into what bytes the parser is
|
||||
// still using.
|
||||
//
|
||||
// start discard read fetch end
|
||||
// ofs ofs ofs ofs ofs
|
||||
// | |--->Discard() | |--->Fetch() |
|
||||
// V V V V V
|
||||
// +-------------+-------------------------+-----------------+-----------------+
|
||||
// | discarded | | | fetchable |
|
||||
// +-------------+-------------------------+-----------------+-----------------+
|
||||
// | <------------- loaded ------------------> |
|
||||
// | <- available -> |
|
||||
// | <---------- remaining ----------> |
|
||||
//
|
||||
// Note that the start offset may be something other than zero! A byteregion
|
||||
// is a view into an underlying bytesrc stream, and the region may start
|
||||
// somewhere other than the beginning of that stream.
|
||||
//
|
||||
// The region can be either delimited or nondelimited. A non-delimited region
|
||||
// will keep returning data until the underlying data source returns EOF. A
|
||||
// delimited region will return EOF at a predetermined offset.
|
||||
//
|
||||
// end
|
||||
// ofs
|
||||
// |
|
||||
// V
|
||||
// +-----------------------+
|
||||
// | delimited region | <-- hard EOF, even if data source has more data.
|
||||
// +-----------------------+
|
||||
//
|
||||
// +------------------------
|
||||
// | nondelimited region Z <-- won't return EOF until data source hits EOF.
|
||||
// +------------------------
|
||||
|
||||
#ifndef UPB_BYTESTREAM_HPP |
||||
#define UPB_BYTESTREAM_HPP |
||||
|
||||
#include "upb/bytestream.h" |
||||
#include "upb/upb.hpp" |
||||
#include <string> |
||||
|
||||
namespace upb { |
||||
|
||||
typedef upb_bytesuccess_t ByteSuccess; |
||||
|
||||
// Implement this interface to vend bytes to ByteRegions which will be used by
|
||||
// a decoder.
|
||||
class ByteSourceBase : public upb_bytesrc { |
||||
public: |
||||
ByteSourceBase() { upb_bytesrc_init(this, vtable()); } |
||||
virtual ~ByteSourceBase() { upb_bytesrc_uninit(this); } |
||||
|
||||
// Fetches at least one byte starting at ofs, setting *len to the actual
|
||||
// number of bytes fetched (or 0 on EOF or error: see return value for
|
||||
// details). It is valid for bytes to be fetched multiple times, as long as
|
||||
// the bytes have not been previously discarded.
|
||||
virtual ByteSuccess Fetch(uint64_t ofs, size_t* len) = 0; |
||||
|
||||
// Discards all data prior to ofs (except data that is pinned, if pinning
|
||||
// support is added -- see TODO below).
|
||||
virtual void Discard(uint64_t ofs) = 0; |
||||
|
||||
// Copies "len" bytes of data from ofs to "dst", which must be at least "len"
|
||||
// bytes long. The given region must not be discarded.
|
||||
virtual void Copy(uint64_t ofs, size_t len, char *dst) const = 0; |
||||
|
||||
// Returns a pointer to the bytesrc's internal buffer, storing in *len how
|
||||
// much data is available. The given offset must not be discarded. The
|
||||
// returned buffer is valid for as long as its bytes are not discarded (in
|
||||
// the case that part of the returned buffer is discarded, only the
|
||||
// non-discarded bytes remain valid).
|
||||
virtual const char *GetPtr(uint64_t ofs, size_t *len) const = 0; |
||||
|
||||
// TODO: Add if/when there is a demonstrated need:
|
||||
//
|
||||
// // When the caller pins a region (which must not be already discarded), it
|
||||
// // is guaranteed that the region will not be discarded (nor will the
|
||||
// // bytesrc be destroyed) until the region is unpinned. However, not all
|
||||
// // bytesrc's support pinning; a false return indicates that a pin was not
|
||||
// // possible.
|
||||
// virtual bool Pin(uint64_t ofs, size_t len);
|
||||
//
|
||||
// // Releases some number of pinned bytes from the beginning of a pinned
|
||||
// // region (which may be fewer than the total number of bytes pinned).
|
||||
// virtual void Unpin(uint64_t ofs, size_t len, size_t bytes_to_release);
|
||||
//
|
||||
// Adding pinning support would also involve adding a "pin_ofs" parameter to
|
||||
// upb_bytesrc_fetch, so that the fetch can extend an already-pinned region.
|
||||
private: |
||||
static upb_bytesrc_vtbl* vtable(); |
||||
static upb_bytesuccess_t VFetch(void*, uint64_t, size_t*); |
||||
static void VDiscard(void*, uint64_t); |
||||
static void VCopy(const void*, uint64_t, size_t, char*); |
||||
static const char *VGetPtr(const void*, uint64_t, size_t*); |
||||
}; |
||||
|
||||
class ByteRegion : public upb_byteregion { |
||||
public: |
||||
static const uint64_t kNondelimited = UPB_NONDELIMITED; |
||||
|
||||
ByteRegion() { upb_byteregion_init(this); } |
||||
~ByteRegion() { upb_byteregion_uninit(this); } |
||||
|
||||
// Accessors for the regions bounds -- the meaning of these is described in
|
||||
// the diagram above.
|
||||
uint64_t start_ofs() const { return upb_byteregion_startofs(this); } |
||||
uint64_t discard_ofs() const { return upb_byteregion_discardofs(this); } |
||||
uint64_t fetch_ofs() const { return upb_byteregion_fetchofs(this); } |
||||
uint64_t end_ofs() const { return upb_byteregion_endofs(this); } |
||||
|
||||
// Returns how many bytes are fetched and available for reading starting from
|
||||
// offset "offset".
|
||||
uint64_t BytesAvailable(uint64_t offset) const { |
||||
return upb_byteregion_available(this, offset); |
||||
} |
||||
|
||||
// Returns the total number of bytes remaining after offset "offset", or
|
||||
// kNondelimited if the byteregion is non-delimited.
|
||||
uint64_t BytesRemaining(uint64_t offset) const { |
||||
return upb_byteregion_remaining(this, offset); |
||||
} |
||||
|
||||
uint64_t Length() const { return upb_byteregion_len(this); } |
||||
|
||||
// Sets the value of this byteregion to be a subset of the given byteregion's
|
||||
// data. The caller is responsible for releasing this region before the src
|
||||
// region is released (unless the region is first pinned, if pinning support
|
||||
// is added. see below).
|
||||
void Reset(const upb_byteregion *src, uint64_t ofs, uint64_t len) { |
||||
upb_byteregion_reset(this, src, ofs, len); |
||||
} |
||||
void Release() { upb_byteregion_release(this); } |
||||
|
||||
// Attempts to fetch more data, extending the fetched range of this
|
||||
// byteregion. Returns true if the fetched region was extended by at least
|
||||
// one byte, false on EOF or error (see *s for details).
|
||||
ByteSuccess Fetch() { return upb_byteregion_fetch(this); } |
||||
|
||||
// Fetches all remaining data, returning false if the operation failed (see
|
||||
// *s for details). May only be used on delimited byteregions.
|
||||
ByteSuccess FetchAll() { return upb_byteregion_fetchall(this); } |
||||
|
||||
// Discards bytes from the byteregion up until ofs (which must be greater or
|
||||
// equal to discard_ofs()). It is valid to discard bytes that have not been
|
||||
// fetched (such bytes will never be fetched) but it is an error to discard
|
||||
// past the end of a delimited byteregion.
|
||||
void Discard(uint64_t ofs) { return upb_byteregion_discard(this, ofs); } |
||||
|
||||
// Copies "len" bytes of data into "dst", starting at ofs. The specified
|
||||
// region must be available.
|
||||
void Copy(uint64_t ofs, size_t len, char *dst) const { |
||||
upb_byteregion_copy(this, ofs, len, dst); |
||||
} |
||||
|
||||
// Copies all bytes from the byteregion into dst. Requires that the entire
|
||||
// byteregion is fetched and that none has been discarded.
|
||||
void CopyAll(char *dst) const { |
||||
upb_byteregion_copyall(this, dst); |
||||
} |
||||
|
||||
// Returns a pointer to the internal buffer for the byteregion starting at
|
||||
// offset "ofs." Stores the number of bytes available in this buffer in *len.
|
||||
// The returned buffer is invalidated when the byteregion is reset or
|
||||
// released, or when the bytes are discarded. If the byteregion is not
|
||||
// currently pinned, the pointer is only valid for the lifetime of the parent
|
||||
// byteregion.
|
||||
const char *GetPtr(uint64_t ofs, size_t *len) const { |
||||
return upb_byteregion_getptr(this, ofs, len); |
||||
} |
||||
|
||||
// Copies the contents of the byteregion into a newly-allocated,
|
||||
// NULL-terminated string. Requires that the byteregion is fully fetched.
|
||||
char *StrDup() const { |
||||
return upb_byteregion_strdup(this); |
||||
} |
||||
|
||||
template <typename T> void AssignToString(T* str) { |
||||
uint64_t ofs = start_ofs(); |
||||
size_t len; |
||||
const char *ptr = GetPtr(ofs, &len); |
||||
// Emperically calling reserve() here is counterproductive and slows down
|
||||
// benchmarks. If the parsing is happening in a tight loop that is reusing
|
||||
// the string object, there is probably enough data reserved already and
|
||||
// the reserve() call is extra overhead.
|
||||
str->assign(ptr, len); |
||||
ofs += len; |
||||
while (ofs < end_ofs()) { |
||||
ptr = GetPtr(ofs, &len); |
||||
str->append(ptr, len); |
||||
ofs += len; |
||||
} |
||||
} |
||||
|
||||
// TODO: add if/when there is a demonstrated need.
|
||||
//
|
||||
// // Pins this byteregion's bytes in memory, allowing it to outlive its
|
||||
// // parent byteregion. Normally a byteregion may only be used while its
|
||||
// // parent is still valid, but a pinned byteregion may continue to be used
|
||||
// // until it is reset or released. A byteregion must be fully fetched to
|
||||
// // be pinned (this implies that the byteregion must be delimited).
|
||||
// //
|
||||
// // In some cases this operation may cause the input data to be copied.
|
||||
// //
|
||||
// // void Pin();
|
||||
}; |
||||
|
||||
class StringSource : public upb_stringsrc { |
||||
public: |
||||
StringSource() : upb_stringsrc() { upb_stringsrc_init(this); } |
||||
template <typename T> explicit StringSource(const T& str) { |
||||
upb_stringsrc_init(this); |
||||
Reset(str); |
||||
} |
||||
StringSource(const char *data, size_t len) { |
||||
upb_stringsrc_init(this); |
||||
Reset(data, len); |
||||
} |
||||
~StringSource() { upb_stringsrc_uninit(this); } |
||||
|
||||
void Reset(const char* data, size_t len) { |
||||
upb_stringsrc_reset(this, data, len); |
||||
} |
||||
|
||||
template <typename T> void Reset(const T& str) { |
||||
Reset(str.c_str(), str.size()); |
||||
} |
||||
|
||||
ByteRegion* AllBytes() { |
||||
return static_cast<ByteRegion*>(upb_stringsrc_allbytes(this)); |
||||
} |
||||
|
||||
upb_bytesrc* ByteSource() { return upb_stringsrc_bytesrc(this); } |
||||
}; |
||||
|
||||
template <> inline ByteRegion* GetValue<ByteRegion*>(Value v) { |
||||
return static_cast<ByteRegion*>(upb_value_getbyteregion(v)); |
||||
} |
||||
|
||||
template <> inline Value MakeValue<ByteRegion*>(ByteRegion* v) { |
||||
return upb_value_byteregion(v); |
||||
} |
||||
|
||||
} // namespace upb
|
||||
|
||||
#endif |
@ -1,462 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// The set of upb::*Def classes and upb::SymbolTable allow for defining and
|
||||
// manipulating schema information (as defined in .proto files).
|
||||
//
|
||||
// Defs go through two distinct phases of life:
|
||||
//
|
||||
// 1. MUTABLE: when first created, the properties of the def can be set freely
|
||||
// (for example a message's name, its list of fields, the name/number of
|
||||
// fields, etc). During this phase the def is *not* thread-safe, and may
|
||||
// not be used for any purpose except to set its properties (it can't be
|
||||
// used to parse anything, create any messages in memory, etc).
|
||||
//
|
||||
// 2. FINALIZED: the Def::Finzlie() operation finalizes a set of defs,
|
||||
// which makes them thread-safe and immutable. Finalized defs may only be
|
||||
// accessed through a CONST POINTER. If you want to modify an existing
|
||||
// immutable def, copy it with Dup() and modify and finalize the copy.
|
||||
//
|
||||
// The refcounting of defs works properly no matter what state the def is in.
|
||||
// Once the def is finalized it is guaranteed that any def reachable from a
|
||||
// live def is also live (so a ref on the base of a message tree keeps the
|
||||
// whole tree alive).
|
||||
//
|
||||
// You can test for which stage of life a def is in by calling IsMutable().
|
||||
// This is particularly useful for dynamic language bindings, which must
|
||||
// properly guarantee that the dynamic language cannot break the rules laid out
|
||||
// above.
|
||||
//
|
||||
// It would be possible to make the defs thread-safe during stage 1 by using
|
||||
// mutexes internally and changing any methods returning pointers to return
|
||||
// copies instead. This could be important if we are integrating with a VM or
|
||||
// interpreter that does not naturally serialize access to wrapped objects (for
|
||||
// example, in the case of Python this is not necessary because of the GIL).
|
||||
|
||||
#ifndef UPB_DEF_HPP |
||||
#define UPB_DEF_HPP |
||||
|
||||
#include <algorithm> |
||||
#include <string> |
||||
#include <vector> |
||||
#include "upb/def.h" |
||||
#include "upb/upb.hpp" |
||||
|
||||
namespace upb { |
||||
|
||||
class Def; |
||||
class MessageDef; |
||||
|
||||
typedef upb_fieldtype_t FieldType; |
||||
typedef upb_label_t Label; |
||||
|
||||
class FieldDef : public upb_fielddef { |
||||
public: |
||||
static FieldDef* Cast(upb_fielddef *f) { return static_cast<FieldDef*>(f); } |
||||
static const FieldDef* Cast(const upb_fielddef *f) { |
||||
return static_cast<const FieldDef*>(f); |
||||
} |
||||
|
||||
static FieldDef* New(const void *owner) { |
||||
return Cast(upb_fielddef_new(owner)); |
||||
} |
||||
FieldDef* Dup(const void *owner) const { |
||||
return Cast(upb_fielddef_dup(this, owner)); |
||||
} |
||||
void Ref(const void *owner) { upb_fielddef_ref(this, owner); } |
||||
void Unref(const void *owner) { upb_fielddef_unref(this, owner); } |
||||
|
||||
bool IsMutable() const { return upb_fielddef_ismutable(this); } |
||||
bool IsFinalized() const { return upb_fielddef_isfinalized(this); } |
||||
bool IsString() const { return upb_isstring(this); } |
||||
bool IsSequence() const { return upb_isseq(this); } |
||||
bool IsSubmessage() const { return upb_issubmsg(this); } |
||||
|
||||
// Simple accessors. /////////////////////////////////////////////////////////
|
||||
|
||||
FieldType type() const { return upb_fielddef_type(this); } |
||||
Label label() const { return upb_fielddef_label(this); } |
||||
int32_t number() const { return upb_fielddef_number(this); } |
||||
std::string name() const { return std::string(upb_fielddef_name(this)); } |
||||
Value default_() const { return upb_fielddef_default(this); } |
||||
Value bound_value() const { return upb_fielddef_fval(this); } |
||||
uint16_t offset() const { return upb_fielddef_offset(this); } |
||||
int16_t hasbit() const { return upb_fielddef_hasbit(this); } |
||||
|
||||
bool set_type(FieldType type) { return upb_fielddef_settype(this, type); } |
||||
bool set_label(Label label) { return upb_fielddef_setlabel(this, label); } |
||||
void set_offset(uint16_t offset) { upb_fielddef_setoffset(this, offset); } |
||||
void set_hasbit(int16_t hasbit) { upb_fielddef_sethasbit(this, hasbit); } |
||||
void set_fval(Value fval) { upb_fielddef_setfval(this, fval); } |
||||
void set_accessor(struct _upb_accessor_vtbl* vtbl) { |
||||
upb_fielddef_setaccessor(this, vtbl); |
||||
} |
||||
MessageDef* message(); |
||||
const MessageDef* message() const; |
||||
|
||||
struct _upb_accessor_vtbl *accessor() const { |
||||
return upb_fielddef_accessor(this); |
||||
} |
||||
|
||||
// "Number" and "name" must be set before the fielddef is added to a msgdef.
|
||||
// For the moment we do not allow these to be set once the fielddef is added
|
||||
// to a msgdef -- this could be relaxed in the future.
|
||||
bool set_number(int32_t number) { |
||||
return upb_fielddef_setnumber(this, number); |
||||
} |
||||
bool set_name(const char *name) { return upb_fielddef_setname(this, name); } |
||||
bool set_name(const std::string& name) { return set_name(name.c_str()); } |
||||
|
||||
// Default value. ////////////////////////////////////////////////////////////
|
||||
|
||||
// Returns the default value for this fielddef, which may either be something
|
||||
// the client set explicitly or the "default default" (0 for numbers, empty
|
||||
// for strings). The field's type indicates the type of the returned value,
|
||||
// except for enum fields that are still mutable.
|
||||
//
|
||||
// For enums the default can be set either numerically or symbolically -- the
|
||||
// upb_fielddef_default_is_symbolic() function below will indicate which it
|
||||
// is. For string defaults, the value will be a upb_byteregion which is
|
||||
// invalidated by any other non-const call on this object. Once the fielddef
|
||||
// is finalized, symbolic enum defaults are resolved, so finalized enum
|
||||
// fielddefs always have a default of type int32.
|
||||
Value defaultval() { return upb_fielddef_default(this); } |
||||
|
||||
// Sets default value for the field. For numeric types, use
|
||||
// upb_fielddef_setdefault(), and "value" must match the type of the field.
|
||||
// For string/bytes types, use upb_fielddef_setdefaultstr(). Enum types may
|
||||
// use either, since the default may be set either numerically or
|
||||
// symbolically.
|
||||
//
|
||||
// NOTE: May only be called for fields whose type has already been set.
|
||||
// Also, will be reset to default if the field's type is set again.
|
||||
void set_default(Value value) { upb_fielddef_setdefault(this, value); } |
||||
void set_default(const char *str) { upb_fielddef_setdefaultcstr(this, str); } |
||||
void set_default(const char *str, size_t len) { |
||||
upb_fielddef_setdefaultstr(this, str, len); |
||||
} |
||||
void set_default(const std::string& str) { |
||||
upb_fielddef_setdefaultstr(this, str.c_str(), str.size()); |
||||
} |
||||
|
||||
// The results of this function are only meaningful for mutable enum fields,
|
||||
// which can have a default specified either as an integer or as a string.
|
||||
// If this returns true, the default returned from upb_fielddef_default() is
|
||||
// a string, otherwise it is an integer.
|
||||
bool DefaultIsSymbolic() { return upb_fielddef_default_is_symbolic(this); } |
||||
|
||||
// Subdef. ///////////////////////////////////////////////////////////////////
|
||||
|
||||
// Submessage and enum fields must reference a "subdef", which is the
|
||||
// MessageDef or EnumDef that defines their type. Note that when the
|
||||
// FieldDef is mutable it may not have a subdef *yet*, but this still returns
|
||||
// true to indicate that the field's type requires a subdef.
|
||||
bool HasSubDef() { return upb_hassubdef(this); } |
||||
|
||||
// Before a FieldDef is finalized, its subdef may be set either directly
|
||||
// (with a Def*) or symbolically. Symbolic refs must be resolved by the
|
||||
// client before the containing msgdef can be finalized.
|
||||
//
|
||||
// Both methods require that HasSubDef() (so the type must be set prior to
|
||||
// calling these methods). Returns false if this is not the case, or if the
|
||||
// given subdef is not of the correct type. The subtype is reset if the
|
||||
// field's type is changed.
|
||||
bool set_subdef(Def* def); |
||||
bool set_subtype_name(const char *name) { |
||||
return upb_fielddef_setsubtypename(this, name); |
||||
} |
||||
bool set_subtype_name(const std::string& str) { |
||||
return set_subtype_name(str.c_str()); |
||||
} |
||||
|
||||
// Returns the enum or submessage def or symbolic name for this field, if
|
||||
// any. May only be called for fields where HasSubDef() is true. Returns
|
||||
// NULL if the subdef has not been set or if you ask for a subtype name when
|
||||
// the subtype is currently set symbolically (or vice-versa).
|
||||
//
|
||||
// Caller does *not* own a ref on the returned def or string.
|
||||
// subtypename_name() is non-const because only mutable defs can have the
|
||||
// subtype name set symbolically (symbolic references must be resolved before
|
||||
// the MessageDef can be finalized).
|
||||
const Def* subdef() const; |
||||
const char *subtype_name() { return upb_fielddef_subtypename(this); } |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(FieldDef); |
||||
}; |
||||
|
||||
class Def : public upb_def { |
||||
public: |
||||
// Converting from C types to C++ wrapper types.
|
||||
static Def* Cast(upb_def *def) { return static_cast<Def*>(def); } |
||||
static const Def* Cast(const upb_def *def) { |
||||
return static_cast<const Def*>(def); |
||||
} |
||||
|
||||
void Ref(const void *owner) const { upb_def_ref(this, owner); } |
||||
void Unref(const void *owner) const { upb_def_unref(this, owner); } |
||||
|
||||
void set_full_name(const char *name) { upb_def_setfullname(this, name); } |
||||
void set_full_name(const std::string& name) { |
||||
upb_def_setfullname(this, name.c_str()); |
||||
} |
||||
|
||||
const char *full_name() const { return upb_def_fullname(this); } |
||||
|
||||
// Finalizes the given list of defs (as well as the fielddefs for the given
|
||||
// msgdefs). All defs reachable from any def in this list must either be
|
||||
// already finalized or elsewhere in the list. Any symbolic references to
|
||||
// enums or submessages must already have been resolved. Returns true on
|
||||
// success, otherwise false is returned and status contains details. In the
|
||||
// error case the input defs are unmodified. See the comment at the top of
|
||||
// this file for the semantics of finalized defs.
|
||||
//
|
||||
// n is currently limited to 64k defs, if more are required break them into
|
||||
// batches of 64k (or we could raise this limit, at the cost of a bigger
|
||||
// upb_def structure or complexity in upb_def_finalize()).
|
||||
static bool Finalize(Def*const* defs, int n, Status* status) { |
||||
return upb_finalize(reinterpret_cast<upb_def*const*>(defs), n, status); |
||||
} |
||||
static bool Finalize(const std::vector<Def*>& defs, Status* status) { |
||||
return Finalize(&defs[0], defs.size(), status); |
||||
} |
||||
}; |
||||
|
||||
class MessageDef : public upb_msgdef { |
||||
public: |
||||
// Converting from C types to C++ wrapper types.
|
||||
static MessageDef* Cast(upb_msgdef *md) { |
||||
return static_cast<MessageDef*>(md); |
||||
} |
||||
static const MessageDef* Cast(const upb_msgdef *md) { |
||||
return static_cast<const MessageDef*>(md); |
||||
} |
||||
static MessageDef* DynamicCast(Def* def) { |
||||
return Cast(upb_dyncast_msgdef(def)); |
||||
} |
||||
static const MessageDef* DynamicCast(const Def* def) { |
||||
return Cast(upb_dyncast_msgdef_const(def)); |
||||
} |
||||
|
||||
Def* AsDef() { return Def::Cast(UPB_UPCAST(this)); } |
||||
const Def* AsDef() const { return Def::Cast(UPB_UPCAST(this)); } |
||||
|
||||
static MessageDef* New(void *owner) { return Cast(upb_msgdef_new(owner)); } |
||||
MessageDef* Dup(void *owner) const { |
||||
return Cast(upb_msgdef_dup(this, owner)); |
||||
} |
||||
|
||||
void Ref(const void *owner) const { upb_msgdef_ref(this, owner); } |
||||
void Unref(const void *owner) const { upb_msgdef_unref(this, owner); } |
||||
|
||||
// Read accessors -- may be called at any time.
|
||||
|
||||
const char *full_name() const { return AsDef()->full_name(); } |
||||
|
||||
// The total size of in-memory messages created with this MessageDef.
|
||||
uint16_t instance_size() const { return upb_msgdef_size(this); } |
||||
|
||||
// The number of "hasbit" bytes in a message instance.
|
||||
uint8_t hasbit_bytes() const { return upb_msgdef_hasbit_bytes(this); } |
||||
|
||||
uint32_t extension_start() const { return upb_msgdef_extstart(this); } |
||||
uint32_t extension_end() const { return upb_msgdef_extend(this); } |
||||
|
||||
// Write accessors. May only be called before the msgdef is in a symtab.
|
||||
|
||||
void set_full_name(const char *name) { AsDef()->set_full_name(name); } |
||||
void set_full_name(const std::string& name) { AsDef()->set_full_name(name); } |
||||
|
||||
void set_instance_size(uint16_t size) { upb_msgdef_setsize(this, size); } |
||||
void set_hasbit_bytes(uint16_t size) { upb_msgdef_setsize(this, size); } |
||||
bool SetExtensionRange(uint32_t start, uint32_t end) { |
||||
return upb_msgdef_setextrange(this, start, end); |
||||
} |
||||
|
||||
// Adds a set of fields (FieldDef objects) to a MessageDef. Caller passes a
|
||||
// ref on the FieldDef to the MessageDef in both success and failure cases.
|
||||
// May only be done before the MessageDef is in a SymbolTable (requires
|
||||
// m->IsMutable() for the MessageDef). The FieldDef's name and number must
|
||||
// be set, and the message may not already contain any field with this name
|
||||
// or number, and this FieldDef may not be part of another message, otherwise
|
||||
// false is returned and the MessageDef is unchanged.
|
||||
bool AddField(FieldDef* f, const void *owner) { |
||||
return AddFields(&f, 1, owner); |
||||
} |
||||
bool AddFields(FieldDef*const * f, int n, const void *owner) { |
||||
return upb_msgdef_addfields(this, (upb_fielddef*const*)f, n, owner); |
||||
} |
||||
bool AddFields(const std::vector<FieldDef*>& fields, const void *owner) { |
||||
return AddFields(&fields[0], fields.size(), owner); |
||||
} |
||||
|
||||
int field_count() const { return upb_msgdef_numfields(this); } |
||||
|
||||
// Lookup fields by name or number, returning NULL if no such field exists.
|
||||
FieldDef* FindFieldByName(const char *name) { |
||||
return FieldDef::Cast(upb_msgdef_ntof(this, name)); |
||||
} |
||||
FieldDef* FindFieldByName(const std::string& name) { |
||||
return FieldDef::Cast(upb_msgdef_ntof(this, name.c_str())); |
||||
} |
||||
FieldDef* FindFieldByNumber(uint32_t num) { |
||||
return FieldDef::Cast(upb_msgdef_itof(this, num)); |
||||
} |
||||
|
||||
const FieldDef* FindFieldByName(const char *name) const { |
||||
return FindFieldByName(name); |
||||
} |
||||
const FieldDef* FindFieldByName(const std::string& name) const { |
||||
return FindFieldByName(name); |
||||
} |
||||
const FieldDef* FindFieldByNumber(uint32_t num) const { |
||||
return FindFieldByNumber(num); |
||||
} |
||||
|
||||
class Iterator : public upb_msg_iter { |
||||
public: |
||||
explicit Iterator(MessageDef* md) { upb_msg_begin(this, md); } |
||||
Iterator() {} |
||||
|
||||
FieldDef* field() { return FieldDef::Cast(upb_msg_iter_field(this)); } |
||||
bool Done() { return upb_msg_done(this); } |
||||
void Next() { return upb_msg_next(this); } |
||||
}; |
||||
|
||||
class ConstIterator : public upb_msg_iter { |
||||
public: |
||||
explicit ConstIterator(const MessageDef* md) { upb_msg_begin(this, md); } |
||||
ConstIterator() {} |
||||
|
||||
const FieldDef* field() { return FieldDef::Cast(upb_msg_iter_field(this)); } |
||||
bool Done() { return upb_msg_done(this); } |
||||
void Next() { return upb_msg_next(this); } |
||||
}; |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(MessageDef); |
||||
}; |
||||
|
||||
class EnumDef : public upb_enumdef { |
||||
public: |
||||
// Converting from C types to C++ wrapper types.
|
||||
static EnumDef* Cast(upb_enumdef *e) { return static_cast<EnumDef*>(e); } |
||||
static const EnumDef* Cast(const upb_enumdef *e) { |
||||
return static_cast<const EnumDef*>(e); |
||||
} |
||||
|
||||
static EnumDef* New(const void *owner) { return Cast(upb_enumdef_new(owner)); } |
||||
|
||||
void Ref(const void *owner) { upb_enumdef_ref(this, owner); } |
||||
void Unref(const void *owner) { upb_enumdef_unref(this, owner); } |
||||
EnumDef* Dup(const void *owner) const { |
||||
return Cast(upb_enumdef_dup(this, owner)); |
||||
} |
||||
|
||||
Def* AsDef() { return Def::Cast(UPB_UPCAST(this)); } |
||||
const Def* AsDef() const { return Def::Cast(UPB_UPCAST(this)); } |
||||
|
||||
int32_t default_value() const { return upb_enumdef_default(this); } |
||||
|
||||
// May only be set if IsMutable().
|
||||
void set_full_name(const char *name) { AsDef()->set_full_name(name); } |
||||
void set_full_name(const std::string& name) { AsDef()->set_full_name(name); } |
||||
void set_default_value(int32_t val) { |
||||
return upb_enumdef_setdefault(this, val); |
||||
} |
||||
|
||||
// Adds a value to the enumdef. Requires that no existing val has this
|
||||
// name or number (returns false and does not add if there is). May only
|
||||
// be called if IsMutable().
|
||||
bool AddValue(char *name, int32_t num) { |
||||
return upb_enumdef_addval(this, name, num); |
||||
} |
||||
bool AddValue(const std::string& name, int32_t num) { |
||||
return upb_enumdef_addval(this, name.c_str(), num); |
||||
} |
||||
|
||||
// Lookups from name to integer and vice-versa.
|
||||
bool LookupName(const char *name, int32_t* num) const { |
||||
return upb_enumdef_ntoi(this, name, num); |
||||
} |
||||
|
||||
// Lookup from integer to name, returns a NULL-terminated string which
|
||||
// the caller does not own, or NULL if not found.
|
||||
const char *LookupNumber(int32_t num) const { |
||||
return upb_enumdef_iton(this, num); |
||||
} |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(EnumDef); |
||||
}; |
||||
|
||||
class SymbolTable : public upb_symtab { |
||||
public: |
||||
// Converting from C types to C++ wrapper types.
|
||||
static SymbolTable* Cast(upb_symtab *s) { |
||||
return static_cast<SymbolTable*>(s); |
||||
} |
||||
static const SymbolTable* Cast(const upb_symtab *s) { |
||||
return static_cast<const SymbolTable*>(s); |
||||
} |
||||
|
||||
static SymbolTable* New(const void *owner) { |
||||
return Cast(upb_symtab_new(owner)); |
||||
} |
||||
|
||||
void Ref(const void *owner) const { upb_symtab_unref(this, owner); } |
||||
void Unref(const void *owner) const { upb_symtab_unref(this, owner); } |
||||
void DonateRef(const void *from, const void *to) const { |
||||
upb_symtab_donateref(this, from, to); |
||||
} |
||||
|
||||
// Adds the given defs to the symtab, resolving all symbols. Only one def
|
||||
// per name may be in the list, but defs can replace existing defs in the
|
||||
// symtab. The entire operation either succeeds or fails. If the operation
|
||||
// fails, the symtab is unchanged, false is returned, and status indicates
|
||||
// the error. The caller passes a ref on the defs in all cases.
|
||||
bool Add(Def *const *defs, int n, void *owner, Status* status) { |
||||
return upb_symtab_add(this, (upb_def*const*)defs, n, owner, status); |
||||
} |
||||
bool Add(const std::vector<Def*>& defs, void *owner, Status* status) { |
||||
return Add(&defs[0], defs.size(), owner, status); |
||||
} |
||||
|
||||
// If the given name refers to a message in this symbol table, returns a new
|
||||
// ref to that MessageDef object, otherwise returns NULL.
|
||||
const MessageDef* LookupMessage(const char *name, void *owner) const { |
||||
return MessageDef::Cast(upb_symtab_lookupmsg(this, name, owner)); |
||||
} |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(SymbolTable); |
||||
}; |
||||
|
||||
template <> inline const FieldDef* GetValue<const FieldDef*>(Value v) { |
||||
return static_cast<const FieldDef*>(upb_value_getfielddef(v)); |
||||
} |
||||
|
||||
template <> inline Value MakeValue<FieldDef*>(FieldDef* v) { |
||||
return upb_value_fielddef(v); |
||||
} |
||||
|
||||
inline MessageDef* FieldDef::message() { |
||||
return MessageDef::Cast(upb_fielddef_msgdef(this)); |
||||
} |
||||
inline const MessageDef* FieldDef::message() const { |
||||
return MessageDef::Cast(upb_fielddef_msgdef(this)); |
||||
} |
||||
|
||||
inline const Def* FieldDef::subdef() const { |
||||
return Def::Cast(upb_fielddef_subdef(this)); |
||||
} |
||||
inline bool FieldDef::set_subdef(Def* def) { |
||||
return upb_fielddef_setsubdef(this, def); |
||||
} |
||||
|
||||
} // namespace upb
|
||||
|
||||
#endif |
@ -1,39 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
|
||||
#include "handlers.hpp" |
||||
|
||||
#include "def.hpp" |
||||
|
||||
namespace upb { |
||||
|
||||
namespace { |
||||
|
||||
void MessageCallbackWrapper( |
||||
void* closure, upb_mhandlers* mh, const upb_msgdef* m) { |
||||
Handlers::MessageRegistrationVisitor* visitor = |
||||
static_cast<Handlers::MessageRegistrationVisitor*>(closure); |
||||
visitor->OnMessage(static_cast<MessageHandlers*>(mh), |
||||
static_cast<const MessageDef*>(m)); |
||||
} |
||||
|
||||
void FieldCallbackWrapper( |
||||
void* closure, upb_fhandlers* fh, const upb_fielddef* f) { |
||||
Handlers::MessageRegistrationVisitor* visitor = |
||||
static_cast<Handlers::MessageRegistrationVisitor*>(closure); |
||||
visitor->OnField(static_cast<FieldHandlers*>(fh), |
||||
static_cast<const FieldDef*>(f)); |
||||
} |
||||
} // namepace
|
||||
|
||||
MessageHandlers* Handlers::RegisterMessageDef( |
||||
const MessageDef& m, Handlers::MessageRegistrationVisitor* visitor) { |
||||
upb_mhandlers* mh = upb_handlers_regmsgdef( |
||||
this, &m, &MessageCallbackWrapper, &FieldCallbackWrapper, &visitor); |
||||
return static_cast<MessageHandlers*>(mh); |
||||
} |
||||
|
||||
} // namespace upb
|
@ -1,176 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// upb::Handlers is a generic visitor-like interface for iterating over a
|
||||
// stream of protobuf data. You can register function pointers that will be
|
||||
// called for each message and/or field as the data is being parsed or iterated
|
||||
// over, without having to know the source format that we are parsing from.
|
||||
// This decouples the parsing logic from the processing logic.
|
||||
|
||||
#ifndef UPB_HANDLERS_HPP |
||||
#define UPB_HANDLERS_HPP |
||||
|
||||
#include "upb/handlers.h" |
||||
|
||||
#include "upb/upb.hpp" |
||||
|
||||
namespace upb { |
||||
|
||||
typedef upb_fieldtype_t FieldType; |
||||
typedef upb_flow_t Flow; |
||||
typedef upb_sflow_t SubFlow; |
||||
class MessageHandlers; |
||||
class MessageDef; |
||||
class FieldDef; |
||||
|
||||
class FieldHandlers : public upb_fhandlers { |
||||
public: |
||||
typedef upb_value_handler ValueHandler; |
||||
typedef upb_startfield_handler StartFieldHandler; |
||||
typedef upb_endfield_handler EndFieldHandler; |
||||
|
||||
// The FieldHandlers will live at least as long as the upb::Handlers to
|
||||
// which it belongs, but can be Ref'd/Unref'd to make it live longer (which
|
||||
// will prolong the life of the underlying upb::Handlers also).
|
||||
void Ref() { upb_fhandlers_ref(this); } |
||||
void Unref() { upb_fhandlers_unref(this); } |
||||
|
||||
// Functions to set this field's handlers.
|
||||
// These return "this" so they can be conveniently chained, eg.
|
||||
// message_handlers->NewField(...)
|
||||
// ->SetStartSequenceHandler(&StartSequence),
|
||||
// ->SetEndSequenceHandler(&EndSequence),
|
||||
// ->SetValueHandler(&Value);
|
||||
FieldHandlers* SetValueHandler(ValueHandler* h) { |
||||
upb_fhandlers_setvalue(this, h); return this; |
||||
} |
||||
FieldHandlers* SetStartSequenceHandler(StartFieldHandler* h) { |
||||
upb_fhandlers_setstartseq(this, h); return this; |
||||
} |
||||
FieldHandlers* SetEndSequenceHandler(EndFieldHandler* h) { |
||||
upb_fhandlers_setendseq(this, h); return this; |
||||
} |
||||
FieldHandlers* SetStartSubmessageHandler(StartFieldHandler* h) { |
||||
upb_fhandlers_setstartsubmsg(this, h); return this; |
||||
} |
||||
FieldHandlers* SetEndSubmessageHandler(EndFieldHandler* h) { |
||||
upb_fhandlers_setendsubmsg(this, h); return this; |
||||
} |
||||
|
||||
// Get/Set the field's bound value, which will be passed to its handlers.
|
||||
Value GetBoundValue() const { return upb_fhandlers_getfval(this); } |
||||
FieldHandlers* SetBoundValue(Value val) { |
||||
upb_fhandlers_setfval(this, val); return this; |
||||
} |
||||
|
||||
// Returns the MessageHandlers to which we belong.
|
||||
MessageHandlers* GetMessageHandlers() const; |
||||
// Returns the MessageHandlers for this field's submessage (invalid to call
|
||||
// unless this field's type UPB_TYPE(MESSAGE) or UPB_TYPE(GROUP).
|
||||
MessageHandlers* GetSubMessageHandlers() const; |
||||
// If set to >=0, the given hasbit will be set after the value callback is
|
||||
// called (offset relative to the current closure).
|
||||
int32_t GetHasbit() const { return upb_fhandlers_gethasbit(this); } |
||||
void SetHasbit(int32_t bit) { upb_fhandlers_sethasbit(this, bit); } |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(FieldHandlers); |
||||
}; |
||||
|
||||
class MessageHandlers : public upb_mhandlers { |
||||
public: |
||||
typedef upb_startmsg_handler StartMessageHandler; |
||||
typedef upb_endmsg_handler EndMessageHandler; |
||||
|
||||
static MessageHandlers* Cast(upb_mhandlers* mh) { |
||||
return static_cast<MessageHandlers*>(mh); |
||||
} |
||||
static const MessageHandlers* Cast(const upb_mhandlers* mh) { |
||||
return static_cast<const MessageHandlers*>(mh); |
||||
} |
||||
|
||||
// The MessageHandlers will live at least as long as the upb::Handlers to
|
||||
// which it belongs, but can be Ref'd/Unref'd to make it live longer (which
|
||||
// will prolong the life of the underlying upb::Handlers also).
|
||||
void Ref() { upb_mhandlers_ref(this); } |
||||
void Unref() { upb_mhandlers_unref(this); } |
||||
|
||||
// Functions to set this message's handlers.
|
||||
// These return "this" so they can be conveniently chained, eg.
|
||||
// handlers->NewMessageHandlers()
|
||||
// ->SetStartMessageHandler(&StartMessage)
|
||||
// ->SetEndMessageHandler(&EndMessage);
|
||||
MessageHandlers* SetStartMessageHandler(StartMessageHandler* h) { |
||||
upb_mhandlers_setstartmsg(this, h); return this; |
||||
} |
||||
MessageHandlers* SetEndMessageHandler(EndMessageHandler* h) { |
||||
upb_mhandlers_setendmsg(this, h); return this; |
||||
} |
||||
|
||||
// Functions to create new FieldHandlers for this message.
|
||||
FieldHandlers* NewFieldHandlers(uint32_t fieldnum, FieldType type, |
||||
bool repeated) { |
||||
return static_cast<FieldHandlers*>( |
||||
upb_mhandlers_newfhandlers(this, fieldnum, type, repeated)); |
||||
} |
||||
|
||||
// Like the previous but for MESSAGE or GROUP fields. For GROUP fields, the
|
||||
// given submessage must not have any fields with this field number.
|
||||
FieldHandlers* NewFieldHandlersForSubmessage(uint32_t n, const char *name, |
||||
FieldType type, bool repeated, |
||||
MessageHandlers* subm) { |
||||
(void)name; |
||||
return static_cast<FieldHandlers*>( |
||||
upb_mhandlers_newfhandlers_subm(this, n, type, repeated, subm)); |
||||
} |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(MessageHandlers); |
||||
}; |
||||
|
||||
class Handlers : public upb_handlers { |
||||
public: |
||||
// Creates a new Handlers instance.
|
||||
static Handlers* New() { return static_cast<Handlers*>(upb_handlers_new()); } |
||||
|
||||
void Ref() { upb_handlers_ref(this); } |
||||
void Unref() { upb_handlers_unref(this); } |
||||
|
||||
// Returns a new MessageHandlers object. The first such message that is
|
||||
// obtained will be the top-level message for this Handlers object.
|
||||
MessageHandlers* NewMessageHandlers() { |
||||
return static_cast<MessageHandlers*>(upb_handlers_newmhandlers(this)); |
||||
} |
||||
|
||||
// Convenience function for registering handlers for all messages and fields
|
||||
// in a MessageDef and all its children. For every registered message,
|
||||
// OnMessage will be called on the visitor with newly-created MessageHandlers
|
||||
// and MessageDef. Likewise with OnField will be called with newly-created
|
||||
// FieldHandlers and FieldDef for each field.
|
||||
class MessageRegistrationVisitor { |
||||
public: |
||||
virtual ~MessageRegistrationVisitor() {} |
||||
virtual void OnMessage(MessageHandlers* mh, const MessageDef* m) = 0; |
||||
virtual void OnField(FieldHandlers* fh, const FieldDef* f) = 0; |
||||
}; |
||||
MessageHandlers* RegisterMessageDef(const MessageDef& m, |
||||
MessageRegistrationVisitor* visitor); |
||||
|
||||
private: |
||||
UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(Handlers); |
||||
}; |
||||
|
||||
inline MessageHandlers* FieldHandlers::GetMessageHandlers() const { |
||||
return static_cast<MessageHandlers*>(upb_fhandlers_getmsg(this)); |
||||
} |
||||
|
||||
inline MessageHandlers* FieldHandlers::GetSubMessageHandlers() const { |
||||
return static_cast<MessageHandlers*>(upb_fhandlers_getsubmsg(this)); |
||||
} |
||||
|
||||
} // namespace upb
|
||||
|
||||
#endif |
@ -1,62 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
// Routines for reading and writing message data to an in-memory structure,
|
||||
// similar to a C struct.
|
||||
//
|
||||
// upb does not define one single message object that everyone must use.
|
||||
// Rather it defines an abstract interface for reading and writing members
|
||||
// of a message object, and all of the parsers and serializers use this
|
||||
// abstract interface. This allows upb's parsers and serializers to be used
|
||||
// regardless of what memory management scheme or synchronization model the
|
||||
// application is using.
|
||||
//
|
||||
// A standard set of accessors is provided for doing simple reads and writes at
|
||||
// a known offset into the message. These accessors should be used when
|
||||
// possible, because they are specially optimized -- for example, the JIT can
|
||||
// recognize them and emit specialized code instead of having to call the
|
||||
// function at all. The application can substitute its own accessors when the
|
||||
// standard accessors are not suitable.
|
||||
|
||||
#ifndef UPB_MSG_HPP |
||||
#define UPB_MSG_HPP |
||||
|
||||
#include "upb/msg.h" |
||||
#include "upb/handlers.hpp" |
||||
|
||||
namespace upb { |
||||
|
||||
typedef upb_accessor_vtbl AccessorVTable; |
||||
|
||||
// Registers handlers for writing into a message of the given type using
|
||||
// whatever accessors it has defined.
|
||||
inline MessageHandlers* RegisterWriteHandlers(upb::Handlers* handlers, |
||||
const upb::MessageDef* md) { |
||||
return MessageHandlers::Cast( |
||||
upb_accessors_reghandlers(handlers, md)); |
||||
} |
||||
|
||||
template <typename T> static FieldHandlers::ValueHandler* GetValueHandler(); |
||||
|
||||
// A handy templated function that will retrieve a value handler for a given
|
||||
// C++ type.
|
||||
#define GET_VALUE_HANDLER(type, ctype) \ |
||||
template <> \
|
||||
inline FieldHandlers::ValueHandler* GetValueHandler<ctype>() { \
|
||||
return &upb_stdmsg_set ## type; \
|
||||
} |
||||
|
||||
GET_VALUE_HANDLER(double, double); |
||||
GET_VALUE_HANDLER(float, float); |
||||
GET_VALUE_HANDLER(uint64, uint64_t); |
||||
GET_VALUE_HANDLER(uint32, uint32_t); |
||||
GET_VALUE_HANDLER(int64, int64_t); |
||||
GET_VALUE_HANDLER(int32, int32_t); |
||||
GET_VALUE_HANDLER(bool, bool); |
||||
#undef GET_VALUE_HANDLER |
||||
|
||||
} // namespace
|
||||
|
||||
#endif |
@ -1,35 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2011 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#ifndef UPB_PB_GLUE_HPP |
||||
#define UPB_PB_GLUE_HPP |
||||
|
||||
#include "upb/upb.hpp" |
||||
#include "upb/pb/glue.h" |
||||
|
||||
namespace upb { |
||||
|
||||
// All routines that load descriptors expect the descriptor to be a
|
||||
// FileDescriptorSet.
|
||||
bool LoadDescriptorFileIntoSymtab(SymbolTable* s, const char *fname, |
||||
Status* status) { |
||||
return upb_load_descriptor_file_into_symtab(s, fname, status); |
||||
} |
||||
|
||||
bool LoadDescriptorIntoSymtab(SymbolTable* s, const char* str, |
||||
size_t len, Status* status) { |
||||
return upb_load_descriptor_into_symtab(s, str, len, status); |
||||
} |
||||
|
||||
template <typename T> |
||||
bool LoadDescriptorIntoSymtab(SymbolTable* s, const T& desc, Status* status) { |
||||
return upb_load_descriptor_into_symtab(s, desc.c_str(), desc.size(), status); |
||||
} |
||||
|
||||
} // namespace upb
|
||||
|
||||
#endif |
@ -1,892 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
|
||||
#include <string> |
||||
#include <typeinfo> |
||||
#include "upb/bytestream.hpp" |
||||
#include "upb/def.hpp" |
||||
#include "upb/handlers.hpp" |
||||
#include "upb/msg.hpp" |
||||
#include "upb/proto2_bridge.hpp" |
||||
|
||||
namespace { |
||||
|
||||
static void* GetFieldPointer(void *message, const upb::FieldDef* f) { |
||||
return static_cast<char*>(message) + f->offset(); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
|
||||
// TODO(haberman): friend upb so that this isn't required.
|
||||
#define protected public |
||||
#include "net/proto2/public/repeated_field.h" |
||||
#undef private |
||||
|
||||
#define private public |
||||
#include "net/proto/proto2_reflection.h" |
||||
#undef private |
||||
|
||||
#include "net/proto2/proto/descriptor.pb.h" |
||||
#include "net/proto2/public/descriptor.h" |
||||
#include "net/proto2/public/generated_message_reflection.h" |
||||
#include "net/proto2/public/lazy_field.h" |
||||
#include "net/proto2/public/message.h" |
||||
#include "net/proto2/public/string_piece_field_support.h" |
||||
#include "net/proto/internal_layout.h" |
||||
#include "strings/cord.h" |
||||
using ::proto2::Descriptor; |
||||
using ::proto2::EnumDescriptor; |
||||
using ::proto2::EnumValueDescriptor; |
||||
using ::proto2::FieldDescriptor; |
||||
using ::proto2::FieldOptions; |
||||
using ::proto2::FileDescriptor; |
||||
using ::proto2::internal::GeneratedMessageReflection; |
||||
using ::proto2::internal::RepeatedPtrFieldBase; |
||||
using ::proto2::internal::StringPieceField; |
||||
using ::proto2::Message; |
||||
using ::proto2::MessageFactory; |
||||
using ::proto2::Reflection; |
||||
using ::proto2::RepeatedField; |
||||
using ::proto2::RepeatedPtrField; |
||||
|
||||
namespace upb { |
||||
|
||||
static const Message* GetPrototypeForField(const Message& m, |
||||
const FieldDescriptor* f); |
||||
|
||||
namespace proto2_bridge_google3 { class FieldAccessor; } |
||||
|
||||
using ::upb::proto2_bridge_google3::FieldAccessor; |
||||
|
||||
namespace proto2_bridge_google3 { |
||||
|
||||
static void AssignToCord(const ByteRegion* r, Cord* cord) { |
||||
// TODO(haberman): ref source data if source is a cord.
|
||||
cord->Clear(); |
||||
uint64_t ofs = r->start_ofs(); |
||||
while (ofs < r->end_ofs()) { |
||||
size_t len; |
||||
const char *buf = r->GetPtr(ofs, &len); |
||||
cord->Append(StringPiece(buf, len)); |
||||
ofs += len; |
||||
} |
||||
} |
||||
|
||||
#else |
||||
|
||||
// TODO(haberman): friend upb so that this isn't required.
|
||||
#define protected public |
||||
#include "google/protobuf/repeated_field.h" |
||||
#undef protected |
||||
|
||||
#define private public |
||||
#include "google/protobuf/generated_message_reflection.h" |
||||
#undef private |
||||
|
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
#include "google/protobuf/message.h" |
||||
using ::google::protobuf::Descriptor; |
||||
using ::google::protobuf::EnumDescriptor; |
||||
using ::google::protobuf::EnumValueDescriptor; |
||||
using ::google::protobuf::FieldDescriptor; |
||||
using ::google::protobuf::FieldOptions; |
||||
using ::google::protobuf::FileDescriptor; |
||||
using ::google::protobuf::internal::GeneratedMessageReflection; |
||||
using ::google::protobuf::internal::RepeatedPtrFieldBase; |
||||
using ::google::protobuf::Message; |
||||
using ::google::protobuf::MessageFactory; |
||||
using ::google::protobuf::Reflection; |
||||
using ::google::protobuf::RepeatedField; |
||||
using ::google::protobuf::RepeatedPtrField; |
||||
|
||||
namespace upb { |
||||
static const Message* GetPrototypeForField(const Message& m, |
||||
const FieldDescriptor* f); |
||||
|
||||
namespace proto2_bridge_opensource { class FieldAccessor; } |
||||
|
||||
using ::upb::proto2_bridge_opensource::FieldAccessor; |
||||
|
||||
namespace proto2_bridge_opensource { |
||||
|
||||
#endif // ifdef UPB_GOOGLE3
|
||||
|
||||
// Have to define this manually since older versions of proto2 didn't define
|
||||
// an enum value for STRING.
|
||||
#define UPB_CTYPE_STRING 0 |
||||
|
||||
// The code in this class depends on the internal representation of the proto2
|
||||
// generated classes, which is an internal implementation detail of proto2 and
|
||||
// is not a public interface. As a result, this class's implementation may
|
||||
// need to be changed if/when proto2 changes its internal representation. It
|
||||
// is intended that this class is the only code that depends on these internal,
|
||||
// non-public interfaces.
|
||||
//
|
||||
// This class only works with messages that use GeneratedMessageReflection.
|
||||
// Other reflection classes will need other accessor implementations.
|
||||
class FieldAccessor { |
||||
public: |
||||
// Returns true if we were able to set an accessor and any other properties
|
||||
// of the FieldDef that are necessary to read/write this field to a
|
||||
// proto2::Message.
|
||||
static bool TrySet(const FieldDescriptor* proto2_f, |
||||
const upb::MessageDef* md, |
||||
upb::FieldDef* upb_f) { |
||||
const Message* prototype = static_cast<const Message*>(md->prototype); |
||||
const Reflection* base_r = prototype->GetReflection(); |
||||
const GeneratedMessageReflection* r = |
||||
dynamic_cast<const GeneratedMessageReflection*>(base_r); |
||||
// Old versions of the open-source protobuf release erroneously default to
|
||||
// Cord even though that has never been supported in the open-source
|
||||
// release.
|
||||
int32_t ctype = proto2_f->options().has_ctype() ? |
||||
proto2_f->options().ctype() : UPB_CTYPE_STRING; |
||||
if (!r) return false; |
||||
// Extensions not supported yet.
|
||||
if (proto2_f->is_extension()) return false; |
||||
|
||||
upb_f->set_accessor(GetForFieldDescriptor(proto2_f, ctype)); |
||||
upb_f->set_hasbit(GetHasbit(proto2_f, r)); |
||||
upb_f->set_offset(GetOffset(proto2_f, r)); |
||||
if (upb_f->IsSubmessage()) { |
||||
upb_f->set_subtype_name(proto2_f->message_type()->full_name()); |
||||
upb_f->prototype = GetPrototypeForField(*prototype, proto2_f); |
||||
} |
||||
|
||||
if (upb_f->IsString() && !upb_f->IsSequence() && |
||||
ctype == UPB_CTYPE_STRING) { |
||||
upb_f->prototype = &r->GetStringReference(*prototype, proto2_f, NULL); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static MessageFactory* GetMessageFactory(const Message& m) { |
||||
const GeneratedMessageReflection* r = |
||||
dynamic_cast<const GeneratedMessageReflection*>(m.GetReflection()); |
||||
return r ? r->message_factory_ : NULL; |
||||
} |
||||
|
||||
private: |
||||
static int64_t GetHasbit(const FieldDescriptor* f, |
||||
const GeneratedMessageReflection* r) { |
||||
if (f->is_repeated()) { |
||||
// proto2 does not store hasbits for repeated fields.
|
||||
return -1; |
||||
} else { |
||||
return (r->has_bits_offset_ * 8) + f->index(); |
||||
} |
||||
} |
||||
|
||||
static uint16_t GetOffset(const FieldDescriptor* f, |
||||
const GeneratedMessageReflection* r) { |
||||
return r->offsets_[f->index()]; |
||||
} |
||||
|
||||
static AccessorVTable *GetForFieldDescriptor(const FieldDescriptor* f, |
||||
int32_t ctype) { |
||||
switch (f->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
// Should handlers validate enum membership to match proto2?
|
||||
case FieldDescriptor::CPPTYPE_INT32: return Get<int32_t>(); |
||||
case FieldDescriptor::CPPTYPE_INT64: return Get<int64_t>(); |
||||
case FieldDescriptor::CPPTYPE_UINT32: return Get<uint32_t>(); |
||||
case FieldDescriptor::CPPTYPE_UINT64: return Get<uint64_t>(); |
||||
case FieldDescriptor::CPPTYPE_DOUBLE: return Get<double>(); |
||||
case FieldDescriptor::CPPTYPE_FLOAT: return Get<float>(); |
||||
case FieldDescriptor::CPPTYPE_BOOL: return Get<bool>(); |
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
switch (ctype) { |
||||
#ifdef UPB_GOOGLE3 |
||||
case FieldOptions::STRING: |
||||
return GetForString<string>(); |
||||
case FieldOptions::CORD: |
||||
return GetForCord(); |
||||
case FieldOptions::STRING_PIECE: |
||||
return GetForStringPiece(); |
||||
#else |
||||
case UPB_CTYPE_STRING: |
||||
return GetForString<std::string>(); |
||||
#endif |
||||
default: return NULL; |
||||
} |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
#ifdef UPB_GOOGLE3 |
||||
if (f->options().lazy()) { |
||||
return NULL; // Not yet implemented.
|
||||
} else { |
||||
return GetForMessage(); |
||||
} |
||||
#else |
||||
return GetForMessage(); |
||||
#endif |
||||
default: return NULL; |
||||
} |
||||
} |
||||
|
||||
// PushOffset handler (used for StartSequence and others) ///////////////////
|
||||
|
||||
static SubFlow PushOffset(void *m, Value fval) { |
||||
const FieldDef *f = GetValue<const FieldDef*>(fval); |
||||
return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); |
||||
} |
||||
|
||||
// Primitive Value (numeric, enum, bool) /////////////////////////////////////
|
||||
|
||||
template <typename T> static AccessorVTable *Get() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
GetValueHandler<T>(), |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&Append<T>, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
template <typename T> |
||||
static Flow Append(void *_r, Value fval, Value val) { |
||||
(void)fval; |
||||
RepeatedField<T>* r = static_cast<RepeatedField<T>*>(_r); |
||||
r->Add(GetValue<T>(val)); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// String ////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T> static AccessorVTable *GetForString() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
&SetString<T>, |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&AppendString<T>, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
// This needs to be templated because google3 string is not std::string.
|
||||
template <typename T> static Flow SetString(void *m, Value fval, Value val) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
T **str = static_cast<T**>(GetFieldPointer(m, f)); |
||||
// If it points to the default instance, we must create a new instance.
|
||||
if (*str == f->prototype) *str = new T(); |
||||
GetValue<ByteRegion*>(val)->AssignToString(*str); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
template <typename T> |
||||
static Flow AppendString(void *_r, Value fval, Value val) { |
||||
(void)fval; |
||||
RepeatedPtrField<T>* r = static_cast<RepeatedPtrField<T>*>(_r); |
||||
GetValue<ByteRegion*>(val)->AssignToString(r->Add()); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// SubMessage ////////////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForMessage() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
&StartSubMessage, |
||||
NULL, // Value handler
|
||||
&PushOffset, // StartSequence handler
|
||||
&StartRepeatedSubMessage, |
||||
NULL, // Repeated value handler
|
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static SubFlow StartSubMessage(void *m, Value fval) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
void **subm = static_cast<void**>(GetFieldPointer(m, f)); |
||||
if (*subm == NULL || *subm == f->prototype) { |
||||
const Message* prototype = static_cast<const Message*>(f->prototype); |
||||
*subm = prototype->New(); |
||||
} |
||||
return UPB_CONTINUE_WITH(*subm); |
||||
} |
||||
|
||||
class RepeatedMessageTypeHandler { |
||||
public: |
||||
typedef void Type; |
||||
// AddAllocated() calls this, but only if other objects are sitting
|
||||
// around waiting for reuse, which we will not do.
|
||||
static void Delete(Type* t) { |
||||
(void)t; |
||||
assert(false); |
||||
} |
||||
}; |
||||
|
||||
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
|
||||
// its base class RepeatedPtrFieldBase*.
|
||||
static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
RepeatedPtrFieldBase *r = static_cast<RepeatedPtrFieldBase*>(_r); |
||||
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); |
||||
if (!submsg) { |
||||
const Message* prototype = static_cast<const Message*>(f->prototype); |
||||
submsg = prototype->New(); |
||||
r->AddAllocated<RepeatedMessageTypeHandler>(submsg); |
||||
} |
||||
return UPB_CONTINUE_WITH(submsg); |
||||
} |
||||
|
||||
// TODO(haberman): handle Extensions, Unknown Fields.
|
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
// Handlers for types/features only included in internal proto2 release:
|
||||
// Cord, StringPiece, LazyField, and MessageSet.
|
||||
// TODO(haberman): LazyField, MessageSet.
|
||||
|
||||
// Cord //////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForCord() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
&SetCord, |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&AppendCord, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static Flow SetCord(void *m, Value fval, Value val) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
Cord* field = static_cast<Cord*>(GetFieldPointer(m, f)); |
||||
AssignToCord(GetValue<ByteRegion*>(val), field); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
static Flow AppendCord(void *_r, Value fval, Value val) { |
||||
RepeatedField<Cord>* r = static_cast<RepeatedField<Cord>*>(_r); |
||||
AssignToCord(GetValue<ByteRegion*>(val), r->Add()); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// StringPiece ///////////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForStringPiece() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
&SetStringPiece, |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&AppendStringPiece, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static void AssignToStringPieceField(const ByteRegion* r, |
||||
proto2::internal::StringPieceField* f) { |
||||
// TODO(haberman): alias if possible and enabled on the input stream.
|
||||
// TODO(haberman): add a method to StringPieceField that lets us avoid
|
||||
// this copy/malloc/free.
|
||||
char *data = new char[r->Length()]; |
||||
r->Copy(r->start_ofs(), r->Length(), data); |
||||
f->CopyFrom(StringPiece(data, r->Length())); |
||||
delete[] data; |
||||
} |
||||
|
||||
static Flow SetStringPiece(void *m, Value fval, Value val) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
StringPieceField* field = |
||||
static_cast<StringPieceField*>(GetFieldPointer(m, f)); |
||||
AssignToStringPieceField(GetValue<ByteRegion*>(val), field); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
static Flow AppendStringPiece(void* _r, Value fval, Value val) { |
||||
RepeatedPtrField<StringPieceField>* r = |
||||
static_cast<RepeatedPtrField<StringPieceField>*>(_r); |
||||
AssignToStringPieceField(GetValue<ByteRegion*>(val), r->Add()); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
#endif // UPB_GOOGLE3
|
||||
}; |
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
|
||||
// Proto1 accessor -- only needed inside Google.
|
||||
class Proto1FieldAccessor { |
||||
public: |
||||
// Returns true if we were able to set an accessor and any other properties
|
||||
// of the FieldDef that are necessary to read/write this field to a
|
||||
// proto2::Message.
|
||||
static bool TrySet(const FieldDescriptor* proto2_f, |
||||
const upb::MessageDef* md, |
||||
upb::FieldDef* upb_f) { |
||||
const Message* m = static_cast<const Message*>(md->prototype); |
||||
const proto2::Reflection* base_r = m->GetReflection(); |
||||
const _pi::Proto2Reflection* r = |
||||
dynamic_cast<const _pi::Proto2Reflection*>(base_r); |
||||
if (!r) return false; |
||||
// Extensions not supported yet.
|
||||
if (proto2_f->is_extension()) return false; |
||||
|
||||
const _pi::Field* f = r->GetFieldLayout(proto2_f); |
||||
|
||||
if (f->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { |
||||
// Override the BYTES type that proto2 descriptors have for weak fields.
|
||||
upb_f->set_type(UPB_TYPE(MESSAGE)); |
||||
} |
||||
|
||||
if (upb_f->IsSubmessage()) { |
||||
const Message* prototype = upb::GetPrototypeForField(*m, proto2_f); |
||||
upb_f->set_subtype_name(prototype->GetDescriptor()->full_name()); |
||||
upb_f->prototype = prototype; |
||||
} |
||||
|
||||
upb_f->set_accessor(GetForCrep(f->crep)); |
||||
upb_f->set_hasbit(GetHasbit(proto2_f, r)); |
||||
upb_f->set_offset(GetOffset(proto2_f, r)); |
||||
return true; |
||||
} |
||||
|
||||
private: |
||||
static int16_t GetHasbit(const FieldDescriptor* f, |
||||
const _pi::Proto2Reflection* r) { |
||||
if (f->is_repeated()) { |
||||
// proto1 does not store hasbits for repeated fields.
|
||||
return -1; |
||||
} else { |
||||
return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; |
||||
} |
||||
} |
||||
|
||||
static uint16_t GetOffset(const FieldDescriptor* f, |
||||
const _pi::Proto2Reflection* r) { |
||||
return r->GetFieldLayout(f)->offset; |
||||
} |
||||
|
||||
static AccessorVTable *GetForCrep(int crep) { |
||||
#define PRIMITIVE(name, type_name) \ |
||||
case _pi::CREP_REQUIRED_ ## name: \
|
||||
case _pi::CREP_OPTIONAL_ ## name: \
|
||||
case _pi::CREP_REPEATED_ ## name: return Get<type_name>(); |
||||
|
||||
switch (crep) { |
||||
PRIMITIVE(DOUBLE, double); |
||||
PRIMITIVE(FLOAT, float); |
||||
PRIMITIVE(INT64, int64_t); |
||||
PRIMITIVE(UINT64, uint64_t); |
||||
PRIMITIVE(INT32, int32_t); |
||||
PRIMITIVE(FIXED64, uint64_t); |
||||
PRIMITIVE(FIXED32, uint32_t); |
||||
PRIMITIVE(BOOL, bool); |
||||
case _pi::CREP_REQUIRED_STRING: |
||||
case _pi::CREP_OPTIONAL_STRING: |
||||
case _pi::CREP_REPEATED_STRING: return GetForString(); |
||||
case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: return GetForOutOfLineString(); |
||||
case _pi::CREP_REQUIRED_CORD: |
||||
case _pi::CREP_OPTIONAL_CORD: |
||||
case _pi::CREP_REPEATED_CORD: return GetForCord(); |
||||
case _pi::CREP_REQUIRED_GROUP: |
||||
case _pi::CREP_REQUIRED_FOREIGN: |
||||
case _pi::CREP_REQUIRED_FOREIGN_PROTO2: return GetForRequiredMessage(); |
||||
case _pi::CREP_OPTIONAL_GROUP: |
||||
case _pi::CREP_REPEATED_GROUP: |
||||
case _pi::CREP_OPTIONAL_FOREIGN: |
||||
case _pi::CREP_REPEATED_FOREIGN: |
||||
case _pi::CREP_OPTIONAL_FOREIGN_PROTO2: |
||||
case _pi::CREP_REPEATED_FOREIGN_PROTO2: return GetForMessage(); |
||||
case _pi::CREP_OPTIONAL_FOREIGN_WEAK: return GetForWeakMessage(); |
||||
default: assert(false); return NULL; |
||||
} |
||||
#undef PRIMITIVE |
||||
} |
||||
|
||||
// PushOffset handler (used for StartSequence and others) ///////////////////
|
||||
|
||||
// We can find a RepeatedField* or a RepeatedPtrField* at f->offset().
|
||||
static SubFlow PushOffset(void *m, Value fval) { |
||||
const FieldDef *f = GetValue<const FieldDef*>(fval); |
||||
return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); |
||||
} |
||||
|
||||
// Primitive Value (numeric, enum, bool) /////////////////////////////////////
|
||||
|
||||
template <typename T> static AccessorVTable *Get() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
GetValueHandler<T>(), |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&Append<T>, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
template <typename T> |
||||
static Flow Append(void *_r, Value fval, Value val) { |
||||
(void)fval; |
||||
// Proto1's ProtoArray class derives from RepeatedField.
|
||||
RepeatedField<T>* r = static_cast<RepeatedField<T>*>(_r); |
||||
r->Add(GetValue<T>(val)); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// String ////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForString() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
&SetString, |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&AppendString, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static Flow SetString(void *m, Value fval, Value val) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
string *str = static_cast<string*>(GetFieldPointer(m, f)); |
||||
GetValue<ByteRegion*>(val)->AssignToString(str); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
static Flow AppendString(void *_r, Value fval, Value val) { |
||||
(void)fval; |
||||
RepeatedPtrField<string>* r = static_cast<RepeatedPtrField<string>*>(_r); |
||||
GetValue<ByteRegion*>(val)->AssignToString(r->Add()); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// Out-of-line string ////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForOutOfLineString() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, &SetOutOfLineString, |
||||
// This type is only used for non-repeated string fields.
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static Flow SetOutOfLineString(void *m, Value fval, Value val) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
string **str = static_cast<string**>(GetFieldPointer(m, f)); |
||||
if (*str == &::ProtocolMessage::___empty_internal_proto_string_) |
||||
*str = new string(); |
||||
GetValue<ByteRegion*>(val)->AssignToString(*str); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// Cord //////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForCord() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
NULL, // StartSubMessage handler
|
||||
&SetCord, |
||||
&PushOffset, // StartSequence handler
|
||||
NULL, // StartRepeatedSubMessage handler
|
||||
&AppendCord, |
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static Flow SetCord(void *m, Value fval, Value val) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
Cord* field = static_cast<Cord*>(GetFieldPointer(m, f)); |
||||
AssignToCord(GetValue<ByteRegion*>(val), field); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
static Flow AppendCord(void *_r, Value fval, Value val) { |
||||
RepeatedField<Cord>* r = static_cast<RepeatedField<Cord>*>(_r); |
||||
AssignToCord(GetValue<ByteRegion*>(val), r->Add()); |
||||
return UPB_CONTINUE; |
||||
} |
||||
|
||||
// SubMessage ////////////////////////////////////////////////////////////////
|
||||
|
||||
static AccessorVTable *GetForRequiredMessage() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
&PushOffset, // StartSubMessage handler
|
||||
NULL, // Value handler
|
||||
&PushOffset, // StartSequence handler
|
||||
&StartRepeatedSubMessage, |
||||
NULL, // Repeated value handler
|
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static AccessorVTable *GetForWeakMessage() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
&StartWeakSubMessage, // StartSubMessage handler
|
||||
NULL, // Value handler
|
||||
&PushOffset, // StartSequence handler
|
||||
&StartRepeatedSubMessage, |
||||
NULL, // Repeated value handler
|
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static AccessorVTable *GetForMessage() { |
||||
static upb_accessor_vtbl vtbl = { |
||||
&StartSubMessage, |
||||
NULL, // Value handler
|
||||
&PushOffset, // StartSequence handler
|
||||
&StartRepeatedSubMessage, |
||||
NULL, // Repeated value handler
|
||||
NULL, NULL, NULL, NULL, NULL, NULL}; |
||||
return &vtbl; |
||||
} |
||||
|
||||
static SubFlow StartSubMessage(void *m, Value fval) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
Message **subm = static_cast<Message**>(GetFieldPointer(m, f)); |
||||
if (*subm == f->prototype) *subm = (*subm)->New(); |
||||
return UPB_CONTINUE_WITH(*subm); |
||||
} |
||||
|
||||
static SubFlow StartWeakSubMessage(void *m, Value fval) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
Message **subm = static_cast<Message**>(GetFieldPointer(m, f)); |
||||
if (*subm == NULL) { |
||||
const Message* prototype = static_cast<const Message*>(f->prototype); |
||||
*subm = prototype->New(); |
||||
} |
||||
return UPB_CONTINUE_WITH(*subm); |
||||
} |
||||
|
||||
class RepeatedMessageTypeHandler { |
||||
public: |
||||
typedef void Type; |
||||
// AddAllocated() calls this, but only if other objects are sitting
|
||||
// around waiting for reuse, which we will not do.
|
||||
static void Delete(Type* t) { |
||||
(void)t; |
||||
assert(false); |
||||
} |
||||
}; |
||||
|
||||
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
|
||||
// its base class RepeatedPtrFieldBase*.
|
||||
static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { |
||||
const FieldDef* f = GetValue<const FieldDef*>(fval); |
||||
RepeatedPtrFieldBase *r = static_cast<RepeatedPtrFieldBase*>(_r); |
||||
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); |
||||
if (!submsg) { |
||||
const Message* prototype = static_cast<const Message*>(f->prototype); |
||||
submsg = prototype->New(); |
||||
r->AddAllocated<RepeatedMessageTypeHandler>(submsg); |
||||
} |
||||
return UPB_CONTINUE_WITH(submsg); |
||||
} |
||||
}; |
||||
|
||||
#endif |
||||
|
||||
} // namespace proto2_bridge_{google3,opensource}
|
||||
|
||||
static const Message* GetPrototypeForMessage(const Message& m) { |
||||
const Message* ret = NULL; |
||||
MessageFactory* factory = FieldAccessor::GetMessageFactory(m); |
||||
if (factory) { |
||||
// proto2 generated message or DynamicMessage.
|
||||
ret = factory->GetPrototype(m.GetDescriptor()); |
||||
assert(ret); |
||||
} else { |
||||
// Proto1 message; since proto1 has no dynamic message, it must be
|
||||
// from the generated factory.
|
||||
ret = MessageFactory::generated_factory()->GetPrototype(m.GetDescriptor()); |
||||
assert(ret); // If NULL, then wasn't a proto1 message, can't handle it.
|
||||
} |
||||
assert(ret->GetReflection() == m.GetReflection()); |
||||
return ret; |
||||
} |
||||
|
||||
static const Message* GetPrototypeForField(const Message& m, |
||||
const FieldDescriptor* f) { |
||||
#ifdef UPB_GOOGLE3 |
||||
if (f->type() == FieldDescriptor::TYPE_BYTES) { |
||||
// Proto1 weak field: the proto2 descriptor says their type is BYTES.
|
||||
const _pi::Proto2Reflection* r = |
||||
dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection()); |
||||
assert(r); |
||||
const _pi::Field* field = r->GetFieldLayout(f); |
||||
assert(field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK); |
||||
return GetPrototypeForMessage( |
||||
*static_cast<const Message*>(field->weak_layout()->default_instance)); |
||||
} else if (dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection())) { |
||||
// Proto1 message; since proto1 has no dynamic message, it must be from
|
||||
// the generated factory.
|
||||
const Message* ret = |
||||
MessageFactory::generated_factory()->GetPrototype(f->message_type()); |
||||
assert(ret); |
||||
return ret; |
||||
} |
||||
#endif |
||||
assert(f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); |
||||
// We assume that all submessages (and extensions) will be constructed using
|
||||
// the same MessageFactory as this message. This doesn't cover the case of
|
||||
// CodedInputStream::SetExtensionRegistry().
|
||||
MessageFactory* factory = FieldAccessor::GetMessageFactory(m); |
||||
assert(factory); // If neither proto1 nor proto2 we can't handle it.
|
||||
const Message* ret = factory->GetPrototype(f->message_type()); |
||||
assert(ret); |
||||
return ret; |
||||
} |
||||
|
||||
namespace proto2_bridge { |
||||
|
||||
upb::FieldDef* AddFieldDef(const FieldDescriptor* f, upb::MessageDef* md) { |
||||
upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f); |
||||
upb_f->set_number(f->number()); |
||||
upb_f->set_name(f->name()); |
||||
upb_f->set_label(static_cast<upb::Label>(f->label())); |
||||
upb_f->set_type(static_cast<upb::FieldType>(f->type())); |
||||
|
||||
if (!FieldAccessor::TrySet(f, md, upb_f) |
||||
#ifdef UPB_GOOGLE3 |
||||
&& !proto2_bridge_google3::Proto1FieldAccessor::TrySet(f, md, upb_f) |
||||
#endif |
||||
) { |
||||
// Unsupported reflection class.
|
||||
assert(false); |
||||
} |
||||
|
||||
if (upb_f->type() == UPB_TYPE(ENUM)) { |
||||
// We set the enum default symbolically.
|
||||
upb_f->set_default(f->default_value_enum()->name()); |
||||
upb_f->set_subtype_name(f->enum_type()->full_name()); |
||||
} else { |
||||
// Set field default for primitive types. Need to switch on the upb type
|
||||
// rather than the proto2 type, because upb_f->type() may have been changed
|
||||
// from BYTES to MESSAGE for a weak field.
|
||||
switch (upb_types[upb_f->type()].inmemory_type) { |
||||
case UPB_CTYPE_INT32: |
||||
upb_f->set_default(MakeValue(f->default_value_int32())); |
||||
break; |
||||
case UPB_CTYPE_INT64: |
||||
upb_f->set_default( |
||||
MakeValue(static_cast<int64_t>(f->default_value_int64()))); |
||||
break; |
||||
case UPB_CTYPE_UINT32: |
||||
upb_f->set_default(MakeValue(f->default_value_uint32())); |
||||
break; |
||||
case UPB_CTYPE_UINT64: |
||||
upb_f->set_default( |
||||
MakeValue(static_cast<uint64_t>(f->default_value_uint64()))); |
||||
break; |
||||
case UPB_CTYPE_DOUBLE: |
||||
upb_f->set_default(MakeValue(f->default_value_double())); |
||||
break; |
||||
case UPB_CTYPE_FLOAT: |
||||
upb_f->set_default(MakeValue(f->default_value_float())); |
||||
break; |
||||
case UPB_CTYPE_BOOL: |
||||
upb_f->set_default(MakeValue(f->default_value_bool())); |
||||
break; |
||||
case UPB_CTYPE_BYTEREGION: |
||||
upb_f->set_default(f->default_value_string()); |
||||
break; |
||||
} |
||||
} |
||||
return md->AddField(upb_f, &upb_f) ? upb_f : NULL; |
||||
} |
||||
|
||||
upb::MessageDef *NewEmptyMessageDef(const Message& m, void *owner) { |
||||
upb::MessageDef *md = upb::MessageDef::New(owner); |
||||
md->set_full_name(m.GetDescriptor()->full_name()); |
||||
md->prototype = GetPrototypeForMessage(m); |
||||
return md; |
||||
} |
||||
|
||||
upb::EnumDef* NewEnumDef(const EnumDescriptor* desc, void *owner) { |
||||
upb::EnumDef* e = upb::EnumDef::New(owner); |
||||
e->set_full_name(desc->full_name()); |
||||
for (int i = 0; i < desc->value_count(); i++) { |
||||
const EnumValueDescriptor* val = desc->value(i); |
||||
bool success = e->AddValue(val->name(), val->number()); |
||||
assert(success); |
||||
(void)success; |
||||
} |
||||
return e; |
||||
} |
||||
|
||||
void AddAllFields(upb::MessageDef* md) { |
||||
const Descriptor* d = |
||||
static_cast<const Message*>(md->prototype)->GetDescriptor(); |
||||
for (int i = 0; i < d->field_count(); i++) { |
||||
#ifdef UPB_GOOGLE3 |
||||
// Skip lazy fields for now since we can't properly handle them.
|
||||
if (d->field(i)->options().lazy()) continue; |
||||
#endif |
||||
// Extensions not supported yet.
|
||||
if (d->field(i)->is_extension()) continue; |
||||
AddFieldDef(d->field(i), md); |
||||
} |
||||
} |
||||
|
||||
upb::MessageDef *NewFullMessageDef(const Message& m, void *owner) { |
||||
upb::MessageDef* md = NewEmptyMessageDef(m, owner); |
||||
AddAllFields(md); |
||||
// TODO(haberman): add unknown field handler and extensions.
|
||||
return md; |
||||
} |
||||
|
||||
typedef std::map<std::string, upb::Def*> SymbolMap; |
||||
|
||||
static upb::MessageDef* NewFinalMessageDefHelper(const Message& m, void *owner, |
||||
SymbolMap* symbols) { |
||||
upb::MessageDef* md = NewFullMessageDef(m, owner); |
||||
// Must do this before processing submessages to prevent infinite recursion.
|
||||
(*symbols)[std::string(md->full_name())] = md->AsDef(); |
||||
|
||||
for (upb::MessageDef::Iterator i(md); !i.Done(); i.Next()) { |
||||
upb::FieldDef* f = i.field(); |
||||
if (!f->HasSubDef()) continue; |
||||
SymbolMap::iterator iter = symbols->find(f->subtype_name()); |
||||
upb::Def* subdef; |
||||
if (iter != symbols->end()) { |
||||
subdef = iter->second; |
||||
} else { |
||||
const FieldDescriptor* proto2_f = |
||||
m.GetDescriptor()->FindFieldByNumber(f->number()); |
||||
if (f->type() == UPB_TYPE(ENUM)) { |
||||
subdef = NewEnumDef(proto2_f->enum_type(), owner)->AsDef(); |
||||
(*symbols)[std::string(subdef->full_name())] = subdef; |
||||
} else { |
||||
assert(f->IsSubmessage()); |
||||
const Message* prototype = GetPrototypeForField(m, proto2_f); |
||||
subdef = NewFinalMessageDefHelper(*prototype, owner, symbols)->AsDef(); |
||||
} |
||||
} |
||||
f->set_subdef(subdef); |
||||
} |
||||
return md; |
||||
} |
||||
|
||||
const upb::MessageDef* NewFinalMessageDef(const Message& m, void *owner) { |
||||
SymbolMap symbols; |
||||
upb::MessageDef* ret = NewFinalMessageDefHelper(m, owner, &symbols); |
||||
|
||||
// Finalize defs.
|
||||
std::vector<upb::Def*> defs; |
||||
SymbolMap::iterator iter; |
||||
for (iter = symbols.begin(); iter != symbols.end(); ++iter) { |
||||
defs.push_back(iter->second); |
||||
} |
||||
Status status; |
||||
bool success = Def::Finalize(defs, &status); |
||||
assert(success); |
||||
(void)success; |
||||
|
||||
// Unref all defs except the top-level one that we are returning.
|
||||
for (int i = 0; i < static_cast<int>(defs.size()); i++) { |
||||
if (defs[i] != ret->AsDef()) defs[i]->Unref(owner); |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
} // namespace proto2_bridge
|
||||
} // namespace upb
|
@ -1,170 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// A bridge between upb and proto2, allows populating proto2 generated
|
||||
// classes using upb's parser, translating between descriptors and defs, etc.
|
||||
//
|
||||
// This is designed to be able to be compiled against either the open-source
|
||||
// version of protocol buffers or the Google-internal proto2. The two are
|
||||
// the same in most ways, but live in different namespaces (proto2 vs
|
||||
// google::protobuf) and have a few other more minor differences.
|
||||
//
|
||||
// The bridge gives you a lot of control over which fields will be written to
|
||||
// the message (fields that are not written will just be skipped), and whether
|
||||
// unknown fields are written to the UnknownFieldSet. This can save a lot of
|
||||
// work if the client only cares about some subset of the fields.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// // Build a def that will have all fields and parse just like proto2 would.
|
||||
// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto());
|
||||
//
|
||||
// // JIT the parser; should only be done once ahead-of-time.
|
||||
// upb::Handlers* handlers = upb::NewHandlersForMessage(md);
|
||||
// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers);
|
||||
// handlers->Unref();
|
||||
//
|
||||
// // The actual parsing.
|
||||
// MyProto proto;
|
||||
// upb::Decoder decoder;
|
||||
// upb::StringSource source(buf, len);
|
||||
// decoder.ResetPlan(plan, 0);
|
||||
// decoder.ResetInput(source.AllBytes(), &proto);
|
||||
// CHECK(decoder.Decode() == UPB_OK) << decoder.status();
|
||||
//
|
||||
// To parse only one field and skip all others:
|
||||
//
|
||||
// const upb::MessageDef* md =
|
||||
// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype());
|
||||
// upb::proto2_bridge::AddFieldDef(
|
||||
// MyProto::descriptor()->FindFieldByName("my_field"), md);
|
||||
// upb::Finalize(md);
|
||||
//
|
||||
// // Now continue with "JIT the parser" from above.
|
||||
//
|
||||
// Note that there is currently no support for
|
||||
// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate
|
||||
// DescriptorPool and MessageFactory for extensions. Since this is a property
|
||||
// of the input in proto2, it's difficult to build a plan ahead-of-time that
|
||||
// can properly support this. If it's an important use case, the caller should
|
||||
// probably build a upb plan explicitly.
|
||||
|
||||
#ifndef UPB_PROTO2_BRIDGE |
||||
#define UPB_PROTO2_BRIDGE |
||||
|
||||
#include <vector> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Descriptor; |
||||
class EnumDescriptor; |
||||
class FieldDescriptor; |
||||
class FileDescriptor; |
||||
class Message; |
||||
} // namespace google
|
||||
} // namespace protobuf
|
||||
|
||||
namespace proto2 { |
||||
class Descriptor; |
||||
class EnumDescriptor; |
||||
class FieldDescriptor; |
||||
class FileDescriptor; |
||||
class Message; |
||||
} // namespace proto2
|
||||
|
||||
|
||||
namespace upb { |
||||
|
||||
class Def; |
||||
class FieldDef; |
||||
class MessageDef; |
||||
|
||||
namespace proto2_bridge { |
||||
|
||||
// Unfinalized defs ////////////////////////////////////////////////////////////
|
||||
|
||||
// Creating of UNFINALIZED defs. All of these functions return defs that are
|
||||
// still mutable and have not been finalized. They must be finalized before
|
||||
// using them to parse anything. This is useful if you want more control over
|
||||
// the process of constructing defs, eg. to add the specific set of fields you
|
||||
// care about.
|
||||
|
||||
// Creates a new upb::MessageDef that corresponds to the type in the given
|
||||
// prototype message. The MessageDef will not have any fields added to it.
|
||||
upb::MessageDef *NewEmptyMessageDef(const proto2::Message& m, void *owner); |
||||
upb::MessageDef *NewEmptyMessageDef(const google::protobuf::Message& desc, |
||||
void *owner); |
||||
|
||||
// Adds a new upb::FieldDef to the given MessageDef corresponding to the given
|
||||
// FieldDescriptor. The FieldDef will be given an accessor and offset so that
|
||||
// it can be used to read and write data into the proto2::Message classes.
|
||||
// The given MessageDef must have been constructed with NewEmptyDefForMessage()
|
||||
// and f->containing_type() must correspond to the message that was used.
|
||||
//
|
||||
// Any submessage, group, or enum fields will be given symbolic references to
|
||||
// the subtype, which must be resolved before the MessageDef can be finalized.
|
||||
//
|
||||
// On success, returns the FieldDef that was added (caller does not own a ref).
|
||||
// If an existing field had the same name or number, returns NULL.
|
||||
upb::FieldDef* AddFieldDef(const proto2::FieldDescriptor* f, |
||||
upb::MessageDef* md); |
||||
upb::FieldDef* AddFieldDef(const google::protobuf::FieldDescriptor* f, |
||||
upb::MessageDef* md); |
||||
|
||||
// Given a MessageDef that was constructed with NewEmptyDefForMessage(), adds
|
||||
// FieldDefs for all fields defined in the original message, but not for any
|
||||
// extensions or unknown fields. The given MessageDef must not have any fields
|
||||
// that have the same name or number as any of the fields we are adding (the
|
||||
// easiest way to guarantee this is to start with an empty MessageDef).
|
||||
//
|
||||
// Returns true on success or false if any of the fields could not be added.
|
||||
void AddAllFields(upb::MessageDef* md); |
||||
|
||||
// TODO(haberman): Add:
|
||||
// // Adds a handler that will store unknown fields in the UnknownFieldSet.
|
||||
// void AddUnknownFieldHandler(upb::MessageDef* md);
|
||||
|
||||
// Returns a new upb::MessageDef that contains handlers for all fields, unknown
|
||||
// fields, and any extensions in the descriptor's pool. The resulting
|
||||
// def/handlers should be equivalent to the generated code constructed by the
|
||||
// protobuf compiler (or the code in DynamicMessage) for the given type.
|
||||
// The subdefs for message/enum fields (if any) will be referenced symbolically,
|
||||
// and will need to be resolved before being finalized.
|
||||
//
|
||||
// TODO(haberman): Add missing support (LazyField, MessageSet, and extensions).
|
||||
//
|
||||
// TODO(haberman): possibly add a similar function that lets you supply a
|
||||
// separate DescriptorPool and MessageFactory for extensions, to support
|
||||
// proto2's io::CodedInputStream::SetExtensionRegistry().
|
||||
upb::MessageDef* NewFullMessageDef(const proto2::Message& m, void *owner); |
||||
upb::MessageDef* NewFullMessageDef(const google::protobuf::Message& m, |
||||
void *owner); |
||||
|
||||
// Returns a new upb::EnumDef that corresponds to the given EnumDescriptor.
|
||||
// Caller owns a ref on the returned EnumDef.
|
||||
upb::EnumDef* NewEnumDef(const proto2::EnumDescriptor* desc, void *owner); |
||||
upb::EnumDef* NewEnumDef(const google::protobuf::EnumDescriptor* desc, |
||||
void *owner); |
||||
|
||||
// Finalized defs //////////////////////////////////////////////////////////////
|
||||
|
||||
// These functions return FINALIZED defs, meaning that they are immutable and
|
||||
// ready for use. Since they are immutable you cannot make any further changes
|
||||
// to eg. the set of fields, but these functions are more convenient if you
|
||||
// simply want to parse a message exactly how the built-in proto2 parser would.
|
||||
|
||||
// Creates a returns a finalized MessageDef for the give message and its entire
|
||||
// type tree that will include all fields and unknown handlers (ie. it will
|
||||
// parse just like proto2 would).
|
||||
const upb::MessageDef* NewFinalMessageDef(const proto2::Message& m, |
||||
void *owner); |
||||
const upb::MessageDef* NewFinalMessageDef(const google::protobuf::Message& m, |
||||
void *owner); |
||||
|
||||
} // namespace proto2_bridge
|
||||
} // namespace upb
|
||||
|
||||
#endif |
@ -1,81 +0,0 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
|
||||
#ifndef UPB_HPP |
||||
#define UPB_HPP |
||||
|
||||
#include "upb/upb.h" |
||||
#include <iostream> |
||||
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && !defined(UPB_NO_CXX11) |
||||
#define UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(class_name) \ |
||||
class_name() = delete; \
|
||||
~class_name() = delete; |
||||
#else |
||||
#define UPB_DISALLOW_CONSTRUCT_AND_DESTRUCT(class_name) \ |
||||
class_name(); \
|
||||
~class_name(); |
||||
#endif |
||||
|
||||
namespace upb { |
||||
|
||||
typedef upb_success_t Success; |
||||
|
||||
class Status : public upb_status { |
||||
public: |
||||
Status() { upb_status_init(this); } |
||||
~Status() { upb_status_uninit(this); } |
||||
|
||||
bool ok() const { return upb_ok(this); } |
||||
bool eof() const { return upb_eof(this); } |
||||
|
||||
const char *GetString() const { return upb_status_getstr(this); } |
||||
void SetEof() { upb_status_seteof(this); } |
||||
void SetErrorLiteral(const char* msg) { |
||||
upb_status_seterrliteral(this, msg); |
||||
} |
||||
|
||||
void Clear() { upb_status_clear(this); } |
||||
}; |
||||
|
||||
typedef upb_value Value; |
||||
|
||||
template <typename T> T GetValue(Value v); |
||||
template <typename T> Value MakeValue(T v); |
||||
|
||||
#define UPB_VALUE_ACCESSORS(type, ctype) \ |
||||
template <> inline ctype GetValue<ctype>(Value v) { \
|
||||
return upb_value_get ## type(v); \
|
||||
} \
|
||||
template <> inline Value MakeValue<ctype>(ctype v) { \
|
||||
return upb_value_ ## type(v); \
|
||||
} |
||||
|
||||
UPB_VALUE_ACCESSORS(double, double); |
||||
UPB_VALUE_ACCESSORS(float, float); |
||||
UPB_VALUE_ACCESSORS(int32, int32_t); |
||||
UPB_VALUE_ACCESSORS(int64, int64_t); |
||||
UPB_VALUE_ACCESSORS(uint32, uint32_t); |
||||
UPB_VALUE_ACCESSORS(uint64, uint64_t); |
||||
UPB_VALUE_ACCESSORS(bool, bool); |
||||
|
||||
#undef UPB_VALUE_ACCESSORS |
||||
|
||||
template <typename T> inline T* GetPtrValue(Value v) { |
||||
return static_cast<T*>(upb_value_getptr(v)); |
||||
} |
||||
template <typename T> inline Value MakePtrValue(T* v) { |
||||
return upb_value_ptr(static_cast<void*>(v)); |
||||
} |
||||
|
||||
INLINE std::ostream& operator<<(std::ostream& out, const Status& status) { |
||||
out << status.GetString(); |
||||
return out; |
||||
} |
||||
|
||||
} // namespace upb
|
||||
|
||||
#endif |
@ -1,8 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#include <linux/ctype.h> |
@ -1,22 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#ifndef PRId64 |
||||
#define PRId64 "ld" |
||||
#endif |
||||
|
||||
#ifndef PRIu64 |
||||
#define PRIu64 "lu" |
||||
#endif |
||||
|
||||
#ifndef PRId32 |
||||
#define PRId32 "d" |
||||
#endif |
||||
|
||||
#ifndef PRIu32 |
||||
#define PRIu32 "u" |
||||
#endif |
@ -1,60 +0,0 @@ |
||||
/* |
||||
* Copyright (c) 2003 Peter Wemm. |
||||
* Copyright (c) 1993 The Regents of the University of California. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. 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. |
||||
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. |
||||
* |
||||
* $FreeBSD$ |
||||
*/ |
||||
|
||||
.globl _setjmp, _longjmp |
||||
|
||||
_setjmp: |
||||
movq %rbx,0(%rdi) /* save rbx */ |
||||
movq %rsp,8(%rdi) /* save rsp */ |
||||
movq %rbp,16(%rdi) /* save rbp */ |
||||
movq %r12,24(%rdi) /* save r12 */ |
||||
movq %r13,32(%rdi) /* save r13 */ |
||||
movq %r14,40(%rdi) /* save r14 */ |
||||
movq %r15,48(%rdi) /* save r15 */ |
||||
movq 0(%rsp),%rdx /* get rta */ |
||||
movq %rdx,56(%rdi) /* save rip */ |
||||
xorl %eax,%eax /* return(0); */
|
||||
ret |
||||
|
||||
_longjmp: |
||||
movq 0(%rdi),%rbx /* restore rbx */ |
||||
movq 8(%rdi),%rsp /* restore rsp */ |
||||
movq 16(%rdi),%rbp /* restore rbp */ |
||||
movq 24(%rdi),%r12 /* restore r12 */ |
||||
movq 32(%rdi),%r13 /* restore r13 */ |
||||
movq 40(%rdi),%r14 /* restore r14 */ |
||||
movq 48(%rdi),%r15 /* restore r15 */ |
||||
movq 56(%rdi),%rdx /* get rta */ |
||||
movq %rdx,0(%rsp) /* put in return frame */ |
||||
xorl %eax,%eax /* return(1); */
|
||||
incl %eax |
||||
ret |
@ -1,13 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
// Linux doesn't provide setjmp/longjmp, boo.
|
||||
|
||||
typedef void *jmp_buf[8]; |
||||
|
||||
extern int _setjmp(jmp_buf env); |
||||
__attribute__((__noreturn__)) extern void _longjmp(jmp_buf env, int val); |
@ -0,0 +1,32 @@ |
||||
|
||||
Lunit License |
||||
------------- |
||||
|
||||
Lunit is written by Michael Roth <mroth@nessie.de> and is licensed |
||||
under the terms of the MIT license reproduced below. |
||||
|
||||
======================================================================== |
||||
|
||||
Copyright (c) 2004-2010 Michael Roth <mroth@nessie.de> |
||||
|
||||
Permission is hereby granted, free of charge, to any person |
||||
obtaining a copy of this software and associated documentation |
||||
files (the "Software"), to deal in the Software without restriction, |
||||
including without limitation the rights to use, copy, modify, merge, |
||||
publish, distribute, sublicense, and/or sell copies of the Software, |
||||
and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
||||
======================================================================== |
||||
|
@ -0,0 +1,32 @@ |
||||
|
||||
local actions = {} |
||||
|
||||
local atexit |
||||
|
||||
if _VERSION >= 'Lua 5.2' then |
||||
|
||||
atexit = function (fn) |
||||
actions[#actions+1] = setmetatable({}, { __gc = fn }) |
||||
end |
||||
|
||||
else |
||||
|
||||
local newproxy = newproxy |
||||
local debug = debug |
||||
local assert = assert |
||||
local setmetatable = setmetatable |
||||
|
||||
local function gc(fn) |
||||
local p = assert(newproxy()) |
||||
assert(debug.setmetatable(p, { __gc = fn })) |
||||
return p |
||||
end |
||||
|
||||
atexit = function (fn) |
||||
actions[#actions+1] = gc(fn) |
||||
end |
||||
|
||||
end |
||||
|
||||
return atexit |
||||
|
@ -0,0 +1,725 @@ |
||||
--[[-------------------------------------------------------------------------- |
||||
|
||||
This file is part of lunit 0.5. |
||||
|
||||
For Details about lunit look at: http://www.mroth.net/lunit/ |
||||
|
||||
Author: Michael Roth <mroth@nessie.de> |
||||
|
||||
Copyright (c) 2004, 2006-2010 Michael Roth <mroth@nessie.de> |
||||
|
||||
Permission is hereby granted, free of charge, to any person |
||||
obtaining a copy of this software and associated documentation |
||||
files (the "Software"), to deal in the Software without restriction, |
||||
including without limitation the rights to use, copy, modify, merge, |
||||
publish, distribute, sublicense, and/or sell copies of the Software, |
||||
and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
||||
--]]-------------------------------------------------------------------------- |
||||
|
||||
|
||||
local orig_assert = assert |
||||
|
||||
local pairs = pairs |
||||
local ipairs = ipairs |
||||
local next = next |
||||
local type = type |
||||
local error = error |
||||
local tostring = tostring |
||||
local setmetatable = setmetatable |
||||
local pcall = pcall |
||||
local xpcall = xpcall |
||||
local require = require |
||||
local loadfile = loadfile |
||||
|
||||
local string_sub = string.sub |
||||
local string_gsub = string.gsub |
||||
local string_format = string.format |
||||
local string_lower = string.lower |
||||
local string_find = string.find |
||||
|
||||
local table_concat = table.concat |
||||
|
||||
local debug_getinfo = debug.getinfo |
||||
|
||||
local _G = _G |
||||
|
||||
local lunit |
||||
|
||||
if _VERSION >= 'Lua 5.2' then |
||||
|
||||
lunit = {} |
||||
_ENV = lunit |
||||
|
||||
else |
||||
|
||||
module("lunit") |
||||
lunit = _M |
||||
|
||||
end |
||||
|
||||
|
||||
local __failure__ = {} -- Type tag for failed assertions |
||||
|
||||
local typenames = { "nil", "boolean", "number", "string", "table", "function", "thread", "userdata" } |
||||
|
||||
|
||||
local traceback_hide -- Traceback function which hides lunit internals |
||||
local mypcall -- Protected call to a function with own traceback |
||||
do |
||||
local _tb_hide = setmetatable( {}, {__mode="k"} ) |
||||
|
||||
function traceback_hide(func) |
||||
_tb_hide[func] = true |
||||
end |
||||
|
||||
local function my_traceback(errobj) |
||||
if is_table(errobj) and errobj.type == __failure__ then |
||||
local info = debug_getinfo(5, "Sl") -- FIXME: Hardcoded integers are bad... |
||||
errobj.where = string_format( "%s:%d", info.short_src, info.currentline) |
||||
else |
||||
errobj = { msg = tostring(errobj) } |
||||
errobj.tb = {} |
||||
local i = 2 |
||||
while true do |
||||
local info = debug_getinfo(i, "Snlf") |
||||
if not is_table(info) then |
||||
break |
||||
end |
||||
if not _tb_hide[info.func] then |
||||
local line = {} -- Ripped from ldblib.c... |
||||
line[#line+1] = string_format("%s:", info.short_src) |
||||
if info.currentline > 0 then |
||||
line[#line+1] = string_format("%d:", info.currentline) |
||||
end |
||||
if info.namewhat ~= "" then |
||||
line[#line+1] = string_format(" in function '%s'", info.name) |
||||
else |
||||
if info.what == "main" then |
||||
line[#line+1] = " in main chunk" |
||||
elseif info.what == "C" or info.what == "tail" then |
||||
line[#line+1] = " ?" |
||||
else |
||||
line[#line+1] = string_format(" in function <%s:%d>", info.short_src, info.linedefined) |
||||
end |
||||
end |
||||
errobj.tb[#errobj.tb+1] = table_concat(line) |
||||
end |
||||
i = i + 1 |
||||
end |
||||
end |
||||
return errobj |
||||
end |
||||
|
||||
function mypcall(func) |
||||
orig_assert( is_function(func) ) |
||||
local ok, errobj = xpcall(func, my_traceback) |
||||
if not ok then |
||||
return errobj |
||||
end |
||||
end |
||||
traceback_hide(mypcall) |
||||
end |
||||
|
||||
|
||||
-- Type check functions |
||||
|
||||
for _, typename in ipairs(typenames) do |
||||
lunit["is_"..typename] = function(x) |
||||
return type(x) == typename |
||||
end |
||||
end |
||||
|
||||
local is_nil = is_nil |
||||
local is_boolean = is_boolean |
||||
local is_number = is_number |
||||
local is_string = is_string |
||||
local is_table = is_table |
||||
local is_function = is_function |
||||
local is_thread = is_thread |
||||
local is_userdata = is_userdata |
||||
|
||||
|
||||
local function failure(name, usermsg, defaultmsg, ...) |
||||
local errobj = { |
||||
type = __failure__, |
||||
name = name, |
||||
msg = string_format(defaultmsg,...), |
||||
usermsg = usermsg |
||||
} |
||||
error(errobj, 0) |
||||
end |
||||
traceback_hide( failure ) |
||||
|
||||
|
||||
local function format_arg(arg) |
||||
local argtype = type(arg) |
||||
if argtype == "string" then |
||||
return "'"..arg.."'" |
||||
elseif argtype == "number" or argtype == "boolean" or argtype == "nil" then |
||||
return tostring(arg) |
||||
else |
||||
return "["..tostring(arg).."]" |
||||
end |
||||
end |
||||
|
||||
|
||||
local function selected(map, name) |
||||
if not map then |
||||
return true |
||||
end |
||||
|
||||
local m = {} |
||||
for k,v in pairs(map) do |
||||
m[k] = lunitpat2luapat(v) |
||||
end |
||||
return in_patternmap(m, name) |
||||
end |
||||
|
||||
|
||||
function fail(msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
failure( "fail", msg, "failure" ) |
||||
end |
||||
traceback_hide( fail ) |
||||
|
||||
|
||||
function assert(assertion, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if not assertion then |
||||
failure( "assert", msg, "assertion failed" ) |
||||
end |
||||
return assertion |
||||
end |
||||
traceback_hide( assert ) |
||||
|
||||
|
||||
function assert_true(actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if actual ~= true then |
||||
failure( "assert_true", msg, "true expected but was %s", format_arg(actual) ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( assert_true ) |
||||
|
||||
|
||||
function assert_false(actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if actual ~= false then |
||||
failure( "assert_false", msg, "false expected but was %s", format_arg(actual) ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( assert_false ) |
||||
|
||||
|
||||
function assert_equal(expected, actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if expected ~= actual then |
||||
failure( "assert_equal", msg, "expected %s but was %s", format_arg(expected), format_arg(actual) ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( assert_equal ) |
||||
|
||||
|
||||
function assert_not_equal(unexpected, actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if unexpected == actual then |
||||
failure( "assert_not_equal", msg, "%s not expected but was one", format_arg(unexpected) ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( assert_not_equal ) |
||||
|
||||
|
||||
function assert_match(pattern, actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if type(pattern) ~= "string" then |
||||
failure( "assert_match", msg, "expected a string as pattern but was %s", format_arg(pattern) ) |
||||
end |
||||
if type(actual) ~= "string" then |
||||
failure( "assert_match", msg, "expected a string to match pattern '%s' but was a %s", pattern, format_arg(actual) ) |
||||
end |
||||
if not string_find(actual, pattern) then |
||||
failure( "assert_match", msg, "expected '%s' to match pattern '%s' but doesn't", actual, pattern ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( assert_match ) |
||||
|
||||
|
||||
function assert_not_match(pattern, actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if type(pattern) ~= "string" then |
||||
failure( "assert_not_match", msg, "expected a string as pattern but was %s", format_arg(pattern) ) |
||||
end |
||||
if type(actual) ~= "string" then |
||||
failure( "assert_not_match", msg, "expected a string to not match pattern '%s' but was %s", pattern, format_arg(actual) ) |
||||
end |
||||
if string_find(actual, pattern) then |
||||
failure( "assert_not_match", msg, "expected '%s' to not match pattern '%s' but it does", actual, pattern ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( assert_not_match ) |
||||
|
||||
|
||||
function assert_error(msg, func) |
||||
stats.assertions = stats.assertions + 1 |
||||
if func == nil then |
||||
func, msg = msg, nil |
||||
end |
||||
if type(func) ~= "function" then |
||||
failure( "assert_error", msg, "expected a function as last argument but was %s", format_arg(func) ) |
||||
end |
||||
local ok, errmsg = pcall(func) |
||||
if ok then |
||||
failure( "assert_error", msg, "error expected but no error occurred" ) |
||||
end |
||||
end |
||||
traceback_hide( assert_error ) |
||||
|
||||
|
||||
function assert_error_match(msg, pattern, func) |
||||
stats.assertions = stats.assertions + 1 |
||||
if func == nil then |
||||
msg, pattern, func = nil, msg, pattern |
||||
end |
||||
if type(pattern) ~= "string" then |
||||
failure( "assert_error_match", msg, "expected the pattern as a string but was %s", format_arg(pattern) ) |
||||
end |
||||
if type(func) ~= "function" then |
||||
failure( "assert_error_match", msg, "expected a function as last argument but was %s", format_arg(func) ) |
||||
end |
||||
local ok, errmsg = pcall(func) |
||||
if ok then |
||||
failure( "assert_error_match", msg, "error expected but no error occurred" ) |
||||
end |
||||
if type(errmsg) ~= "string" then |
||||
failure( "assert_error_match", msg, "error as string expected but was %s", format_arg(errmsg) ) |
||||
end |
||||
if not string_find(errmsg, pattern) then |
||||
failure( "assert_error_match", msg, "expected error '%s' to match pattern '%s' but doesn't", errmsg, pattern ) |
||||
end |
||||
end |
||||
traceback_hide( assert_error_match ) |
||||
|
||||
|
||||
function assert_pass(msg, func) |
||||
stats.assertions = stats.assertions + 1 |
||||
if func == nil then |
||||
func, msg = msg, nil |
||||
end |
||||
if type(func) ~= "function" then |
||||
failure( "assert_pass", msg, "expected a function as last argument but was %s", format_arg(func) ) |
||||
end |
||||
local ok, errmsg = pcall(func) |
||||
if not ok then |
||||
failure( "assert_pass", msg, "no error expected but error was: '%s'", errmsg ) |
||||
end |
||||
end |
||||
traceback_hide( assert_pass ) |
||||
|
||||
|
||||
-- lunit.assert_typename functions |
||||
|
||||
for _, typename in ipairs(typenames) do |
||||
local assert_typename = "assert_"..typename |
||||
lunit[assert_typename] = function(actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if type(actual) ~= typename then |
||||
failure( assert_typename, msg, "%s expected but was %s", typename, format_arg(actual) ) |
||||
end |
||||
return actual |
||||
end |
||||
traceback_hide( lunit[assert_typename] ) |
||||
end |
||||
|
||||
|
||||
-- lunit.assert_not_typename functions |
||||
|
||||
for _, typename in ipairs(typenames) do |
||||
local assert_not_typename = "assert_not_"..typename |
||||
lunit[assert_not_typename] = function(actual, msg) |
||||
stats.assertions = stats.assertions + 1 |
||||
if type(actual) == typename then |
||||
failure( assert_not_typename, msg, typename.." not expected but was one" ) |
||||
end |
||||
end |
||||
traceback_hide( lunit[assert_not_typename] ) |
||||
end |
||||
|
||||
|
||||
function lunit.clearstats() |
||||
stats = { |
||||
assertions = 0; |
||||
passed = 0; |
||||
failed = 0; |
||||
errors = 0; |
||||
} |
||||
end |
||||
|
||||
|
||||
local report, reporterrobj |
||||
do |
||||
local testrunner |
||||
|
||||
function lunit.setrunner(newrunner) |
||||
if not ( is_table(newrunner) or is_nil(newrunner) ) then |
||||
return error("lunit.setrunner: Invalid argument", 0) |
||||
end |
||||
local oldrunner = testrunner |
||||
testrunner = newrunner |
||||
return oldrunner |
||||
end |
||||
|
||||
function lunit.loadrunner(name) |
||||
if not is_string(name) then |
||||
return error("lunit.loadrunner: Invalid argument", 0) |
||||
end |
||||
local ok, runner = pcall( require, name ) |
||||
if not ok then |
||||
return error("lunit.loadrunner: Can't load test runner: "..runner, 0) |
||||
end |
||||
return setrunner(runner) |
||||
end |
||||
|
||||
function lunit.getrunner() |
||||
return testrunner |
||||
end |
||||
|
||||
function report(event, ...) |
||||
local f = testrunner and testrunner[event] |
||||
if is_function(f) then |
||||
pcall(f, ...) |
||||
end |
||||
end |
||||
|
||||
function reporterrobj(context, tcname, testname, errobj) |
||||
local fullname = tcname .. "." .. testname |
||||
if context == "setup" then |
||||
fullname = fullname .. ":" .. setupname(tcname, testname) |
||||
elseif context == "teardown" then |
||||
fullname = fullname .. ":" .. teardownname(tcname, testname) |
||||
end |
||||
if errobj.type == __failure__ then |
||||
stats.failed = stats.failed + 1 |
||||
report("fail", fullname, errobj.where, errobj.msg, errobj.usermsg) |
||||
else |
||||
stats.errors = stats.errors + 1 |
||||
report("err", fullname, errobj.msg, errobj.tb) |
||||
end |
||||
end |
||||
end |
||||
|
||||
|
||||
|
||||
local function key_iter(t, k) |
||||
return (next(t,k)) |
||||
end |
||||
|
||||
|
||||
local testcase |
||||
do |
||||
-- Array with all registered testcases |
||||
local _testcases = {} |
||||
|
||||
-- Marks a module as a testcase. |
||||
-- Applied over a module from module("xyz", lunit.testcase). |
||||
function lunit.testcase(m) |
||||
orig_assert( is_table(m) ) |
||||
--orig_assert( m._M == m ) |
||||
orig_assert( is_string(m._NAME) ) |
||||
--orig_assert( is_string(m._PACKAGE) ) |
||||
|
||||
-- Register the module as a testcase |
||||
_testcases[m._NAME] = m |
||||
|
||||
-- Import lunit, fail, assert* and is_* function to the module/testcase |
||||
m.lunit = lunit |
||||
m.fail = lunit.fail |
||||
for funcname, func in pairs(lunit) do |
||||
if "assert" == string_sub(funcname, 1, 6) or "is_" == string_sub(funcname, 1, 3) then |
||||
m[funcname] = func |
||||
end |
||||
end |
||||
end |
||||
|
||||
function lunit.module(name,seeall) |
||||
local m = {} |
||||
if seeall == "seeall" then |
||||
setmetatable(m, { __index = _G }) |
||||
end |
||||
m._NAME = name |
||||
lunit.testcase(m) |
||||
return m |
||||
end |
||||
|
||||
-- Iterator (testcasename) over all Testcases |
||||
function lunit.testcases() |
||||
-- Make a copy of testcases to prevent confusing the iterator when |
||||
-- new testcase are defined |
||||
local _testcases2 = {} |
||||
for k,v in pairs(_testcases) do |
||||
_testcases2[k] = true |
||||
end |
||||
return key_iter, _testcases2, nil |
||||
end |
||||
|
||||
function testcase(tcname) |
||||
return _testcases[tcname] |
||||
end |
||||
end |
||||
|
||||
|
||||
do |
||||
-- Finds a function in a testcase case insensitive |
||||
local function findfuncname(tcname, name) |
||||
for key, value in pairs(testcase(tcname)) do |
||||
if is_string(key) and is_function(value) and string_lower(key) == name then |
||||
return key |
||||
end |
||||
end |
||||
end |
||||
|
||||
function lunit.setupname(tcname) |
||||
return findfuncname(tcname, "setup") |
||||
end |
||||
|
||||
function lunit.teardownname(tcname) |
||||
return findfuncname(tcname, "teardown") |
||||
end |
||||
|
||||
-- Iterator over all test names in a testcase. |
||||
-- Have to collect the names first in case one of the test |
||||
-- functions creates a new global and throws off the iteration. |
||||
function lunit.tests(tcname) |
||||
local testnames = {} |
||||
for key, value in pairs(testcase(tcname)) do |
||||
if is_string(key) and is_function(value) then |
||||
local lfn = string_lower(key) |
||||
if string_sub(lfn, 1, 4) == "test" or string_sub(lfn, -4) == "test" then |
||||
testnames[key] = true |
||||
end |
||||
end |
||||
end |
||||
return key_iter, testnames, nil |
||||
end |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
function lunit.runtest(tcname, testname) |
||||
orig_assert( is_string(tcname) ) |
||||
orig_assert( is_string(testname) ) |
||||
|
||||
if (not getrunner()) then |
||||
loadrunner("lunit.console") |
||||
end |
||||
|
||||
local function callit(context, func) |
||||
if func then |
||||
local err = mypcall(func) |
||||
if err then |
||||
reporterrobj(context, tcname, testname, err) |
||||
return false |
||||
end |
||||
end |
||||
return true |
||||
end |
||||
traceback_hide(callit) |
||||
|
||||
report("run", tcname, testname) |
||||
|
||||
local tc = testcase(tcname) |
||||
local setup = tc[setupname(tcname)] |
||||
local test = tc[testname] |
||||
local teardown = tc[teardownname(tcname)] |
||||
|
||||
local setup_ok = callit( "setup", setup ) |
||||
local test_ok = setup_ok and callit( "test", test ) |
||||
local teardown_ok = setup_ok and callit( "teardown", teardown ) |
||||
|
||||
if setup_ok and test_ok and teardown_ok then |
||||
stats.passed = stats.passed + 1 |
||||
report("pass", tcname, testname) |
||||
end |
||||
end |
||||
traceback_hide(runtest) |
||||
|
||||
|
||||
|
||||
function lunit.run(testpatterns) |
||||
clearstats() |
||||
report("begin") |
||||
for testcasename in lunit.testcases() do |
||||
-- Run tests in the testcases |
||||
for testname in lunit.tests(testcasename) do |
||||
if selected(testpatterns, testname) then |
||||
runtest(testcasename, testname) |
||||
end |
||||
end |
||||
end |
||||
report("done") |
||||
return stats |
||||
end |
||||
traceback_hide(run) |
||||
|
||||
|
||||
function lunit.loadonly() |
||||
clearstats() |
||||
report("begin") |
||||
report("done") |
||||
return stats |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local lunitpat2luapat |
||||
do |
||||
local conv = { |
||||
["^"] = "%^", |
||||
["$"] = "%$", |
||||
["("] = "%(", |
||||
[")"] = "%)", |
||||
["%"] = "%%", |
||||
["."] = "%.", |
||||
["["] = "%[", |
||||
["]"] = "%]", |
||||
["+"] = "%+", |
||||
["-"] = "%-", |
||||
["?"] = ".", |
||||
["*"] = ".*" |
||||
} |
||||
function lunitpat2luapat(str) |
||||
--return "^" .. string.gsub(str, "%W", conv) .. "$" |
||||
-- Above was very annoying, if I want to run all the tests having to do with |
||||
-- RSS, I want to be able to do "-t rss" not "-t \*rss\*". |
||||
return string_gsub(str, "%W", conv) |
||||
end |
||||
end |
||||
|
||||
|
||||
|
||||
local function in_patternmap(map, name) |
||||
if map[name] == true then |
||||
return true |
||||
else |
||||
for _, pat in ipairs(map) do |
||||
if string_find(name, pat) then |
||||
return true |
||||
end |
||||
end |
||||
end |
||||
return false |
||||
end |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- Called from 'lunit' shell script. |
||||
|
||||
function main(argv) |
||||
argv = argv or {} |
||||
|
||||
-- FIXME: Error handling and error messages aren't nice. |
||||
|
||||
local function checkarg(optname, arg) |
||||
if not is_string(arg) then |
||||
return error("lunit.main: option "..optname..": argument missing.", 0) |
||||
end |
||||
end |
||||
|
||||
local function loadtestcase(filename) |
||||
if not is_string(filename) then |
||||
return error("lunit.main: invalid argument") |
||||
end |
||||
local chunk, err = loadfile(filename) |
||||
if err then |
||||
return error(err) |
||||
else |
||||
chunk() |
||||
end |
||||
end |
||||
|
||||
local testpatterns = nil |
||||
local doloadonly = false |
||||
|
||||
local i = 0 |
||||
while i < #argv do |
||||
i = i + 1 |
||||
local arg = argv[i] |
||||
if arg == "--loadonly" then |
||||
doloadonly = true |
||||
elseif arg == "--runner" or arg == "-r" then |
||||
local optname = arg; i = i + 1; arg = argv[i] |
||||
checkarg(optname, arg) |
||||
loadrunner(arg) |
||||
elseif arg == "--test" or arg == "-t" then |
||||
local optname = arg; i = i + 1; arg = argv[i] |
||||
checkarg(optname, arg) |
||||
testpatterns = testpatterns or {} |
||||
testpatterns[#testpatterns+1] = arg |
||||
elseif arg == "--help" or arg == "-h" then |
||||
print[[ |
||||
lunit 0.5 |
||||
Copyright (c) 2004-2009 Michael Roth <mroth@nessie.de> |
||||
This program comes WITHOUT WARRANTY OF ANY KIND. |
||||
|
||||
Usage: lua test [OPTIONS] [--] scripts |
||||
|
||||
Options: |
||||
|
||||
-r, --runner RUNNER Testrunner to use, defaults to 'lunit-console'. |
||||
-t, --test PATTERN Which tests to run, may contain * or ? wildcards. |
||||
--loadonly Only load the tests. |
||||
-h, --help Print this help screen. |
||||
|
||||
Please report bugs to <mroth@nessie.de>. |
||||
]] |
||||
return |
||||
elseif arg == "--" then |
||||
while i < #argv do |
||||
i = i + 1; arg = argv[i] |
||||
loadtestcase(arg) |
||||
end |
||||
else |
||||
loadtestcase(arg) |
||||
end |
||||
end |
||||
|
||||
if doloadonly then |
||||
return loadonly() |
||||
else |
||||
return run(testpatterns) |
||||
end |
||||
end |
||||
|
||||
clearstats() |
||||
|
||||
return lunit |
@ -0,0 +1,156 @@ |
||||
|
||||
--[[-------------------------------------------------------------------------- |
||||
|
||||
This file is part of lunit 0.5. |
||||
|
||||
For Details about lunit look at: http://www.mroth.net/lunit/ |
||||
|
||||
Author: Michael Roth <mroth@nessie.de> |
||||
|
||||
Copyright (c) 2006-2008 Michael Roth <mroth@nessie.de> |
||||
|
||||
Permission is hereby granted, free of charge, to any person |
||||
obtaining a copy of this software and associated documentation |
||||
files (the "Software"), to deal in the Software without restriction, |
||||
including without limitation the rights to use, copy, modify, merge, |
||||
publish, distribute, sublicense, and/or sell copies of the Software, |
||||
and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be |
||||
included in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
||||
--]]-------------------------------------------------------------------------- |
||||
|
||||
|
||||
|
||||
--[[ |
||||
|
||||
begin() |
||||
run(testcasename, testname) |
||||
err(fullname, message, traceback) |
||||
fail(fullname, where, message, usermessage) |
||||
pass(testcasename, testname) |
||||
done() |
||||
|
||||
Fullname: |
||||
testcase.testname |
||||
testcase.testname:setupname |
||||
testcase.testname:teardownname |
||||
|
||||
--]] |
||||
|
||||
|
||||
lunit = require "lunit" |
||||
|
||||
local lunit_console |
||||
|
||||
if _VERSION >= 'Lua 5.2' then |
||||
|
||||
lunit_console = setmetatable({},{__index = _ENV}) |
||||
_ENV = lunit_console |
||||
|
||||
else |
||||
|
||||
module( "lunit-console", package.seeall ) |
||||
lunit_console = _M |
||||
|
||||
end |
||||
|
||||
|
||||
|
||||
local function printformat(format, ...) |
||||
io.write( string.format(format, ...) ) |
||||
end |
||||
|
||||
|
||||
local columns_printed = 0 |
||||
|
||||
local function writestatus(char) |
||||
if columns_printed == 0 then |
||||
io.write(" ") |
||||
end |
||||
if columns_printed == 60 then |
||||
io.write("\n ") |
||||
columns_printed = 0 |
||||
end |
||||
io.write(char) |
||||
io.flush() |
||||
columns_printed = columns_printed + 1 |
||||
end |
||||
|
||||
|
||||
local msgs = {} |
||||
|
||||
|
||||
function begin() |
||||
local total_tc = 0 |
||||
local total_tests = 0 |
||||
|
||||
msgs = {} -- e |
||||
|
||||
for tcname in lunit.testcases() do |
||||
total_tc = total_tc + 1 |
||||
for testname, test in lunit.tests(tcname) do |
||||
total_tests = total_tests + 1 |
||||
end |
||||
end |
||||
|
||||
printformat("Loaded testsuite with %d tests in %d testcases.\n\n", total_tests, total_tc) |
||||
end |
||||
|
||||
|
||||
function run(testcasename, testname) |
||||
-- NOP |
||||
end |
||||
|
||||
|
||||
function err(fullname, message, traceback) |
||||
writestatus("E") |
||||
msgs[#msgs+1] = "Error! ("..fullname.."):\n"..message.."\n\t"..table.concat(traceback, "\n\t") .. "\n" |
||||
end |
||||
|
||||
|
||||
function fail(fullname, where, message, usermessage) |
||||
writestatus("F") |
||||
local text = "Failure ("..fullname.."):\n".. |
||||
where..": "..message.."\n" |
||||
|
||||
if usermessage then |
||||
text = text .. where..": "..usermessage.."\n" |
||||
end |
||||
|
||||
msgs[#msgs+1] = text |
||||
end |
||||
|
||||
|
||||
function pass(testcasename, testname) |
||||
writestatus(".") |
||||
end |
||||
|
||||
|
||||
|
||||
function done() |
||||
printformat("\n\n%d Assertions checked.\n", lunit.stats.assertions ) |
||||
print() |
||||
|
||||
for i, msg in ipairs(msgs) do |
||||
printformat( "%3d) %s\n", i, msg ) |
||||
end |
||||
|
||||
printformat("Testsuite finished (%d passed, %d failed, %d errors).\n", |
||||
lunit.stats.passed, lunit.stats.failed, lunit.stats.errors ) |
||||
end |
||||
|
||||
|
||||
return lunit_console |
||||
|
||||
|
@ -0,0 +1,21 @@ |
||||
local atexit = require "atexit" |
||||
local lunit = require "lunit" |
||||
|
||||
--for k,v in pairs(debug.getinfo(1,"S")) do print(k,v) end |
||||
-- autonameing |
||||
-- module("bcrc-test", lunit.testcase, package.seeall) |
||||
|
||||
atexit(function() |
||||
local _, emsg = xpcall(function() |
||||
lunit.main(arg) |
||||
end, debug.traceback) |
||||
if emsg then |
||||
print(emsg) |
||||
os.exit(1) |
||||
end |
||||
if lunit.stats.failed > 0 or lunit.stats.errors > 0 then |
||||
os.exit(1) |
||||
end |
||||
end) |
||||
|
||||
return lunit |
@ -0,0 +1,167 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* Lua extension that provides access to upb_table. This is an internal-only |
||||
* interface and exists for the sole purpose of writing a C code generator in |
||||
* Lua that can dump a upb_table as static C initializers. This lets us use |
||||
* Lua for convenient string manipulation while saving us from re-implementing |
||||
* the upb_table hash function and hash table layout / collision strategy in |
||||
* Lua. |
||||
* |
||||
* Since this is used only as part of the toolchain (and not part of the |
||||
* runtime) we do not hold this module to the same stringent requirements as |
||||
* the main Lua modules (for example that misbehaving Lua programs cannot |
||||
* crash the interpreter). |
||||
*/ |
||||
|
||||
#include <float.h> |
||||
#include <math.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "lauxlib.h" |
||||
#include "bindings/lua/upb.h" |
||||
#include "upb/def.h" |
||||
|
||||
static void lupbtable_setnum(lua_State *L, int tab, const char *key, |
||||
lua_Number val) { |
||||
lua_pushnumber(L, val); |
||||
lua_setfield(L, tab - 1, key); |
||||
} |
||||
|
||||
static void lupbtable_pushval(lua_State *L, upb_value val, upb_ctype_t type) { |
||||
switch (type) { |
||||
case UPB_CTYPE_INT32: |
||||
lua_pushnumber(L, upb_value_getint32(val)); |
||||
break; |
||||
case UPB_CTYPE_PTR: |
||||
lupb_def_pushwrapper(L, upb_value_getptr(val), NULL); |
||||
break; |
||||
case UPB_CTYPE_CSTR: |
||||
lua_pushstring(L, upb_value_getcstr(val)); |
||||
break; |
||||
default: |
||||
luaL_error(L, "Unexpected type: %d", type); |
||||
} |
||||
} |
||||
|
||||
// Sets a few fields common to both hash table entries and arrays.
|
||||
static void lupbtable_setmetafields(lua_State *L, int type, const void *ptr) { |
||||
// We tack this onto every entry so we know it even if the entries
|
||||
// don't stay with the table.
|
||||
lua_pushnumber(L, type); |
||||
lua_setfield(L, -2, "valtype"); |
||||
|
||||
// Set this to facilitate linking.
|
||||
lua_pushlightuserdata(L, (void*)ptr); |
||||
lua_setfield(L, -2, "ptr"); |
||||
} |
||||
|
||||
static void lupbtable_pushent(lua_State *L, const upb_tabent *e, |
||||
bool inttab, int type) { |
||||
lua_newtable(L); |
||||
if (!upb_tabent_isempty(e)) { |
||||
if (inttab) { |
||||
lua_pushnumber(L, e->key.num); |
||||
} else { |
||||
lua_pushstring(L, e->key.str); |
||||
} |
||||
lua_setfield(L, -2, "key"); |
||||
lupbtable_pushval(L, e->val, type); |
||||
lua_setfield(L, -2, "value"); |
||||
} |
||||
lua_pushlightuserdata(L, (void*)e->next); |
||||
lua_setfield(L, -2, "next"); |
||||
lupbtable_setmetafields(L, type, e); |
||||
} |
||||
|
||||
// Dumps the shared part of upb_table into a Lua table.
|
||||
static void lupbtable_pushtable(lua_State *L, const upb_table *t, bool inttab) { |
||||
lua_newtable(L); |
||||
lupbtable_setnum(L, -1, "count", t->count); |
||||
lupbtable_setnum(L, -1, "mask", t->mask); |
||||
lupbtable_setnum(L, -1, "type", t->type); |
||||
lupbtable_setnum(L, -1, "size_lg2", t->size_lg2); |
||||
|
||||
lua_newtable(L); |
||||
for (int i = 0; i < upb_table_size(t); i++) { |
||||
lupbtable_pushent(L, &t->entries[i], inttab, t->type); |
||||
lua_rawseti(L, -2, i + 1); |
||||
} |
||||
lua_setfield(L, -2, "entries"); |
||||
} |
||||
|
||||
// Dumps a upb_inttable to a Lua table.
|
||||
static void lupbtable_pushinttable(lua_State *L, const upb_inttable *t) { |
||||
lupbtable_pushtable(L, &t->t, true); |
||||
lupbtable_setnum(L, -1, "array_size", t->array_size); |
||||
lupbtable_setnum(L, -1, "array_count", t->array_count); |
||||
|
||||
lua_newtable(L); |
||||
for (int i = 0; i < t->array_size; i++) { |
||||
lua_newtable(L); |
||||
if (upb_arrhas(t->array[i])) { |
||||
lupbtable_pushval(L, t->array[i], t->t.type); |
||||
lua_setfield(L, -2, "val"); |
||||
} |
||||
lupbtable_setmetafields(L, t->t.type, &t->array[i]); |
||||
lua_rawseti(L, -2, i + 1); |
||||
} |
||||
lua_setfield(L, -2, "array"); |
||||
} |
||||
|
||||
static void lupbtable_pushstrtable(lua_State *L, const upb_strtable *t) { |
||||
lupbtable_pushtable(L, &t->t, false); |
||||
} |
||||
|
||||
static int lupbtable_msgdef_itof(lua_State *L) { |
||||
const upb_msgdef *m = lupb_msgdef_check(L, 1); |
||||
lupbtable_pushinttable(L, &m->itof); |
||||
return 1; |
||||
} |
||||
|
||||
static int lupbtable_msgdef_ntof(lua_State *L) { |
||||
const upb_msgdef *m = lupb_msgdef_check(L, 1); |
||||
lupbtable_pushstrtable(L, &m->ntof); |
||||
return 1; |
||||
} |
||||
|
||||
static int lupbtable_enumdef_iton(lua_State *L) { |
||||
const upb_enumdef *e = lupb_enumdef_check(L, 1); |
||||
lupbtable_pushinttable(L, &e->iton); |
||||
return 1; |
||||
} |
||||
|
||||
static int lupbtable_enumdef_ntoi(lua_State *L) { |
||||
const upb_enumdef *e = lupb_enumdef_check(L, 1); |
||||
lupbtable_pushstrtable(L, &e->ntoi); |
||||
return 1; |
||||
} |
||||
|
||||
static void lupbtable_setfieldi(lua_State *L, const char *field, int i) { |
||||
lua_pushnumber(L, i); |
||||
lua_setfield(L, -2, field); |
||||
} |
||||
|
||||
static const struct luaL_Reg lupbtable_toplevel_m[] = { |
||||
{"msgdef_itof", lupbtable_msgdef_itof}, |
||||
{"msgdef_ntof", lupbtable_msgdef_ntof}, |
||||
{"enumdef_iton", lupbtable_enumdef_iton}, |
||||
{"enumdef_ntoi", lupbtable_enumdef_ntoi}, |
||||
{NULL, NULL} |
||||
}; |
||||
|
||||
int luaopen_upbtable(lua_State *L) { |
||||
lupb_newlib(L, "upb.table", lupbtable_toplevel_m); |
||||
|
||||
// We define these here because they are not public (at least at the moment).
|
||||
lupbtable_setfieldi(L, "CTYPE_PTR", UPB_CTYPE_PTR); |
||||
lupbtable_setfieldi(L, "CTYPE_INT32", UPB_CTYPE_INT32); |
||||
|
||||
lua_pushlightuserdata(L, NULL); |
||||
lua_setfield(L, -2, "NULL"); |
||||
|
||||
return 1; // Return a single Lua value, the package table created above.
|
||||
} |
@ -1,109 +1,262 @@ |
||||
|
||||
require "upb" |
||||
local upb = require "upb" |
||||
local lunit = require "lunitx" |
||||
|
||||
symtab = upb.SymbolTable{ |
||||
upb.MessageDef{fqname="A", fields={ |
||||
upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, |
||||
upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} |
||||
if _VERSION >= 'Lua 5.2' then |
||||
_ENV = lunit.module("testupb", "seeall") |
||||
else |
||||
module("testupb", lunit.testcase, package.seeall) |
||||
end |
||||
|
||||
function test_fielddef() |
||||
local f = upb.FieldDef() |
||||
assert_false(f:is_frozen()) |
||||
assert_nil(f:number()) |
||||
assert_nil(f:name()) |
||||
assert_equal(upb.LABEL_OPTIONAL, f:label()) |
||||
|
||||
f:set_name("foo_field") |
||||
f:set_number(3) |
||||
f:set_label(upb.LABEL_REPEATED) |
||||
f:set_type(upb.TYPE_FLOAT) |
||||
|
||||
assert_equal("foo_field", f:name()) |
||||
assert_equal(3, f:number()) |
||||
assert_equal(upb.LABEL_REPEATED, f:label()) |
||||
assert_equal(upb.TYPE_FLOAT, f:type()) |
||||
|
||||
local f2 = upb.FieldDef{ |
||||
name = "foo", number = 5, type = upb.TYPE_DOUBLE, label = upb.LABEL_REQUIRED |
||||
} |
||||
} |
||||
|
||||
symtab = upb.SymbolTable{ |
||||
upb.MessageDef{fqname="A", fields={ |
||||
upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, |
||||
upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} |
||||
}, |
||||
upb.MessageDef{fqname="B"} |
||||
} |
||||
A, B, C = symtab:lookup("A", "B") |
||||
print(A) |
||||
print(B) |
||||
print(C) |
||||
|
||||
a = A() |
||||
a2 = upb.Message(A) |
||||
print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) |
||||
a.a = 2 |
||||
a2.a = 3 |
||||
print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) |
||||
|
||||
A = symtab:lookup("A") |
||||
if not A then |
||||
error("Could not find A") |
||||
|
||||
assert_equal("foo", f2:name()) |
||||
assert_equal(5, f2:number()) |
||||
assert_equal(upb.TYPE_DOUBLE, f2:type()) |
||||
assert_equal(upb.LABEL_REQUIRED, f2:label()) |
||||
end |
||||
|
||||
f = io.open("../../upb/descriptor.pb") |
||||
if not f then |
||||
error("Couldn't open descriptor.pb, try running 'make descriptorgen'") |
||||
function test_enumdef() |
||||
local e = upb.EnumDef() |
||||
assert_equal(0, #e) |
||||
assert_nil(e:value(5)) |
||||
assert_nil(e:value("NONEXISTENT_NAME")) |
||||
|
||||
for name, value in e:values() do |
||||
fail() |
||||
end |
||||
|
||||
e:add("VAL1", 1) |
||||
e:add("VAL2", 2) |
||||
|
||||
local values = {} |
||||
for name, value in e:values() do |
||||
values[name] = value |
||||
end |
||||
|
||||
assert_equal(1, values["VAL1"]) |
||||
assert_equal(2, values["VAL2"]) |
||||
|
||||
local e2 = upb.EnumDef{ |
||||
values = { |
||||
{"FOO", 1}, |
||||
{"BAR", 77}, |
||||
} |
||||
} |
||||
|
||||
assert_equal(1, e2:value("FOO")) |
||||
assert_equal(77, e2:value("BAR")) |
||||
assert_equal("FOO", e2:value(1)) |
||||
assert_equal("BAR", e2:value(77)) |
||||
end |
||||
symtab:parsedesc(f:read("*all")) |
||||
symtab:load_descriptor() |
||||
symtab:load_descriptor_file() |
||||
|
||||
upb.pb.load_descriptor(f:read("*all")) |
||||
function test_empty_msgdef() |
||||
local md = upb.MessageDef() |
||||
assert_nil(md:full_name()) -- Def without name is anonymous. |
||||
assert_false(md:is_frozen()) |
||||
assert_equal(0, #md) |
||||
assert_nil(md:field("nonexistent_field")) |
||||
assert_nil(md:field(3)) |
||||
for field in md:fields() do |
||||
fail() |
||||
end |
||||
|
||||
upb.freeze(md) |
||||
assert_true(md:is_frozen()) |
||||
assert_equal(0, #md) |
||||
assert_nil(md:field("nonexistent_field")) |
||||
assert_nil(md:field(3)) |
||||
for field in md:fields() do |
||||
fail() |
||||
end |
||||
end |
||||
|
||||
function test_msgdef_constructor() |
||||
local f1 = upb.FieldDef{name = "field1", number = 7, type = upb.TYPE_INT32} |
||||
local f2 = upb.FieldDef{name = "field2", number = 8, type = upb.TYPE_INT32} |
||||
local md = upb.MessageDef{ |
||||
full_name = "TestMessage", |
||||
fields = {f1, f2} |
||||
} |
||||
assert_equal("TestMessage", md:full_name()) |
||||
assert_false(md:is_frozen()) |
||||
assert_equal(2, #md) |
||||
assert_equal(f1, md:field("field1")) |
||||
assert_equal(f2, md:field("field2")) |
||||
assert_equal(f1, md:field(7)) |
||||
assert_equal(f2, md:field(8)) |
||||
local count = 0 |
||||
local found = {} |
||||
for field in md:fields() do |
||||
count = count + 1 |
||||
found[field] = true |
||||
end |
||||
assert_equal(2, count) |
||||
assert_true(found[f1]) |
||||
assert_true(found[f2]) |
||||
|
||||
upb.pb.load_descriptor_file("../../src/descriptor.pb", symtab) |
||||
upb.freeze(md) |
||||
end |
||||
|
||||
function test_msgdef_setters() |
||||
local md = upb.MessageDef() |
||||
md:set_full_name("Message1") |
||||
assert_equal("Message1", md:full_name()) |
||||
local f = upb.FieldDef{name = "field1", number = 3, type = upb.TYPE_DOUBLE} |
||||
md:add{f} |
||||
assert_equal(1, #md) |
||||
assert_equal(f, md:field("field1")) |
||||
end |
||||
|
||||
function test_msgdef_errors() |
||||
assert_error(function() upb.MessageDef{bad_initializer_key = 5} end) |
||||
local md = upb.MessageDef() |
||||
assert_error(function() |
||||
-- Duplicate field number. |
||||
upb.MessageDef{ |
||||
fields = { |
||||
upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, |
||||
upb.FieldDef{name = "field2", number = 1, type = upb.TYPE_INT32} |
||||
} |
||||
} |
||||
end) |
||||
assert_error(function() |
||||
-- Duplicate field name. |
||||
upb.MessageDef{ |
||||
fields = { |
||||
upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, |
||||
upb.FieldDef{name = "field1", number = 2, type = upb.TYPE_INT32} |
||||
} |
||||
} |
||||
end) |
||||
|
||||
-- attempt to set a name with embedded NULLs. |
||||
assert_error_match("names cannot have embedded NULLs", function() |
||||
md:set_full_name("abc\0def") |
||||
end) |
||||
|
||||
upb.freeze(md) |
||||
-- Attempt to mutate frozen MessageDef. |
||||
-- TODO(haberman): better error message and test for message. |
||||
assert_error(function() |
||||
md:add{upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}} |
||||
end) |
||||
assert_error(function() |
||||
md:set_full_name("abc") |
||||
end) |
||||
|
||||
-- Attempt to freeze a msgdef without freezing its subdef. |
||||
assert_error_match("is not frozen or being frozen", function() |
||||
m1 = upb.MessageDef() |
||||
upb.freeze( |
||||
upb.MessageDef{ |
||||
fields = { |
||||
upb.FieldDef{name = "f1", number = 1, type = upb.TYPE_MESSAGE, |
||||
subdef = m1} |
||||
} |
||||
} |
||||
) |
||||
end) |
||||
end |
||||
|
||||
function test_symtab() |
||||
local empty = upb.SymbolTable() |
||||
assert_equal(0, #empty:getdefs(upb.DEF_ANY)) |
||||
|
||||
local symtab = upb.SymbolTable{ |
||||
upb.MessageDef{full_name = "TestMessage"}, |
||||
upb.MessageDef{full_name = "ContainingMessage", fields = { |
||||
upb.FieldDef{name = "field1", number = 1, type = upb.TYPE_INT32}, |
||||
upb.FieldDef{name = "field2", number = 2, type = upb.TYPE_MESSAGE, |
||||
subdef_name = ".TestMessage"} |
||||
} |
||||
} |
||||
} |
||||
|
||||
local msgdef1 = symtab:lookup("TestMessage") |
||||
local msgdef2 = symtab:lookup("ContainingMessage") |
||||
assert_not_nil(msgdef1) |
||||
assert_not_nil(msgdef2) |
||||
assert_equal(msgdef1, msgdef2:field("field2"):subdef()) |
||||
assert_true(msgdef1:is_frozen()) |
||||
assert_true(msgdef2:is_frozen()) |
||||
|
||||
symtab:add{ |
||||
upb.MessageDef{full_name = "ContainingMessage2", fields = { |
||||
upb.FieldDef{name = "field5", number = 5, type = upb.TYPE_MESSAGE, |
||||
subdef = msgdef2} |
||||
} |
||||
} |
||||
} |
||||
|
||||
local msgdef3 = symtab:lookup("ContainingMessage2") |
||||
assert_not_nil(msgdef3) |
||||
assert_equal(msgdef3:field("field5"):subdef(), msgdef2) |
||||
end |
||||
|
||||
f = io.open("../../benchmarks/google_messages.proto.pb") |
||||
if not f then |
||||
error("Couldn't open google_messages.proto.pb, try running 'make benchmarks'") |
||||
-- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer |
||||
-- can be defined in Lua. |
||||
if _VERSION >= 'Lua 5.2' then |
||||
function defer(fn) |
||||
setmetatable({}, { __gc = fn }) |
||||
end |
||||
else |
||||
function defer(fn) |
||||
getmetatable(newproxy(true)).__gc = fn |
||||
end |
||||
end |
||||
symtab:parsedesc(f:read("*all")) |
||||
|
||||
for _, def in ipairs(symtab:getdefs(-1)) do |
||||
print(def:name()) |
||||
function test_finalizer() |
||||
-- Tests that we correctly handle a call into an already-finalized object. |
||||
-- Collectible objects are finalized in the opposite order of creation. |
||||
do |
||||
local t = {} |
||||
defer(function() |
||||
assert_error_match("called into dead def", function() |
||||
-- Generic def call. |
||||
t[1]:full_name() |
||||
end) |
||||
assert_error_match("called into dead msgdef", function() |
||||
-- Specific msgdef call. |
||||
t[1]:add() |
||||
end) |
||||
assert_error_match("called into dead enumdef", function() |
||||
t[2]:values() |
||||
end) |
||||
assert_error_match("called into dead fielddef", function() |
||||
t[3]:number() |
||||
end) |
||||
assert_error_match("called into dead symtab", |
||||
function() t[4]:lookup() |
||||
end) |
||||
end) |
||||
t = { |
||||
upb.MessageDef(), |
||||
upb.EnumDef(), |
||||
upb.FieldDef(), |
||||
upb.SymbolTable(), |
||||
} |
||||
end |
||||
collectgarbage() |
||||
end |
||||
|
||||
SpeedMessage1 = symtab:lookup("benchmarks.SpeedMessage1") |
||||
SpeedMessage2 = symtab:lookup("benchmarks.SpeedMessage2") |
||||
print(SpeedMessage1:name()) |
||||
|
||||
msg = MyType() |
||||
msg:Decode(str) |
||||
|
||||
msg:DecodeJSON(str) |
||||
|
||||
msg = upb.pb.decode(str, MyType) |
||||
str = upb.pb.encode(msg) |
||||
|
||||
msg = upb.pb.decode_text(str, MyType) |
||||
str = upb.pb.encode_text(msg) |
||||
|
||||
upb.clear(msg) |
||||
upb.msgdef(msg) |
||||
upb.has(msg, "foo_bar") |
||||
|
||||
msg = upb.json.decode(str, MyType) |
||||
|
||||
msg = upb.pb.DecodeText(str) |
||||
msg = upb.pb.EncodeText(msg) |
||||
upb. |
||||
|
||||
upb.pb.decode_into(msg, str) |
||||
|
||||
str = upb.json.Encode(msg) |
||||
upb.json.DecodeInto(msg, str) |
||||
f = assert(io.open("../../benchmarks/google_message1.dat")) |
||||
msg:Parse(f:read("*all")) |
||||
print(msg:ToText()) |
||||
print(upb.json.encode(msg)) |
||||
|
||||
msg = SpeedMessage2() |
||||
f = assert(io.open("../../benchmarks/google_message2.dat")) |
||||
msg:Parse(f:read("*all")) |
||||
print(msg:ToText()) |
||||
--msg:Serialize() |
||||
--msg:FromText(str) |
||||
-- print(msg.field129) |
||||
-- print(msg.field271) |
||||
--print(msg.field15.field15) |
||||
--msg.field15.field15 = "my override" |
||||
--print(msg.field15.field15) |
||||
-- print(msg.field1) |
||||
-- print(msg.field1) |
||||
-- msg.field1 = "YEAH BABY!" |
||||
-- print(msg.field1) |
||||
-- print(msg.field129) |
||||
-- msg.field129 = 5 |
||||
-- print(msg.field129) |
||||
--]] |
||||
lunit.main() |
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* Shared definitions for upb Lua modules. |
||||
*/ |
||||
|
||||
#ifndef UPB_LUA_UPB_H_ |
||||
#define UPB_LUA_UPB_H_ |
||||
|
||||
#include "upb/def.h" |
||||
|
||||
// Lua 5.1/5.2 compatibility code.
|
||||
#if LUA_VERSION_NUM == 501 |
||||
|
||||
#define lua_rawlen lua_objlen |
||||
#define lupb_newlib(L, name, l) luaL_register(L, name, l) |
||||
#define lupb_setfuncs(L, l) luaL_register(L, NULL, l) |
||||
#define LUPB_OPENFUNC(mod) luaopen_ ## mod ## upb5_1 |
||||
|
||||
void *luaL_testudata(lua_State *L, int ud, const char *tname); |
||||
|
||||
#elif LUA_VERSION_NUM == 502 |
||||
|
||||
// Lua 5.2 modules are not expected to set a global variable, so "name" is
|
||||
// unused.
|
||||
#define lupb_newlib(L, name, l) luaL_newlib(L, l) |
||||
#define lupb_setfuncs(L, l) luaL_setfuncs(L, l, 0) |
||||
int luaL_typerror(lua_State *L, int narg, const char *tname); |
||||
#define LUPB_OPENFUNC(mod) luaopen_ ## mod ## upb5_2 |
||||
|
||||
#else |
||||
#error Only Lua 5.1 and 5.2 are supported |
||||
#endif |
||||
|
||||
const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); |
||||
const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg); |
||||
const char *lupb_checkname(lua_State *L, int narg); |
||||
bool lupb_def_pushwrapper(lua_State *L, const upb_def *def, const void *owner); |
||||
void lupb_def_pushnewrapper(lua_State *L, const upb_def *def, |
||||
const void *owner); |
||||
|
||||
#endif // UPB_LUA_UPB_H_
|
@ -0,0 +1,64 @@ |
||||
// |
||||
// upb - a minimalist implementation of protocol buffers. |
||||
// |
||||
// Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
// Author: Josh Haberman <jhaberman@gmail.com> |
||||
// |
||||
// Schema used in test_decoder.cc. It contains two fields (one optional |
||||
// and one repeated) for each type. |
||||
|
||||
package upb.test_decoder; |
||||
|
||||
message M { |
||||
optional M m = 1; |
||||
} |
||||
|
||||
enum E { |
||||
FOO = 1; |
||||
} |
||||
|
||||
message EmptyMessage {} |
||||
|
||||
message DecoderTest { |
||||
optional double f_double = 1; |
||||
optional float f_float = 2; |
||||
optional int64 f_int64 = 3; |
||||
optional uint64 f_uint64 = 4; |
||||
optional int32 f_int32 = 5; |
||||
optional fixed64 f_fixed64 = 6; |
||||
optional fixed32 f_fixed32 = 7; |
||||
optional bool f_bool = 8; |
||||
optional string f_string = 9; |
||||
optional bytes f_bytes = 12; |
||||
optional uint32 f_uint32 = 13; |
||||
optional sfixed32 f_sfixed32 = 15; |
||||
optional sfixed64 f_sfixed64 = 16; |
||||
optional sint32 f_sint32 = 17; |
||||
optional sint64 f_sint64 = 18; |
||||
|
||||
optional DecoderTest f_message = 11; |
||||
optional E f_enum = 14; |
||||
|
||||
|
||||
repeated double r_double = 536869912; |
||||
repeated float r_float = 536869913; |
||||
repeated int64 r_int64 = 536869914; |
||||
repeated uint64 r_uint64 = 536869915; |
||||
repeated int32 r_int32 = 536869916; |
||||
repeated fixed64 r_fixed64 = 536869917; |
||||
repeated fixed32 r_fixed32 = 536869918; |
||||
repeated bool r_bool = 536869919; |
||||
repeated string r_string = 536869920; |
||||
repeated bytes r_bytes = 536869923; |
||||
repeated uint32 r_uint32 = 536869924; |
||||
repeated sfixed32 r_sfixed32 = 536869926; |
||||
repeated sfixed64 r_sfixed64 = 536869927; |
||||
repeated sint32 r_sint32 = 536869928; |
||||
repeated sint64 r_sint64 = 536869929; |
||||
|
||||
repeated DecoderTest r_message = 536869922; |
||||
repeated E r_enum = 536869925; |
||||
|
||||
// To allow arbitrary padding. |
||||
optional string nop_field = 40; |
||||
} |
@ -0,0 +1,18 @@ |
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
// Author: haberman@google.com (Josh Haberman)
|
||||
|
||||
#include <stdlib.h> |
||||
#ifdef USE_GOOGLE |
||||
#include "base/init_google.h" |
||||
#endif |
||||
|
||||
extern "C" { |
||||
int run_tests(int argc, char *argv[]); |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
#ifdef USE_GOOGLE |
||||
InitGoogle(NULL, &argc, &argv, true); |
||||
#endif |
||||
run_tests(argc, argv); |
||||
} |
@ -0,0 +1,414 @@ |
||||
--[[ |
||||
|
||||
upb - a minimalist implementation of protocol buffers. |
||||
|
||||
Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
Author: Josh Haberman <jhaberman@gmail.com> |
||||
|
||||
Routines for dumping internal data structures into C initializers |
||||
that can be compiled into a .o file. |
||||
|
||||
--]] |
||||
|
||||
local upbtable = require "upbtable" |
||||
local upb = require "upb" |
||||
local export = {} |
||||
|
||||
-- A tiny little abstraction that decouples the dump_* functions from |
||||
-- what they're writing to (appending to a string, writing to file I/O, etc). |
||||
-- This could possibly matter since naive string building is O(n^2) in the |
||||
-- number of appends. |
||||
function export.str_appender() |
||||
local str = "" |
||||
local function append(fmt, ...) |
||||
str = str .. string.format(fmt, ...) |
||||
end |
||||
local function get() |
||||
return str |
||||
end |
||||
return append, get |
||||
end |
||||
|
||||
function export.file_appender(file) |
||||
local f = file |
||||
local function append(fmt, ...) |
||||
f:write(string.format(fmt, ...)) |
||||
end |
||||
return append |
||||
end |
||||
|
||||
-- const(f, label) -> UPB_LABEL_REPEATED, where f:label() == upb.LABEL_REPEATED |
||||
function const(obj, name) |
||||
local val = obj[name](obj) |
||||
for k, v in pairs(upb) do |
||||
if v == val and string.find(k, "^" .. string.upper(name)) then |
||||
return "UPB_" .. k |
||||
end |
||||
end |
||||
assert(false, "Couldn't find constant") |
||||
end |
||||
|
||||
--[[ |
||||
|
||||
LinkTable: an object that tracks all linkable objects and their offsets to |
||||
facilitate linking. |
||||
|
||||
--]] |
||||
|
||||
local LinkTable = {} |
||||
function LinkTable:new(basename, types) |
||||
local linktab = { |
||||
basename = basename, |
||||
types = types, |
||||
table = {}, -- ptr -> {type, 0-based offset} |
||||
obj_arrays = {} -- Establishes the ordering for each object type |
||||
} |
||||
for type, _ in pairs(types) do |
||||
linktab.obj_arrays[type] = {} |
||||
end |
||||
setmetatable(linktab, {__index = LinkTable}) -- Inheritance |
||||
return linktab |
||||
end |
||||
|
||||
-- Adds a new object to the sequence of objects of this type. |
||||
function LinkTable:add(objtype, ptr, obj) |
||||
obj = obj or ptr |
||||
assert(self.table[obj] == nil) |
||||
assert(self.types[objtype]) |
||||
local arr = self.obj_arrays[objtype] |
||||
self.table[ptr] = {objtype, #arr} |
||||
arr[#arr + 1] = obj |
||||
end |
||||
|
||||
-- Returns a C symbol name for the given objtype and offset. |
||||
function LinkTable:csym(objtype, offset) |
||||
local typestr = assert(self.types[objtype]) |
||||
return string.format("%s_%s[%d]", self.basename, typestr, offset) |
||||
end |
||||
|
||||
-- Returns the address of the given C object. |
||||
function LinkTable:addr(obj) |
||||
if obj == upbtable.NULL then |
||||
return "NULL" |
||||
else |
||||
local tabent = assert(self.table[obj], "unknown object") |
||||
return "&" .. self:csym(tabent[1], tabent[2]) |
||||
end |
||||
end |
||||
|
||||
-- Returns an array declarator indicating how many objects have been added. |
||||
function LinkTable:cdecl(objtype) |
||||
return self:csym(objtype, #self.obj_arrays[objtype]) |
||||
end |
||||
|
||||
function LinkTable:objs(objtype) |
||||
-- Return iterator function, allowing use as: |
||||
-- for obj in linktable:objs(type) do |
||||
-- -- ... |
||||
-- done |
||||
local array = self.obj_arrays[objtype] |
||||
local i = 0 |
||||
return function() |
||||
i = i + 1 |
||||
if array[i] then return array[i] end |
||||
end |
||||
end |
||||
|
||||
--[[ |
||||
|
||||
Dumper: an object that can dump C initializers for several constructs. |
||||
Uses a LinkTable to resolve references when necessary. |
||||
|
||||
--]] |
||||
|
||||
local Dumper = {} |
||||
function Dumper:new(linktab) |
||||
local obj = {linktab = linktab} |
||||
setmetatable(obj, {__index = Dumper}) -- Inheritance |
||||
return obj |
||||
end |
||||
|
||||
-- Dumps a upb_value, eg: |
||||
-- UPB_VALUE_INIT_INT32(5) |
||||
function Dumper:value(val, upbtype) |
||||
if type(val) == "nil" then |
||||
return "UPB_VALUE_INIT_NONE" |
||||
elseif type(val) == "number" then |
||||
-- Use upbtype to disambiguate what kind of number it is. |
||||
if upbtype == upbtable.CTYPE_INT32 then |
||||
return string.format("UPB_VALUE_INIT_INT32(%d)", val) |
||||
else |
||||
-- TODO(haberman): add support for these so we can properly support |
||||
-- default values. |
||||
error("Unsupported number type " .. upbtype) |
||||
end |
||||
elseif type(val) == "string" then |
||||
return string.format('UPB_VALUE_INIT_CONSTPTR("%s")', val) |
||||
else |
||||
-- We take this as an object reference that has an entry in the link table. |
||||
return string.format("UPB_VALUE_INIT_CONSTPTR(%s)", self.linktab:addr(val)) |
||||
end |
||||
end |
||||
|
||||
-- Dumps a table key. |
||||
function Dumper:tabkey(key) |
||||
if type(key) == "nil" then |
||||
return "UPB_TABKEY_NONE" |
||||
elseif type(key) == "string" then |
||||
return string.format('UPB_TABKEY_STR("%s")', key) |
||||
else |
||||
return string.format("UPB_TABKEY_NUM(%d)", key) |
||||
end |
||||
end |
||||
|
||||
-- Dumps a table entry. |
||||
function Dumper:tabent(ent) |
||||
local key = self:tabkey(ent.key) |
||||
local val = self:value(ent.value, ent.valtype) |
||||
local next = self.linktab:addr(ent.next) |
||||
return string.format(' {%s, %s, %s},\n', key, val, next) |
||||
end |
||||
|
||||
-- Dumps an inttable array entry. This is almost the same as value() above, |
||||
-- except that nil values have a special value to indicate "empty". |
||||
function Dumper:arrayval(val) |
||||
if val.val then |
||||
return string.format(" %s,\n", self:value(val.val, val.valtype)) |
||||
else |
||||
return " UPB_ARRAY_EMPTYENT,\n" |
||||
end |
||||
end |
||||
|
||||
-- Dumps an initializer for the given strtable/inttable (respectively). Its |
||||
-- entries must have previously been added to the linktable. |
||||
function Dumper:strtable(t) |
||||
-- UPB_STRTABLE_INIT(count, mask, type, size_lg2, entries) |
||||
return string.format( |
||||
"UPB_STRTABLE_INIT(%d, %d, %d, %d, %s)", |
||||
t.count, t.mask, t.type, t.size_lg2, self.linktab:addr(t.entries[1].ptr)) |
||||
end |
||||
|
||||
function Dumper:inttable(t) |
||||
local lt = assert(self.linktab) |
||||
-- UPB_INTTABLE_INIT(count, mask, type, size_lg2, ent, a, asize, acount) |
||||
local entries = "NULL" |
||||
if #t.entries > 0 then |
||||
entries = lt:addr(t.entries[1].ptr) |
||||
end |
||||
return string.format( |
||||
"UPB_INTTABLE_INIT(%d, %d, %d, %d, %s, %s, %d, %d)", |
||||
t.count, t.mask, t.type, t.size_lg2, entries, |
||||
lt:addr(t.array[1].ptr), t.array_size, t.array_count) |
||||
end |
||||
|
||||
-- A visitor for visiting all tables of a def. Used first to count entries |
||||
-- and later to dump them. |
||||
local function gettables(def) |
||||
if def:def_type() == upb.DEF_MSG then |
||||
return {int = upbtable.msgdef_itof(def), str = upbtable.msgdef_ntof(def)} |
||||
elseif def:def_type() == upb.DEF_ENUM then |
||||
return {int = upbtable.enumdef_iton(def), str = upbtable.enumdef_ntoi(def)} |
||||
end |
||||
end |
||||
|
||||
local function emit_file_warning(append) |
||||
append('// This file was generated by upbc (the upb compiler).\n') |
||||
append('// Do not edit -- your changes will be discarded when the file is\n') |
||||
append('// regenerated.\n\n') |
||||
end |
||||
|
||||
--[[ |
||||
|
||||
Top-level, exported dumper functions |
||||
|
||||
--]] |
||||
|
||||
local function dump_defs_c(symtab, basename, append) |
||||
-- Add fielddefs for any msgdefs passed in. |
||||
local fielddefs = {} |
||||
for _, def in ipairs(symtab:getdefs(upb.DEF_MSG)) do |
||||
for field in def:fields() do |
||||
fielddefs[#fielddefs + 1] = field |
||||
end |
||||
end |
||||
|
||||
-- Get a list of all defs and add fielddefs to it. |
||||
local defs = symtab:getdefs(upb.DEF_ANY) |
||||
for _, fielddef in ipairs(fielddefs) do |
||||
defs[#defs + 1] = fielddef |
||||
end |
||||
|
||||
-- Sort all defs by (type, name). |
||||
-- This gives us a linear ordering that we can use to create offsets into |
||||
-- shared arrays like REFTABLES, hash table entries, and arrays. |
||||
table.sort(defs, function(a, b) |
||||
if a:def_type() ~= b:def_type() then |
||||
return a:def_type() < b:def_type() |
||||
else |
||||
return a:full_name() < b:full_name() end |
||||
end |
||||
) |
||||
|
||||
-- Perform pre-pass to build the link table. |
||||
local linktab = LinkTable:new(basename, { |
||||
[upb.DEF_MSG] = "msgs", |
||||
[upb.DEF_FIELD] = "fields", |
||||
[upb.DEF_ENUM] = "enums", |
||||
intentries = "intentries", |
||||
strentries = "strentries", |
||||
arrays = "arrays", |
||||
}) |
||||
for _, def in ipairs(defs) do |
||||
assert(def:is_frozen(), "can only dump frozen defs.") |
||||
linktab:add(def:def_type(), def) |
||||
local tables = gettables(def) |
||||
if tables then |
||||
for _, e in ipairs(tables.str.entries) do |
||||
linktab:add("strentries", e.ptr, e) |
||||
end |
||||
for _, e in ipairs(tables.int.entries) do |
||||
linktab:add("intentries", e.ptr, e) |
||||
end |
||||
for _, e in ipairs(tables.int.array) do |
||||
linktab:add("arrays", e.ptr, e) |
||||
end |
||||
end |
||||
end |
||||
|
||||
-- Emit forward declarations. |
||||
emit_file_warning(append) |
||||
append('#include "upb/def.h"\n\n') |
||||
append("const upb_msgdef %s;\n", linktab:cdecl(upb.DEF_MSG)) |
||||
append("const upb_fielddef %s;\n", linktab:cdecl(upb.DEF_FIELD)) |
||||
append("const upb_enumdef %s;\n", linktab:cdecl(upb.DEF_ENUM)) |
||||
append("const upb_tabent %s;\n", linktab:cdecl("strentries")) |
||||
append("const upb_tabent %s;\n", linktab:cdecl("intentries")) |
||||
append("const upb_value %s;\n", linktab:cdecl("arrays")) |
||||
append("\n") |
||||
|
||||
-- Emit defs. |
||||
local dumper = Dumper:new(linktab) |
||||
|
||||
append("const upb_msgdef %s = {\n", linktab:cdecl(upb.DEF_MSG)) |
||||
for m in linktab:objs(upb.DEF_MSG) do |
||||
local tables = gettables(m) |
||||
-- UPB_MSGDEF_INIT(name, itof, ntof) |
||||
append(' UPB_MSGDEF_INIT("%s", %s, %s, %s),\n', |
||||
m:full_name(), |
||||
dumper:inttable(tables.int), |
||||
dumper:strtable(tables.str), |
||||
m:_selector_count()) |
||||
end |
||||
append("};\n\n") |
||||
|
||||
append("const upb_fielddef %s = {\n", linktab:cdecl(upb.DEF_FIELD)) |
||||
for f in linktab:objs(upb.DEF_FIELD) do |
||||
local subdef = "NULL" |
||||
if f:has_subdef() then |
||||
subdef = string.format("upb_upcast(%s)", linktab:addr(f:subdef())) |
||||
end |
||||
-- UPB_FIELDDEF_INIT(label, type, name, num, msgdef, subdef, |
||||
-- selector_base, default_value) |
||||
append(' UPB_FIELDDEF_INIT(%s, %s, "%s", %d, %s, %s, %d, %s),\n', |
||||
const(f, "label"), const(f, "type"), f:name(), |
||||
f:number(), linktab:addr(f:msgdef()), subdef, |
||||
f:_selector_base(), |
||||
dumper:value(nil) -- TODO |
||||
) |
||||
end |
||||
append("};\n\n") |
||||
|
||||
append("const upb_enumdef %s = {\n", linktab:cdecl(upb.DEF_ENUM)) |
||||
for e in linktab:objs(upb.DEF_ENUM) do |
||||
local tables = gettables(e) |
||||
-- UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval) |
||||
append(' UPB_ENUMDEF_INIT("%s", %s, %s, %d),\n', |
||||
e:full_name(), |
||||
dumper:strtable(tables.str), |
||||
dumper:inttable(tables.int), |
||||
--e:default()) |
||||
0) |
||||
end |
||||
append("};\n\n") |
||||
|
||||
append("const upb_tabent %s = {\n", linktab:cdecl("strentries")) |
||||
for ent in linktab:objs("strentries") do |
||||
append(dumper:tabent(ent)) |
||||
end |
||||
append("};\n\n"); |
||||
|
||||
append("const upb_tabent %s = {\n", linktab:cdecl("intentries")) |
||||
for ent in linktab:objs("intentries") do |
||||
append(dumper:tabent(ent)) |
||||
end |
||||
append("};\n\n"); |
||||
|
||||
append("const upb_value %s = {\n", linktab:cdecl("arrays")) |
||||
for ent in linktab:objs("arrays") do |
||||
append(dumper:arrayval(ent)) |
||||
end |
||||
append("};\n\n"); |
||||
|
||||
return linktab |
||||
end |
||||
|
||||
local function join(...) |
||||
return table.concat({...}, ".") |
||||
end |
||||
|
||||
local function to_cident(...) |
||||
return string.gsub(join(...), "%.", "_") |
||||
end |
||||
|
||||
local function to_preproc(...) |
||||
return string.upper(to_cident(...)) |
||||
end |
||||
|
||||
local function dump_defs_h(symtab, basename, append, linktab) |
||||
local ucase_basename = string.upper(basename) |
||||
emit_file_warning(append) |
||||
append('#ifndef %s_UPB_H_\n', ucase_basename) |
||||
append('#define %s_UPB_H_\n\n', ucase_basename) |
||||
append('#include "upb/def.h"\n\n') |
||||
append('#ifdef __cplusplus\n') |
||||
append('extern "C" {\n') |
||||
append('#endif\n\n') |
||||
|
||||
-- Dump C enums for proto enums. |
||||
append("// Enums\n\n") |
||||
for _, def in ipairs(symtab:getdefs(upb.DEF_ENUM)) do |
||||
local cident = to_cident(def:full_name()) |
||||
append('typedef enum {\n') |
||||
for k, v in def:values() do |
||||
append(' %s = %d,\n', to_preproc(cident, k), v) |
||||
end |
||||
append('} %s;\n\n', cident) |
||||
end |
||||
|
||||
-- Dump macros for referring to specific defs. |
||||
append("// Do not refer to these forward declarations; use the constants\n") |
||||
append("// below.\n") |
||||
append("extern const upb_msgdef %s;\n", linktab:cdecl(upb.DEF_MSG)) |
||||
append("extern const upb_fielddef %s;\n", linktab:cdecl(upb.DEF_FIELD)) |
||||
append("extern const upb_enumdef %s;\n\n", linktab:cdecl(upb.DEF_ENUM)) |
||||
append("// Constants for references to defs.\n") |
||||
append("// We hide these behind macros to decouple users from the\n") |
||||
append("// details of how we have statically defined them (ie. whether\n") |
||||
append("// each def has its own symbol or lives in an array of defs).\n") |
||||
for def in linktab:objs(upb.DEF_MSG) do |
||||
append("#define %s %s\n", to_preproc(def:full_name()), linktab:addr(def)) |
||||
end |
||||
append("\n") |
||||
|
||||
append('#ifdef __cplusplus\n') |
||||
append('}; // extern "C"\n') |
||||
append('#endif\n\n') |
||||
append('#endif // %s_UPB_H_\n', ucase_basename) |
||||
end |
||||
|
||||
function export.dump_defs(symtab, basename, append_h, append_c) |
||||
local linktab = dump_defs_c(symtab, basename, append_c) |
||||
dump_defs_h(symtab, basename, append_h, linktab) |
||||
end |
||||
|
||||
return export |
@ -0,0 +1,78 @@ |
||||
--[[ |
||||
|
||||
upb - a minimalist implementation of protocol buffers. |
||||
|
||||
Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
Author: Josh Haberman <jhaberman@gmail.com> |
||||
|
||||
Tests for dump_cinit.lua. Runs first in a mode that generates |
||||
some C code for an extension. The C code is compiled and then |
||||
loaded by a second invocation of the test which checks that the |
||||
generated defs are as expected. |
||||
|
||||
--]] |
||||
|
||||
local dump_cinit = require "dump_cinit" |
||||
local upb = require "upb" |
||||
|
||||
-- Once APIs for loading descriptors are fleshed out, we should replace this |
||||
-- with a descriptor for a meaty protobuf like descriptor.proto. |
||||
local symtab = upb.SymbolTable{ |
||||
upb.EnumDef{full_name = "MyEnum", |
||||
values = { |
||||
{"FOO", 1}, |
||||
{"BAR", 77} |
||||
} |
||||
}, |
||||
upb.MessageDef{full_name = "MyMessage", |
||||
fields = { |
||||
upb.FieldDef{label = upb.LABEL_REQUIRED, name = "field1", number = 1, |
||||
type = upb.TYPE_INT32}, |
||||
upb.FieldDef{label = upb.LABEL_REPEATED, name = "field2", number = 2, |
||||
type = upb.TYPE_ENUM, subdef_name = ".MyEnum"}, |
||||
upb.FieldDef{name = "field3", number = 3, type = upb.TYPE_MESSAGE, |
||||
subdef_name = ".MyMessage"} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if arg[1] == "generate" then |
||||
local f = assert(io.open(arg[2], "w")) |
||||
local f_h = assert(io.open(arg[2] .. ".h", "w")) |
||||
local appendc = dump_cinit.file_appender(f) |
||||
local appendh = dump_cinit.file_appender(f_h) |
||||
f:write('#include "lua.h"\n') |
||||
f:write('#define ELEMENTS(array) (sizeof(array)/sizeof(*array))\n') |
||||
f:write('#include "bindings/lua/upb.h"\n') |
||||
dump_cinit.dump_defs(symtab, "test", appendh, appendc) |
||||
f:write([[int luaopen_staticdefs(lua_State *L) { |
||||
lua_newtable(L); |
||||
for (int i = 0; i < ELEMENTS(test_msgs); i++) { |
||||
lupb_def_pushnewrapper(L, upb_upcast(&test_msgs[i]), NULL); |
||||
lua_rawseti(L, -2, i + 1); |
||||
} |
||||
for (int i = 0; i < ELEMENTS(test_enums); i++) { |
||||
lupb_def_pushnewrapper(L, upb_upcast(&test_enums[i]), NULL); |
||||
lua_rawseti(L, -2, ELEMENTS(test_msgs) + i + 1); |
||||
} |
||||
return 1; |
||||
}]]) |
||||
f_h:close() |
||||
f:close() |
||||
elseif arg[1] == "test" then |
||||
local staticdefs = require "staticdefs" |
||||
|
||||
local msg = assert(staticdefs[1]) |
||||
local enum = assert(staticdefs[2]) |
||||
local f2 = assert(msg:field("field2")) |
||||
assert(msg:def_type() == upb.DEF_MSG) |
||||
assert(msg:full_name() == "MyMessage") |
||||
assert(enum:def_type() == upb.DEF_ENUM) |
||||
assert(enum:full_name() == "MyEnum") |
||||
assert(enum:value("FOO") == 1) |
||||
assert(f2:name() == "field2") |
||||
assert(f2:msgdef() == msg) |
||||
assert(f2:subdef() == enum) |
||||
else |
||||
error("Unknown operation " .. arg[1]) |
||||
end |
@ -1,197 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2009 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* upbc is the upb compiler, which at the moment simply takes a |
||||
* protocol descriptor and outputs a header file containing the |
||||
* names and types of the fields. |
||||
*/ |
||||
|
||||
#include <ctype.h> |
||||
#include <inttypes.h> |
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
#include "upb/bytestream.h" |
||||
#include "upb/def.h" |
||||
#include "upb/msg.h" |
||||
#include "upb/pb/glue.h" |
||||
|
||||
/* These are in-place string transformations that do not change the length of
|
||||
* the string (and thus never need to re-allocate). */ |
||||
|
||||
// Convert to C identifier: foo.bar.Baz -> foo_bar_Baz.
|
||||
static void to_cident(char *str) { |
||||
for (; *str; ++str) { |
||||
if(*str == '.' || *str == '/') *str = '_'; |
||||
} |
||||
} |
||||
|
||||
// Convert to C proprocessor identifier: foo.bar.Baz -> FOO_BAR_BAZ.
|
||||
static void to_preproc(char *str) { |
||||
to_cident(str); |
||||
for (; *str; ++str) *str = toupper(*str); |
||||
} |
||||
|
||||
/* The _const.h file defines the constants (enums) defined in the .proto
|
||||
* file. */ |
||||
static void write_const_h(const upb_def *defs[], int num_entries, |
||||
char *outfile_name, FILE *stream) { |
||||
/* Header file prologue. */ |
||||
char *include_guard_name = strdup(outfile_name); |
||||
to_preproc(include_guard_name); |
||||
|
||||
fputs("/* This file was generated by upbc (the upb compiler). " |
||||
"Do not edit. */\n\n", stream), |
||||
fprintf(stream, "#ifndef %s\n", include_guard_name); |
||||
fprintf(stream, "#define %s\n\n", include_guard_name); |
||||
fputs("#ifdef __cplusplus\n", stream); |
||||
fputs("extern \"C\" {\n", stream); |
||||
fputs("#endif\n\n", stream); |
||||
|
||||
/* Enums. */ |
||||
fprintf(stream, "/* Enums. */\n\n"); |
||||
for(int i = 0; i < num_entries; i++) { /* Foreach enum */ |
||||
if(defs[i]->type != UPB_DEF_ENUM) continue; |
||||
const upb_enumdef *enumdef = upb_downcast_enumdef_const(defs[i]); |
||||
char *enum_name = strdup(upb_def_fullname(UPB_UPCAST(enumdef))); |
||||
char *enum_val_prefix = strdup(enum_name); |
||||
to_cident(enum_name); |
||||
to_preproc(enum_val_prefix); |
||||
|
||||
fprintf(stream, "typedef enum %s {\n", enum_name); |
||||
bool first = true; |
||||
/* Foreach enum value. */ |
||||
upb_enum_iter iter; |
||||
for (upb_enum_begin(&iter, enumdef); |
||||
!upb_enum_done(&iter); |
||||
upb_enum_next(&iter)) { |
||||
char *value_name = strdup(upb_enum_iter_name(&iter)); |
||||
uint32_t value = upb_enum_iter_number(&iter); |
||||
to_preproc(value_name); |
||||
/* " GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_UINT32 = 13," */ |
||||
if (!first) fputs(",\n", stream); |
||||
first = false; |
||||
fprintf(stream, " %s_%s = %" PRIu32, enum_val_prefix, value_name, value); |
||||
free(value_name); |
||||
} |
||||
fprintf(stream, "\n} %s;\n\n", enum_name); |
||||
free(enum_name); |
||||
free(enum_val_prefix); |
||||
} |
||||
|
||||
/* Constants for field names and numbers. */ |
||||
fprintf(stream, "/* Constants for field names and numbers. */\n\n"); |
||||
for(int i = 0; i < num_entries; i++) { /* Foreach enum */ |
||||
const upb_msgdef *m = upb_dyncast_msgdef_const(defs[i]); |
||||
if(!m) continue; |
||||
char *msg_name = strdup(upb_def_fullname(UPB_UPCAST(m))); |
||||
char *msg_val_prefix = strdup(msg_name); |
||||
to_preproc(msg_val_prefix); |
||||
upb_msg_iter i; |
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { |
||||
upb_fielddef *f = upb_msg_iter_field(&i); |
||||
char *preproc_field_name = strdup(upb_fielddef_name(f)); |
||||
to_preproc(preproc_field_name); |
||||
fprintf(stream, "#define %s_%s__FIELDNUM %d\n", |
||||
msg_val_prefix, preproc_field_name, upb_fielddef_number(f)); |
||||
fprintf(stream, "#define %s_%s__FIELDNAME \"%s\"\n", |
||||
msg_val_prefix, preproc_field_name, upb_fielddef_name(f)); |
||||
fprintf(stream, "#define %s_%s__FIELDTYPE %d\n\n", |
||||
msg_val_prefix, preproc_field_name, upb_fielddef_type(f)); |
||||
free(preproc_field_name); |
||||
} |
||||
free(msg_val_prefix); |
||||
free(msg_name); |
||||
} |
||||
|
||||
/* Epilogue. */ |
||||
fputs("#ifdef __cplusplus\n", stream); |
||||
fputs("} /* extern \"C\" */\n", stream); |
||||
fputs("#endif\n\n", stream); |
||||
fprintf(stream, "#endif /* %s */\n", include_guard_name); |
||||
free(include_guard_name); |
||||
} |
||||
|
||||
const char usage[] = |
||||
"upbc -- upb compiler.\n" |
||||
"upb v0.1 http://blog.reverberate.org/upb/\n" |
||||
"\n" |
||||
"Usage: upbc [options] descriptor-file\n" |
||||
"\n" |
||||
" -o OUTFILE-BASE Write to OUTFILE-BASE.h and OUTFILE-BASE.c instead\n" |
||||
" of using the input file as a basename.\n" |
||||
; |
||||
|
||||
void usage_err(const char *err) { |
||||
fprintf(stderr, "upbc: %s\n\n", err); |
||||
fputs(usage, stderr); |
||||
exit(1); |
||||
} |
||||
|
||||
void error(const char *err, ...) { |
||||
va_list args; |
||||
va_start(args, err); |
||||
fprintf(stderr, "upbc: "); |
||||
vfprintf(stderr, err, args); |
||||
va_end(args); |
||||
exit(1); |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
/* Parse arguments. */ |
||||
char *outfile_base = NULL, *input_file = NULL; |
||||
for(int i = 1; i < argc; i++) { |
||||
if(strcmp(argv[i], "-o") == 0) { |
||||
if(++i == argc) |
||||
usage_err("-o must be followed by a FILE-BASE."); |
||||
else if(outfile_base) |
||||
usage_err("-o was specified multiple times."); |
||||
outfile_base = argv[i]; |
||||
} else { |
||||
if(input_file) |
||||
usage_err("You can only specify one input file."); |
||||
input_file = argv[i]; |
||||
} |
||||
} |
||||
if(!input_file) usage_err("You must specify an input file."); |
||||
if(!outfile_base) outfile_base = input_file; |
||||
|
||||
// Read and parse input file.
|
||||
size_t len; |
||||
char *descriptor = upb_readfile(input_file, &len); |
||||
if(!descriptor) |
||||
error("Couldn't read input file."); |
||||
|
||||
// TODO: make upb_parsedesc use a separate symtab, so we can use it here when
|
||||
// importing descriptor.proto.
|
||||
upb_symtab *s = upb_symtab_new(); |
||||
upb_status status = UPB_STATUS_INIT; |
||||
upb_load_descriptor_into_symtab(s, descriptor, len, &status); |
||||
if(!upb_ok(&status)) { |
||||
error("Failed to parse input file descriptor: %s\n", |
||||
upb_status_getstr(&status)); |
||||
} |
||||
upb_status_uninit(&status); |
||||
|
||||
/* Emit output files. */ |
||||
char h_const_filename[256]; |
||||
const int maxsize = sizeof(h_const_filename); |
||||
if(snprintf(h_const_filename, maxsize, "%s_const.h", outfile_base) >= maxsize) |
||||
error("File base too long.\n"); |
||||
|
||||
FILE *h_const_file = fopen(h_const_filename, "w"); |
||||
if(!h_const_file) error("Failed to open _const.h output file\n"); |
||||
|
||||
int symcount; |
||||
const upb_def **defs = upb_symtab_getdefs(s, &symcount, UPB_DEF_ANY, &defs); |
||||
write_const_h(defs, symcount, h_const_filename, h_const_file); |
||||
for (int i = 0; i < symcount; i++) upb_def_unref(defs[i], &defs); |
||||
free(defs); |
||||
free(descriptor); |
||||
upb_symtab_unref(s); |
||||
fclose(h_const_file); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,50 @@ |
||||
--[[ |
||||
|
||||
upb - a minimalist implementation of protocol buffers. |
||||
|
||||
Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
Author: Josh Haberman <jhaberman@gmail.com> |
||||
|
||||
The upb compiler. Unlike the proto2 compiler, this does |
||||
not output any parsing code or generated classes or anything |
||||
specific to the protobuf binary format at all. At the moment |
||||
it only dumps C initializers for upb_defs, so that a .proto |
||||
file can be represented in a .o file. |
||||
|
||||
--]] |
||||
|
||||
local dump_cinit = require "dump_cinit" |
||||
local upb = require "upb" |
||||
|
||||
local src = arg[1] |
||||
local outbase = arg[2] |
||||
local basename = arg[3] |
||||
local hfilename = outbase .. ".upb.h" |
||||
local cfilename = outbase .. ".upb.c" |
||||
|
||||
if os.getenv("UPBC_VERBOSE") then |
||||
print("upbc:") |
||||
print(string.format(" source file=%s", src)) |
||||
print(string.format(" output file base=%s", outbase)) |
||||
print(string.format(" hfilename=%s", hfilename)) |
||||
print(string.format(" cfilename=%s", cfilename)) |
||||
end |
||||
|
||||
-- Open input/output files. |
||||
local f = assert(io.open(src, "r"), "couldn't open input file " .. src) |
||||
local descriptor = f:read("*all") |
||||
local symtab = upb.SymbolTable() |
||||
symtab:load_descriptor(descriptor) |
||||
|
||||
os.execute(string.format("mkdir -p `dirname %s`", outbase)) |
||||
local hfile = assert(io.open(hfilename, "w"), "couldn't open " .. hfilename) |
||||
local cfile = assert(io.open(cfilename, "w"), "couldn't open " .. cfilename) |
||||
|
||||
local happend = dump_cinit.file_appender(hfile) |
||||
local cappend = dump_cinit.file_appender(cfile) |
||||
|
||||
-- Dump defs |
||||
dump_cinit.dump_defs(symtab, basename, happend, cappend) |
||||
|
||||
hfile:close() |
||||
cfile:close() |
@ -0,0 +1,483 @@ |
||||
// This file was generated by upbc (the upb compiler).
|
||||
// Do not edit -- your changes will be discarded when the file is
|
||||
// regenerated.
|
||||
|
||||
#include "upb/def.h" |
||||
|
||||
const upb_msgdef google_protobuf_msgs[20]; |
||||
const upb_fielddef google_protobuf_fields[73]; |
||||
const upb_enumdef google_protobuf_enums[4]; |
||||
const upb_tabent google_protobuf_strentries[192]; |
||||
const upb_tabent google_protobuf_intentries[66]; |
||||
const upb_value google_protobuf_arrays[97]; |
||||
|
||||
const upb_msgdef google_protobuf_msgs[20] = { |
||||
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[0], &google_protobuf_arrays[0], 6, 5), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[0]), 31), |
||||
UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[6], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[16]), 2), |
||||
UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[10], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[20]), 11), |
||||
UPB_MSGDEF_INIT("google.protobuf.EnumOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[4], &google_protobuf_arrays[14], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[24]), 5), |
||||
UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[15], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[28]), 7), |
||||
UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[6], &google_protobuf_arrays[19], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[32]), 5), |
||||
UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[8], &google_protobuf_arrays[20], 6, 5), UPB_STRTABLE_INIT(8, 15, 9, 4, &google_protobuf_strentries[36]), 18), |
||||
UPB_MSGDEF_INIT("google.protobuf.FieldOptions", UPB_INTTABLE_INIT(2, 3, 9, 2, &google_protobuf_intentries[12], &google_protobuf_arrays[26], 5, 3), UPB_STRTABLE_INIT(5, 7, 9, 3, &google_protobuf_strentries[52]), 11), |
||||
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", UPB_INTTABLE_INIT(4, 7, 9, 3, &google_protobuf_intentries[16], &google_protobuf_arrays[31], 6, 5), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[60]), 37), |
||||
UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[37], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[76]), 5), |
||||
UPB_MSGDEF_INIT("google.protobuf.FileOptions", UPB_INTTABLE_INIT(8, 15, 9, 4, &google_protobuf_intentries[24], &google_protobuf_arrays[40], 6, 1), UPB_STRTABLE_INIT(9, 15, 9, 4, &google_protobuf_strentries[80]), 17), |
||||
UPB_MSGDEF_INIT("google.protobuf.MessageOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[40], &google_protobuf_arrays[46], 4, 2), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[96]), 7), |
||||
UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[50], 5, 4), UPB_STRTABLE_INIT(4, 7, 9, 3, &google_protobuf_strentries[100]), 12), |
||||
UPB_MSGDEF_INIT("google.protobuf.MethodOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[42], &google_protobuf_arrays[55], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[108]), 5), |
||||
UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[56], 4, 3), UPB_STRTABLE_INIT(3, 3, 9, 2, &google_protobuf_strentries[112]), 11), |
||||
UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", UPB_INTTABLE_INIT(1, 1, 9, 1, &google_protobuf_intentries[44], &google_protobuf_arrays[60], 1, 0), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[116]), 5), |
||||
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[61], 3, 1), UPB_STRTABLE_INIT(1, 3, 9, 2, &google_protobuf_strentries[120]), 5), |
||||
UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[64], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[124]), 6), |
||||
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", UPB_INTTABLE_INIT(3, 3, 9, 2, &google_protobuf_intentries[46], &google_protobuf_arrays[68], 6, 4), UPB_STRTABLE_INIT(7, 15, 9, 4, &google_protobuf_strentries[128]), 17), |
||||
UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", UPB_INTTABLE_INIT(0, 0, 9, 0, NULL, &google_protobuf_arrays[74], 4, 2), UPB_STRTABLE_INIT(2, 3, 9, 2, &google_protobuf_strentries[144]), 4), |
||||
}; |
||||
|
||||
const upb_fielddef google_protobuf_fields[73] = { |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 10, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "ctype", 1, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_enums[2]), 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "default_value", 7, &google_protobuf_msgs[6], NULL, 15, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, "dependency", 3, &google_protobuf_msgs[8], NULL, 8, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "deprecated", 3, &google_protobuf_msgs[7], NULL, 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, "double_value", 6, &google_protobuf_msgs[18], NULL, 13, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "end", 2, &google_protobuf_msgs[1], NULL, 1, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "enum_type", 4, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[2]), 15, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "enum_type", 5, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[2]), 18, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "extendee", 2, &google_protobuf_msgs[6], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "extension", 7, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[6]), 34, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "extension", 6, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 25, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "extension_range", 5, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[1]), 20, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "field", 2, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[6]), 5, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "file", 1, &google_protobuf_msgs[9], upb_upcast(&google_protobuf_msgs[8]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 5, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "input_type", 2, &google_protobuf_msgs[12], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, "is_extension", 2, &google_protobuf_msgs[19], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 6, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 4, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 16, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 12, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "java_package", 1, &google_protobuf_msgs[10], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "label", 4, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[0]), 7, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "location", 1, &google_protobuf_msgs[16], upb_upcast(&google_protobuf_msgs[17]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "message_type", 4, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[0]), 13, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "method", 2, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[12]), 5, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[12], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[4], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[14], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[2], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[6], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "name", 2, &google_protobuf_msgs[18], upb_upcast(&google_protobuf_msgs[19]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[0], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "name", 1, &google_protobuf_msgs[8], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, "name_part", 1, &google_protobuf_msgs[19], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 9, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "nested_type", 3, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[0]), 10, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 1, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "number", 2, &google_protobuf_msgs[4], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "number", 3, &google_protobuf_msgs[6], NULL, 6, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "optimize_for", 9, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_enums[3]), 15, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 4, &google_protobuf_msgs[12], upb_upcast(&google_protobuf_msgs[13]), 9, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 3, &google_protobuf_msgs[14], upb_upcast(&google_protobuf_msgs[15]), 8, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 8, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[10]), 21, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 3, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[3]), 8, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 7, &google_protobuf_msgs[0], upb_upcast(&google_protobuf_msgs[11]), 28, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 8, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_msgs[7]), 9, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "options", 3, &google_protobuf_msgs[4], upb_upcast(&google_protobuf_msgs[5]), 4, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "output_type", 3, &google_protobuf_msgs[12], NULL, 6, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "package", 2, &google_protobuf_msgs[8], NULL, 3, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "packed", 2, &google_protobuf_msgs[7], NULL, 1, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, "path", 1, &google_protobuf_msgs[17], NULL, 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 8, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 5, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "service", 6, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[14]), 29, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, "source_code_info", 9, &google_protobuf_msgs[8], upb_upcast(&google_protobuf_msgs[16]), 24, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, "span", 2, &google_protobuf_msgs[17], NULL, 5, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, "start", 1, &google_protobuf_msgs[1], NULL, 0, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, "string_value", 7, &google_protobuf_msgs[18], NULL, 14, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, "type", 5, &google_protobuf_msgs[6], upb_upcast(&google_protobuf_enums[1]), 8, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, "type_name", 6, &google_protobuf_msgs[6], NULL, 12, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[15], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[11], upb_upcast(&google_protobuf_msgs[18]), 4, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[13], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[10], upb_upcast(&google_protobuf_msgs[18]), 9, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[7], upb_upcast(&google_protobuf_msgs[18]), 8, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[3], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "uninterpreted_option", 999, &google_protobuf_msgs[5], upb_upcast(&google_protobuf_msgs[18]), 2, UPB_VALUE_INIT_NONE), |
||||
UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, "value", 2, &google_protobuf_msgs[2], upb_upcast(&google_protobuf_msgs[4]), 5, UPB_VALUE_INIT_NONE), |
||||
}; |
||||
|
||||
const upb_enumdef google_protobuf_enums[4] = { |
||||
UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, 1, 2, &google_protobuf_strentries[148]), UPB_INTTABLE_INIT(0, 0, 8, 0, NULL, &google_protobuf_arrays[78], 4, 3), 0), |
||||
UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, 1, 5, &google_protobuf_strentries[152]), UPB_INTTABLE_INIT(12, 15, 8, 4, &google_protobuf_intentries[50], &google_protobuf_arrays[82], 7, 6), 0), |
||||
UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, 1, 2, &google_protobuf_strentries[184]), UPB_INTTABLE_INIT(0, 0, 8, 0, NULL, &google_protobuf_arrays[89], 4, 3), 0), |
||||
UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, 1, 2, &google_protobuf_strentries[188]), UPB_INTTABLE_INIT(0, 0, 8, 0, NULL, &google_protobuf_arrays[93], 4, 3), 0), |
||||
}; |
||||
|
||||
const upb_tabent google_protobuf_strentries[192] = { |
||||
{UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("field"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]), NULL}, |
||||
{UPB_TABKEY_STR("extension_range"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[14]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("nested_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[40]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, |
||||
{UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[8]), &google_protobuf_strentries[14]}, |
||||
{UPB_TABKEY_STR("start"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[61]), NULL}, |
||||
{UPB_TABKEY_STR("end"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[7]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[72]), NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), &google_protobuf_strentries[22]}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[42]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), &google_protobuf_strentries[30]}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("label"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[25]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[34]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("number"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[43]), &google_protobuf_strentries[49]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("type_name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL}, |
||||
{UPB_TABKEY_STR("extendee"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[11]), NULL}, |
||||
{UPB_TABKEY_STR("type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[63]), &google_protobuf_strentries[48]}, |
||||
{UPB_TABKEY_STR("default_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, |
||||
{UPB_TABKEY_STR("experimental_map_key"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), &google_protobuf_strentries[58]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("ctype"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[2]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("deprecated"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[5]), NULL}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL}, |
||||
{UPB_TABKEY_STR("packed"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[54]), NULL}, |
||||
{UPB_TABKEY_STR("extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), NULL}, |
||||
{UPB_TABKEY_STR("service"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("source_code_info"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("dependency"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[4]), NULL}, |
||||
{UPB_TABKEY_STR("message_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[28]), NULL}, |
||||
{UPB_TABKEY_STR("package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[53]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL}, |
||||
{UPB_TABKEY_STR("enum_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[9]), &google_protobuf_strentries[74]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("file"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[16]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("cc_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("java_multiple_files"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("java_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), &google_protobuf_strentries[94]}, |
||||
{UPB_TABKEY_STR("java_generate_equals_and_hash"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("java_package"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[24]), NULL}, |
||||
{UPB_TABKEY_STR("optimize_for"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL}, |
||||
{UPB_TABKEY_STR("py_generic_services"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL}, |
||||
{UPB_TABKEY_STR("java_outer_classname"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL}, |
||||
{UPB_TABKEY_STR("message_set_wire_format"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[27]), &google_protobuf_strentries[98]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, |
||||
{UPB_TABKEY_STR("no_standard_descriptor_accessor"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[41]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), NULL}, |
||||
{UPB_TABKEY_STR("input_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[18]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("output_type"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[52]), NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), NULL}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("options"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), &google_protobuf_strentries[114]}, |
||||
{UPB_TABKEY_STR("method"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[29]), NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[32]), &google_protobuf_strentries[113]}, |
||||
{UPB_TABKEY_STR("uninterpreted_option"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("location"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[26]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("span"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[60]), NULL}, |
||||
{UPB_TABKEY_STR("path"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[55]), &google_protobuf_strentries[126]}, |
||||
{UPB_TABKEY_STR("double_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("name"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("negative_int_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[39]), NULL}, |
||||
{UPB_TABKEY_STR("aggregate_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("positive_int_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[56]), NULL}, |
||||
{UPB_TABKEY_STR("identifier_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[17]), NULL}, |
||||
{UPB_TABKEY_STR("string_value"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), &google_protobuf_strentries[142]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("is_extension"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[19]), NULL}, |
||||
{UPB_TABKEY_STR("name_part"), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[38]), NULL}, |
||||
{UPB_TABKEY_STR("LABEL_REQUIRED"), UPB_VALUE_INIT_INT32(2), &google_protobuf_strentries[150]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("LABEL_REPEATED"), UPB_VALUE_INIT_INT32(3), NULL}, |
||||
{UPB_TABKEY_STR("LABEL_OPTIONAL"), UPB_VALUE_INIT_INT32(1), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_FIXED64"), UPB_VALUE_INIT_INT32(6), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_STRING"), UPB_VALUE_INIT_INT32(9), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_FLOAT"), UPB_VALUE_INIT_INT32(2), &google_protobuf_strentries[181]}, |
||||
{UPB_TABKEY_STR("TYPE_DOUBLE"), UPB_VALUE_INIT_INT32(1), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_INT32"), UPB_VALUE_INIT_INT32(5), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_SFIXED32"), UPB_VALUE_INIT_INT32(15), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_FIXED32"), UPB_VALUE_INIT_INT32(7), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_MESSAGE"), UPB_VALUE_INIT_INT32(11), &google_protobuf_strentries[182]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_INT64"), UPB_VALUE_INIT_INT32(3), &google_protobuf_strentries[179]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_ENUM"), UPB_VALUE_INIT_INT32(14), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_UINT32"), UPB_VALUE_INIT_INT32(13), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_UINT64"), UPB_VALUE_INIT_INT32(4), &google_protobuf_strentries[178]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("TYPE_SFIXED64"), UPB_VALUE_INIT_INT32(16), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_BYTES"), UPB_VALUE_INIT_INT32(12), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_SINT64"), UPB_VALUE_INIT_INT32(18), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_BOOL"), UPB_VALUE_INIT_INT32(8), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_GROUP"), UPB_VALUE_INIT_INT32(10), NULL}, |
||||
{UPB_TABKEY_STR("TYPE_SINT32"), UPB_VALUE_INIT_INT32(17), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("CORD"), UPB_VALUE_INIT_INT32(1), NULL}, |
||||
{UPB_TABKEY_STR("STRING"), UPB_VALUE_INIT_INT32(0), &google_protobuf_strentries[185]}, |
||||
{UPB_TABKEY_STR("STRING_PIECE"), UPB_VALUE_INIT_INT32(2), NULL}, |
||||
{UPB_TABKEY_STR("CODE_SIZE"), UPB_VALUE_INIT_INT32(2), NULL}, |
||||
{UPB_TABKEY_STR("SPEED"), UPB_VALUE_INIT_INT32(1), &google_protobuf_strentries[191]}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_STR("LITE_RUNTIME"), UPB_VALUE_INIT_INT32(3), NULL}, |
||||
}; |
||||
|
||||
const upb_tabent google_protobuf_intentries[66] = { |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[13]), NULL}, |
||||
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[49]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[70]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[71]), NULL}, |
||||
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[50]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[64]), NULL}, |
||||
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[3]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[10]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[69]), NULL}, |
||||
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[47]), NULL}, |
||||
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[59]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[58]), NULL}, |
||||
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[12]), NULL}, |
||||
{UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[1]), NULL}, |
||||
{UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[21]), NULL}, |
||||
{UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[57]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(20), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[20]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[68]), NULL}, |
||||
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[23]), NULL}, |
||||
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[44]), NULL}, |
||||
{UPB_TABKEY_NUM(10), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[22]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[66]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[67]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(999), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[65]), NULL}, |
||||
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[0]), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(6), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[6]), NULL}, |
||||
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[62]), NULL}, |
||||
{UPB_TABKEY_NUM(16), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED64"), NULL}, |
||||
{UPB_TABKEY_NUM(17), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT32"), NULL}, |
||||
{UPB_TABKEY_NUM(18), UPB_VALUE_INIT_CONSTPTR("TYPE_SINT64"), NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NONE, UPB_VALUE_INIT_NONE, NULL}, |
||||
{UPB_TABKEY_NUM(7), UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED32"), NULL}, |
||||
{UPB_TABKEY_NUM(8), UPB_VALUE_INIT_CONSTPTR("TYPE_BOOL"), NULL}, |
||||
{UPB_TABKEY_NUM(9), UPB_VALUE_INIT_CONSTPTR("TYPE_STRING"), NULL}, |
||||
{UPB_TABKEY_NUM(10), UPB_VALUE_INIT_CONSTPTR("TYPE_GROUP"), NULL}, |
||||
{UPB_TABKEY_NUM(11), UPB_VALUE_INIT_CONSTPTR("TYPE_MESSAGE"), NULL}, |
||||
{UPB_TABKEY_NUM(12), UPB_VALUE_INIT_CONSTPTR("TYPE_BYTES"), NULL}, |
||||
{UPB_TABKEY_NUM(13), UPB_VALUE_INIT_CONSTPTR("TYPE_UINT32"), NULL}, |
||||
{UPB_TABKEY_NUM(14), UPB_VALUE_INIT_CONSTPTR("TYPE_ENUM"), NULL}, |
||||
{UPB_TABKEY_NUM(15), UPB_VALUE_INIT_CONSTPTR("TYPE_SFIXED32"), NULL}, |
||||
}; |
||||
|
||||
const upb_value google_protobuf_arrays[97] = { |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[36]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[15]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[40]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[8]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[14]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[61]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[7]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[33]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[72]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[48]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[31]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[42]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[51]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[34]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[11]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[43]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[25]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[63]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[2]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[54]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[5]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[37]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[53]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[4]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[28]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[9]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[16]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[24]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[27]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[41]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[30]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[18]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[52]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[45]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[32]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[29]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[46]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[26]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[55]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[60]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[35]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[17]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[56]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[39]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[38]), |
||||
UPB_VALUE_INIT_CONSTPTR(&google_protobuf_fields[19]), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR("LABEL_OPTIONAL"), |
||||
UPB_VALUE_INIT_CONSTPTR("LABEL_REQUIRED"), |
||||
UPB_VALUE_INIT_CONSTPTR("LABEL_REPEATED"), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR("TYPE_DOUBLE"), |
||||
UPB_VALUE_INIT_CONSTPTR("TYPE_FLOAT"), |
||||
UPB_VALUE_INIT_CONSTPTR("TYPE_INT64"), |
||||
UPB_VALUE_INIT_CONSTPTR("TYPE_UINT64"), |
||||
UPB_VALUE_INIT_CONSTPTR("TYPE_INT32"), |
||||
UPB_VALUE_INIT_CONSTPTR("TYPE_FIXED64"), |
||||
UPB_VALUE_INIT_CONSTPTR("STRING"), |
||||
UPB_VALUE_INIT_CONSTPTR("CORD"), |
||||
UPB_VALUE_INIT_CONSTPTR("STRING_PIECE"), |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_ARRAY_EMPTYENT, |
||||
UPB_VALUE_INIT_CONSTPTR("SPEED"), |
||||
UPB_VALUE_INIT_CONSTPTR("CODE_SIZE"), |
||||
UPB_VALUE_INIT_CONSTPTR("LITE_RUNTIME"), |
||||
}; |
||||
|
@ -0,0 +1,90 @@ |
||||
// This file was generated by upbc (the upb compiler).
|
||||
// Do not edit -- your changes will be discarded when the file is
|
||||
// regenerated.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_UPB_H_ |
||||
#define GOOGLE_PROTOBUF_UPB_H_ |
||||
|
||||
#include "upb/def.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
// Enums
|
||||
|
||||
typedef enum { |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_FIXED64 = 6, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_STRING = 9, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_FLOAT = 2, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_DOUBLE = 1, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_INT32 = 5, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SFIXED32 = 15, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_FIXED32 = 7, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_MESSAGE = 11, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_INT64 = 3, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_ENUM = 14, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_UINT32 = 13, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_UINT64 = 4, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SFIXED64 = 16, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_BYTES = 12, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SINT64 = 18, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_BOOL = 8, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_GROUP = 10, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SINT32 = 17, |
||||
} google_protobuf_FieldDescriptorProto_Type; |
||||
|
||||
typedef enum { |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_LABEL_REQUIRED = 2, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_LABEL_REPEATED = 3, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_LABEL_OPTIONAL = 1, |
||||
} google_protobuf_FieldDescriptorProto_Label; |
||||
|
||||
typedef enum { |
||||
GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_CORD = 1, |
||||
GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_STRING = 0, |
||||
GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_STRING_PIECE = 2, |
||||
} google_protobuf_FieldOptions_CType; |
||||
|
||||
typedef enum { |
||||
GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZEMODE_CODE_SIZE = 2, |
||||
GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZEMODE_SPEED = 1, |
||||
GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZEMODE_LITE_RUNTIME = 3, |
||||
} google_protobuf_FileOptions_OptimizeMode; |
||||
|
||||
// Do not refer to these forward declarations; use the constants
|
||||
// below.
|
||||
extern const upb_msgdef google_protobuf_msgs[20]; |
||||
extern const upb_fielddef google_protobuf_fields[73]; |
||||
extern const upb_enumdef google_protobuf_enums[4]; |
||||
|
||||
// Constants for references to defs.
|
||||
// We hide these behind macros to decouple users from the
|
||||
// details of how we have statically defined them (ie. whether
|
||||
// each def has its own symbol or lives in an array of defs).
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO &google_protobuf_msgs[0] |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE &google_protobuf_msgs[1] |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO &google_protobuf_msgs[2] |
||||
#define GOOGLE_PROTOBUF_ENUMOPTIONS &google_protobuf_msgs[3] |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO &google_protobuf_msgs[4] |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS &google_protobuf_msgs[5] |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO &google_protobuf_msgs[6] |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS &google_protobuf_msgs[7] |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO &google_protobuf_msgs[8] |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET &google_protobuf_msgs[9] |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS &google_protobuf_msgs[10] |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS &google_protobuf_msgs[11] |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO &google_protobuf_msgs[12] |
||||
#define GOOGLE_PROTOBUF_METHODOPTIONS &google_protobuf_msgs[13] |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO &google_protobuf_msgs[14] |
||||
#define GOOGLE_PROTOBUF_SERVICEOPTIONS &google_protobuf_msgs[15] |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO &google_protobuf_msgs[16] |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION &google_protobuf_msgs[17] |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION &google_protobuf_msgs[18] |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART &google_protobuf_msgs[19] |
||||
|
||||
#ifdef __cplusplus |
||||
}; // extern "C"
|
||||
#endif |
||||
|
||||
#endif // GOOGLE_PROTOBUF_UPB_H_
|
@ -1,349 +0,0 @@ |
||||
/* This file was generated by upbc (the upb compiler). Do not edit. */ |
||||
|
||||
#ifndef UPB_DESCRIPTOR_CONST_H |
||||
#define UPB_DESCRIPTOR_CONST_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* Enums. */ |
||||
|
||||
typedef enum google_protobuf_FieldDescriptorProto_Type { |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_FIXED64 = 6, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_STRING = 9, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_FLOAT = 2, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_DOUBLE = 1, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_INT32 = 5, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SFIXED32 = 15, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_FIXED32 = 7, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_MESSAGE = 11, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_INT64 = 3, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_ENUM = 14, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_UINT32 = 13, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_UINT64 = 4, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SFIXED64 = 16, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_BYTES = 12, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SINT64 = 18, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_BOOL = 8, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_GROUP = 10, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_SINT32 = 17 |
||||
} google_protobuf_FieldDescriptorProto_Type; |
||||
|
||||
typedef enum google_protobuf_FieldDescriptorProto_Label { |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_LABEL_REQUIRED = 2, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_LABEL_REPEATED = 3, |
||||
GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_LABEL_OPTIONAL = 1 |
||||
} google_protobuf_FieldDescriptorProto_Label; |
||||
|
||||
typedef enum google_protobuf_FieldOptions_CType { |
||||
GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_CORD = 1, |
||||
GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_STRING = 0, |
||||
GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_STRING_PIECE = 2 |
||||
} google_protobuf_FieldOptions_CType; |
||||
|
||||
typedef enum google_protobuf_FileOptions_OptimizeMode { |
||||
GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZEMODE_CODE_SIZE = 2, |
||||
GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZEMODE_SPEED = 1, |
||||
GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZEMODE_LITE_RUNTIME = 3 |
||||
} google_protobuf_FileOptions_OptimizeMode; |
||||
|
||||
/* Constants for field names and numbers. */ |
||||
|
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH__FIELDNAME "path" |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH__FIELDTYPE 5 |
||||
|
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN__FIELDNAME "span" |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN__FIELDTYPE 5 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE__FIELDNAME "identifier_value" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE__FIELDNUM 4 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE__FIELDNAME "positive_int_value" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE__FIELDTYPE 4 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE__FIELDNUM 5 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE__FIELDNAME "negative_int_value" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE__FIELDTYPE 3 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE__FIELDNUM 8 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE__FIELDNAME "aggregate_value" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE__FIELDNUM 6 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE__FIELDNAME "double_value" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE__FIELDTYPE 1 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE__FIELDNUM 7 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE__FIELDNAME "string_value" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE__FIELDTYPE 12 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE__FIELDNAME "package" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY__FIELDNAME "dependency" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE__FIELDNUM 4 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE__FIELDNAME "message_type" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE__FIELDNUM 5 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE__FIELDNAME "enum_type" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS__FIELDNUM 8 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO__FIELDNUM 9 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO__FIELDNAME "source_code_info" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE__FIELDNUM 6 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE__FIELDNAME "service" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION__FIELDNUM 7 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION__FIELDNAME "extension" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE__FIELDNAME "input_type" |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE__FIELDNAME "output_type" |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS__FIELDNUM 4 |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE__FIELDNAME "file" |
||||
#define GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION__FIELDNAME "location" |
||||
#define GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START__FIELDNAME "start" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START__FIELDTYPE 5 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END__FIELDNAME "end" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END__FIELDTYPE 5 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER__FIELDNAME "number" |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER__FIELDTYPE 5 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE__FIELDNAME "ctype" |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE__FIELDTYPE 14 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED__FIELDNAME "packed" |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED__FIELDNAME "deprecated" |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY__FIELDNUM 9 |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY__FIELDNAME "experimental_map_key" |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE__FIELDNAME "java_package" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES__FIELDNUM 16 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES__FIELDNAME "cc_generic_services" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES__FIELDNUM 17 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES__FIELDNAME "java_generic_services" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES__FIELDNUM 18 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES__FIELDNAME "py_generic_services" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH__FIELDNUM 20 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH__FIELDNAME "java_generate_equals_and_hash" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME__FIELDNUM 8 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME__FIELDNAME "java_outer_classname" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR__FIELDNUM 9 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR__FIELDNAME "optimize_for" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR__FIELDTYPE 14 |
||||
|
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES__FIELDNUM 10 |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES__FIELDNAME "java_multiple_files" |
||||
#define GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE__FIELDNAME "value" |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD__FIELDNAME "method" |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD__FIELDNAME "field" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE__FIELDNAME "nested_type" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE__FIELDNUM 4 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE__FIELDNAME "enum_type" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE__FIELDNUM 5 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE__FIELDNAME "extension_range" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION__FIELDNUM 6 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION__FIELDNAME "extension" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS__FIELDNUM 7 |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME__FIELDNAME "name" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE__FIELDNAME "extendee" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER__FIELDNUM 3 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER__FIELDNAME "number" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER__FIELDTYPE 5 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL__FIELDNUM 4 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL__FIELDNAME "label" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL__FIELDTYPE 14 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE__FIELDNUM 5 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE__FIELDNAME "type" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE__FIELDTYPE 14 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS__FIELDNUM 8 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS__FIELDNAME "options" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME__FIELDNUM 6 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME__FIELDNAME "type_name" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE__FIELDNUM 7 |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE__FIELDNAME "default_value" |
||||
#define GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT__FIELDNAME "message_set_wire_format" |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR__FIELDNAME "no_standard_descriptor_accessor" |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR__FIELDTYPE 8 |
||||
|
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION__FIELDNUM 999 |
||||
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION__FIELDNAME "uninterpreted_option" |
||||
#define GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION__FIELDTYPE 11 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART__FIELDNUM 1 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART__FIELDNAME "name_part" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART__FIELDTYPE 9 |
||||
|
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION__FIELDNUM 2 |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION__FIELDNAME "is_extension" |
||||
#define GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION__FIELDTYPE 8 |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif /* UPB_DESCRIPTOR_CONST_H */ |
@ -0,0 +1,16 @@ |
||||
This directory contains code to interoperate with Google's official |
||||
Protocol Buffers release. Since it doesn't really have a name |
||||
besides "protobuf," calling this directory "google" seems like the |
||||
least confusing option. |
||||
|
||||
We support writing into protobuf's generated classes (and hopefully |
||||
reading too, before long). We support both the open source protobuf |
||||
release and the Google-internal version of the same code. The two |
||||
live in different namespaces, and the internal version supports some |
||||
features that are not supported in the open-source release. Also, the |
||||
internal version includes the legacy "proto1" classes which we must |
||||
support; thankfully this is mostly relegated to its own separate file. |
||||
|
||||
Our functionality requires the full google::protobuf::Message |
||||
interface; we rely on reflection so we know what fields to read/write |
||||
and where to put them, so we can't support MessageLite. |
@ -0,0 +1,260 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined
|
||||
// and once without! This allows us to provide functionality against proto2
|
||||
// and protobuf opensource both in a single binary without the two conflicting.
|
||||
// However we must be careful not to violate the ODR.
|
||||
|
||||
#include "upb/google/bridge.h" |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include "upb/def.h" |
||||
#include "upb/google/proto1.h" |
||||
#include "upb/google/proto2.h" |
||||
#include "upb/handlers.h" |
||||
|
||||
namespace upb { |
||||
namespace proto2_bridge_google3 { class Defs; } |
||||
namespace proto2_bridge_opensource { class Defs; } |
||||
} // namespace upb
|
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
#include "net/proto2/public/descriptor.h" |
||||
#include "net/proto2/public/message.h" |
||||
#include "net/proto2/proto/descriptor.pb.h" |
||||
namespace goog = ::proto2; |
||||
namespace me = ::upb::proto2_bridge_google3; |
||||
#else |
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/message.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
namespace goog = ::google::protobuf; |
||||
namespace me = ::upb::proto2_bridge_opensource; |
||||
#endif |
||||
|
||||
class me::Defs { |
||||
public: |
||||
void OnMessage(Handlers* h) { |
||||
const upb::MessageDef* md = h->message_def(); |
||||
const goog::Message& m = *message_map_[md]; |
||||
const goog::Descriptor* d = m.GetDescriptor(); |
||||
for (upb::MessageDef::ConstIterator i(md); !i.Done(); i.Next()) { |
||||
const upb::FieldDef* upb_f = i.field(); |
||||
const goog::FieldDescriptor* proto2_f = |
||||
d->FindFieldByNumber(upb_f->number()); |
||||
if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h) |
||||
#ifdef UPB_GOOGLE3 |
||||
&& !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h) |
||||
#endif |
||||
) { |
||||
// Unsupported reflection class.
|
||||
//
|
||||
// Should we fall back to using the public Reflection interface in this
|
||||
// case? It's unclear whether it's supported behavior for users to
|
||||
// create their own Reflection classes.
|
||||
assert(false); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void StaticOnMessage(void *closure, upb::Handlers* handlers) { |
||||
me::Defs* defs = static_cast<me::Defs*>(closure); |
||||
defs->OnMessage(handlers); |
||||
} |
||||
|
||||
void AddSymbol(const std::string& name, upb::Def* def) { |
||||
assert(symbol_map_.find(name) == symbol_map_.end()); |
||||
symbol_map_[name] = def; |
||||
} |
||||
|
||||
void AddMessage(const goog::Message* m, upb::MessageDef* md) { |
||||
assert(message_map_.find(md) == message_map_.end()); |
||||
message_map_[md] = m; |
||||
AddSymbol(m->GetDescriptor()->full_name(), md->Upcast()); |
||||
} |
||||
|
||||
upb::Def* FindSymbol(const std::string& name) { |
||||
SymbolMap::iterator iter = symbol_map_.find(name); |
||||
return iter != symbol_map_.end() ? iter->second : NULL; |
||||
} |
||||
|
||||
void Flatten(std::vector<upb::Def*>* defs) { |
||||
SymbolMap::iterator iter; |
||||
for (iter = symbol_map_.begin(); iter != symbol_map_.end(); ++iter) { |
||||
defs->push_back(iter->second); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
// Maps a new upb::MessageDef* to a corresponding proto2 Message* whose
|
||||
// derived class is of the correct type according to the message the user
|
||||
// gave us.
|
||||
typedef std::map<const upb::MessageDef*, const goog::Message*> MessageMap; |
||||
MessageMap message_map_; |
||||
|
||||
// Maps a type name to a upb Def we have constructed to represent it.
|
||||
typedef std::map<std::string, upb::Def*> SymbolMap; |
||||
SymbolMap symbol_map_; |
||||
}; |
||||
|
||||
namespace upb { |
||||
namespace google { |
||||
|
||||
// For submessage fields, stores a pointer to an instance of the submessage in
|
||||
// *subm (but it is *not* guaranteed to be a prototype).
|
||||
FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f, |
||||
upb::MessageDef* md, const goog::Message** subm) { |
||||
// To parse weak submessages effectively, we need to represent them in the
|
||||
// upb::Def schema even though they are not reflected in the proto2
|
||||
// descriptors (weak fields are represented as FieldDescriptor::TYPE_BYTES).
|
||||
const goog::Message* weak_prototype = NULL; |
||||
#ifdef UPB_GOOGLE3 |
||||
weak_prototype = upb::google::GetProto1WeakPrototype(m, f); |
||||
#endif |
||||
|
||||
upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f); |
||||
upb_f->set_number(f->number()); |
||||
upb_f->set_name(f->name()); |
||||
upb_f->set_label(static_cast<upb::FieldDef::Label>(f->label())); |
||||
upb_f->set_type(weak_prototype ? |
||||
UPB_TYPE_MESSAGE : static_cast<upb::FieldDef::Type>(f->type())); |
||||
|
||||
if (weak_prototype) { |
||||
upb_f->set_subdef_name(weak_prototype->GetDescriptor()->full_name()); |
||||
} else if (upb_f->IsSubMessage()) { |
||||
upb_f->set_subdef_name(f->message_type()->full_name()); |
||||
} else if (upb_f->type() == UPB_TYPE(ENUM)) { |
||||
// We set the enum default numerically.
|
||||
upb_f->set_default_value( |
||||
MakeValue(static_cast<int32_t>(f->default_value_enum()->number()))); |
||||
upb_f->set_subdef_name(f->enum_type()->full_name()); |
||||
} else { |
||||
// Set field default for primitive types. Need to switch on the upb type
|
||||
// rather than the proto2 type, because upb_f->type() may have been changed
|
||||
// from BYTES to MESSAGE for a weak field.
|
||||
switch (upb_types[upb_f->type()].inmemory_type) { |
||||
case UPB_CTYPE_INT32: |
||||
upb_f->set_default_value(MakeValue(f->default_value_int32())); |
||||
break; |
||||
case UPB_CTYPE_INT64: |
||||
upb_f->set_default_value( |
||||
MakeValue(static_cast<int64_t>(f->default_value_int64()))); |
||||
break; |
||||
case UPB_CTYPE_UINT32: |
||||
upb_f->set_default_value(MakeValue(f->default_value_uint32())); |
||||
break; |
||||
case UPB_CTYPE_UINT64: |
||||
upb_f->set_default_value( |
||||
MakeValue(static_cast<uint64_t>(f->default_value_uint64()))); |
||||
break; |
||||
case UPB_CTYPE_DOUBLE: |
||||
upb_f->set_default_value(MakeValue(f->default_value_double())); |
||||
break; |
||||
case UPB_CTYPE_FLOAT: |
||||
upb_f->set_default_value(MakeValue(f->default_value_float())); |
||||
break; |
||||
case UPB_CTYPE_BOOL: |
||||
upb_f->set_default_value(MakeValue(f->default_value_bool())); |
||||
break; |
||||
case UPB_CTYPE_BYTEREGION: |
||||
upb_f->set_default_string(f->default_value_string()); |
||||
break; |
||||
} |
||||
} |
||||
bool ok = md->AddField(upb_f, &upb_f); |
||||
UPB_ASSERT_VAR(ok, ok); |
||||
|
||||
if (weak_prototype) { |
||||
*subm = weak_prototype; |
||||
} else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { |
||||
*subm = upb::google::GetFieldPrototype(m, f); |
||||
#ifdef UPB_GOOGLE3 |
||||
if (!*subm) |
||||
*subm = upb::google::GetProto1FieldPrototype(m, f); |
||||
#endif |
||||
assert(*subm); |
||||
} |
||||
|
||||
return upb_f; |
||||
} |
||||
|
||||
upb::EnumDef* NewEnumDef(const goog::EnumDescriptor* desc, void *owner) { |
||||
upb::EnumDef* e = upb::EnumDef::New(owner); |
||||
e->set_full_name(desc->full_name()); |
||||
for (int i = 0; i < desc->value_count(); i++) { |
||||
const goog::EnumValueDescriptor* val = desc->value(i); |
||||
bool success = e->AddValue(val->name(), val->number(), NULL); |
||||
UPB_ASSERT_VAR(success, success); |
||||
} |
||||
return e; |
||||
} |
||||
|
||||
static upb::MessageDef* NewMessageDef(const goog::Message& m, void *owner, |
||||
me::Defs* defs) { |
||||
upb::MessageDef* md = upb::MessageDef::New(owner); |
||||
md->set_full_name(m.GetDescriptor()->full_name()); |
||||
|
||||
// Must do this before processing submessages to prevent infinite recursion.
|
||||
defs->AddMessage(&m, md); |
||||
|
||||
const goog::Descriptor* d = m.GetDescriptor(); |
||||
for (int i = 0; i < d->field_count(); i++) { |
||||
const goog::FieldDescriptor* proto2_f = d->field(i); |
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
// Skip lazy fields for now since we can't properly handle them.
|
||||
if (proto2_f->options().lazy()) continue; |
||||
#endif |
||||
// Extensions not supported yet.
|
||||
if (proto2_f->is_extension()) continue; |
||||
|
||||
const goog::Message* subm_prototype; |
||||
upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype); |
||||
|
||||
if (!f->HasSubDef()) continue; |
||||
|
||||
upb::Def* subdef = defs->FindSymbol(f->subdef_name()); |
||||
if (!subdef) { |
||||
if (f->type() == UPB_TYPE(ENUM)) { |
||||
subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast(); |
||||
defs->AddSymbol(subdef->full_name(), subdef); |
||||
} else { |
||||
assert(f->IsSubMessage()); |
||||
assert(subm_prototype); |
||||
subdef = NewMessageDef(*subm_prototype, owner, defs)->Upcast(); |
||||
} |
||||
} |
||||
f->set_subdef(subdef); |
||||
} |
||||
|
||||
return md; |
||||
} |
||||
|
||||
const upb::Handlers* NewWriteHandlers(const goog::Message& m, void *owner) { |
||||
me::Defs defs; |
||||
const upb::MessageDef* md = NewMessageDef(m, owner, &defs); |
||||
|
||||
std::vector<upb::Def*> defs_vec; |
||||
defs.Flatten(&defs_vec); |
||||
Status status; |
||||
bool success = Def::Freeze(defs_vec, &status); |
||||
UPB_ASSERT_VAR(success, success); |
||||
|
||||
const upb::Handlers* ret = |
||||
upb::Handlers::NewFrozen(md, owner, me::Defs::StaticOnMessage, &defs); |
||||
|
||||
// Unref all defs, since they're now ref'd by the handlers.
|
||||
for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) { |
||||
defs_vec[i]->Unref(owner); |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
@ -0,0 +1,76 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// This file contains functionality for constructing upb Defs and Handlers
|
||||
// corresponding to proto2 messages. Using this functionality, you can use upb
|
||||
// to dynamically generate parsing code that can behave exactly like proto2's
|
||||
// generated parsing code. Alternatively, you can configure things to
|
||||
// read/write only a subset of the fields for higher performance when only some
|
||||
// fields are needed.
|
||||
//
|
||||
// Example usage (FIX XXX):
|
||||
//
|
||||
// // Build a def that will have all fields and parse just like proto2 would.
|
||||
// const upb::MessageDef* md = upb::proto2_bridge::NewMessageDef(&MyProto());
|
||||
//
|
||||
// // JIT the parser; should only be done once ahead-of-time.
|
||||
// upb::Handlers* handlers = upb::NewHandlersForMessage(md);
|
||||
// upb::DecoderPlan* plan = upb::DecoderPlan::New(handlers);
|
||||
// handlers->Unref();
|
||||
//
|
||||
// // The actual parsing.
|
||||
// MyProto proto;
|
||||
// upb::Decoder decoder;
|
||||
// upb::StringSource source(buf, len);
|
||||
// decoder.ResetPlan(plan, 0);
|
||||
// decoder.ResetInput(source.AllBytes(), &proto);
|
||||
// CHECK(decoder.Decode() == UPB_OK) << decoder.status();
|
||||
//
|
||||
// To parse only one field and skip all others:
|
||||
//
|
||||
// const upb::MessageDef* md =
|
||||
// upb::proto2_bridge::NewEmptyMessageDef(MyProto().GetPrototype());
|
||||
// upb::proto2_bridge::AddFieldDef(
|
||||
// MyProto::descriptor()->FindFieldByName("my_field"), md);
|
||||
// upb::Freeze(md);
|
||||
//
|
||||
// // Now continue with "JIT the parser" from above.
|
||||
//
|
||||
// Note that there is currently no support for
|
||||
// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate
|
||||
// DescriptorPool and MessageFactory for extensions. Since this is a property
|
||||
// of the input in proto2, it's difficult to build a plan ahead-of-time that
|
||||
// can properly support this. If it's an important use case, the caller should
|
||||
// probably build a upb plan explicitly.
|
||||
|
||||
#ifndef UPB_GOOGLE_BRIDGE_H_ |
||||
#define UPB_GOOGLE_BRIDGE_H_ |
||||
|
||||
namespace google { |
||||
namespace protobuf { class Message; } |
||||
} // namespace google
|
||||
|
||||
namespace proto2 { class Message; } |
||||
|
||||
namespace upb { |
||||
|
||||
class Handlers; |
||||
|
||||
namespace google { |
||||
|
||||
// Returns a upb::Handlers object that can be used to populate a proto2::Message
|
||||
// object of the same type as "m."
|
||||
//
|
||||
// TODO(haberman): Add handler caching functionality so that we don't use
|
||||
// O(n^2) memory in the worst case when incrementally building handlers.
|
||||
const upb::Handlers* NewWriteHandlers(const proto2::Message& m, void *owner); |
||||
const upb::Handlers* NewWriteHandlers(const ::google::protobuf::Message& m, |
||||
void *owner); |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
||||
|
||||
#endif // UPB_GOOGLE_BRIDGE_H_
|
@ -0,0 +1,48 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// Functionality for interoperating with Cord. Only needed inside Google.
|
||||
|
||||
#ifndef UPB_GOOGLE_CORD_H |
||||
#define UPB_GOOGLE_CORD_H |
||||
|
||||
#include "strings/cord.h" |
||||
#include "upb/bytestream.h" |
||||
|
||||
namespace upb { |
||||
|
||||
namespace proto2_bridge_google3 { class FieldAccessor; } |
||||
namespace proto2_bridge_opensource { class FieldAccessor; } |
||||
|
||||
namespace google { |
||||
|
||||
class P2R_Handlers; |
||||
|
||||
class CordSupport { |
||||
private: |
||||
UPB_DISALLOW_POD_OPS(CordSupport); |
||||
|
||||
inline static void AssignToCord(const upb::ByteRegion* r, Cord* cord) { |
||||
// TODO(haberman): ref source data if source is a cord.
|
||||
cord->Clear(); |
||||
uint64_t ofs = r->start_ofs(); |
||||
while (ofs < r->end_ofs()) { |
||||
size_t len; |
||||
const char *buf = r->GetPtr(ofs, &len); |
||||
cord->Append(StringPiece(buf, len)); |
||||
ofs += len; |
||||
} |
||||
} |
||||
|
||||
friend class ::upb::proto2_bridge_google3::FieldAccessor; |
||||
friend class ::upb::proto2_bridge_opensource::FieldAccessor; |
||||
friend class P2R_Handlers; |
||||
}; |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
||||
|
||||
#endif // UPB_GOOGLE_CORD_H
|
@ -0,0 +1,502 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// This set of handlers can write into a proto2::Message whose reflection class
|
||||
// is _pi::Proto2Reflection (ie. proto1 messages; while slightly confusing, the
|
||||
// name "Proto2Reflection" indicates that it is a reflection class implementing
|
||||
// the proto2 reflection interface, but is used for proto1 generated messages).
|
||||
//
|
||||
// Like FieldAccessor this depends on breaking encapsulation, and will need to
|
||||
// be changed if and when the details of _pi::Proto2Reflection change.
|
||||
//
|
||||
// Note that we have received an exception from c-style-artiters regarding
|
||||
// dynamic_cast<> in this file:
|
||||
// https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ
|
||||
|
||||
#include "upb/google/proto1.h" |
||||
|
||||
// TODO(haberman): friend upb so that this isn't required.
|
||||
#define protected public |
||||
#include "net/proto2/public/repeated_field.h" |
||||
#undef private |
||||
|
||||
// TODO(haberman): friend upb so that this isn't required.
|
||||
#define private public |
||||
#include "net/proto/proto2_reflection.h" |
||||
#undef private |
||||
|
||||
#include "net/proto/internal_layout.h" |
||||
#include "upb/bytestream.h" |
||||
#include "upb/def.h" |
||||
#include "upb/google/cord.h" |
||||
#include "upb/handlers.h" |
||||
|
||||
template<class T> static T* GetPointer(void *message, size_t offset) { |
||||
return reinterpret_cast<T*>(static_cast<char*>(message) + offset); |
||||
} |
||||
|
||||
namespace upb { |
||||
namespace google { |
||||
|
||||
class P2R_Handlers { |
||||
public: |
||||
// Returns true if we were able to set an accessor and any other properties
|
||||
// of the FieldDef that are necessary to read/write this field to a
|
||||
// proto2::Message.
|
||||
static bool TrySet(const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& m, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h) { |
||||
const proto2::Reflection* base_r = m.GetReflection(); |
||||
// See file comment re: dynamic_cast.
|
||||
const _pi::Proto2Reflection* r = |
||||
dynamic_cast<const _pi::Proto2Reflection*>(base_r); |
||||
if (!r) return false; |
||||
// Extensions not supported yet.
|
||||
if (proto2_f->is_extension()) return false; |
||||
|
||||
switch (r->GetFieldLayout(proto2_f)->crep) { |
||||
#define PRIMITIVE(name, type_name) \ |
||||
case _pi::CREP_REQUIRED_ ## name: \
|
||||
case _pi::CREP_OPTIONAL_ ## name: \
|
||||
case _pi::CREP_REPEATED_ ## name: \
|
||||
SetPrimitiveHandlers<type_name>(proto2_f, r, upb_f, h); return true; |
||||
PRIMITIVE(DOUBLE, double); |
||||
PRIMITIVE(FLOAT, float); |
||||
PRIMITIVE(INT64, int64_t); |
||||
PRIMITIVE(UINT64, uint64_t); |
||||
PRIMITIVE(INT32, int32_t); |
||||
PRIMITIVE(FIXED64, uint64_t); |
||||
PRIMITIVE(FIXED32, uint32_t); |
||||
PRIMITIVE(BOOL, bool); |
||||
#undef PRIMITIVE |
||||
case _pi::CREP_REQUIRED_STRING: |
||||
case _pi::CREP_OPTIONAL_STRING: |
||||
case _pi::CREP_REPEATED_STRING: |
||||
SetStringHandlers(proto2_f, r, upb_f, h); |
||||
return true; |
||||
case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: |
||||
SetOutOfLineStringHandlers(proto2_f, r, upb_f, h); |
||||
return true; |
||||
case _pi::CREP_REQUIRED_CORD: |
||||
case _pi::CREP_OPTIONAL_CORD: |
||||
case _pi::CREP_REPEATED_CORD: |
||||
SetCordHandlers(proto2_f, r, upb_f, h); |
||||
return true; |
||||
case _pi::CREP_REQUIRED_GROUP: |
||||
case _pi::CREP_REQUIRED_FOREIGN: |
||||
case _pi::CREP_REQUIRED_FOREIGN_PROTO2: |
||||
SetRequiredMessageHandlers(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
case _pi::CREP_OPTIONAL_GROUP: |
||||
case _pi::CREP_REPEATED_GROUP: |
||||
case _pi::CREP_OPTIONAL_FOREIGN: |
||||
case _pi::CREP_REPEATED_FOREIGN: |
||||
case _pi::CREP_OPTIONAL_FOREIGN_PROTO2: |
||||
case _pi::CREP_REPEATED_FOREIGN_PROTO2: |
||||
SetMessageHandlers(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
case _pi::CREP_OPTIONAL_FOREIGN_WEAK: |
||||
case _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2: |
||||
SetWeakMessageHandlers(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
default: assert(false); return false; |
||||
} |
||||
} |
||||
|
||||
// If the field "f" in the message "m" is a weak field, returns the prototype
|
||||
// of the submessage (which may be a specific type or may be OpaqueMessage).
|
||||
// Otherwise returns NULL.
|
||||
static const proto2::Message* GetWeakPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f) { |
||||
// See file comment re: dynamic_cast.
|
||||
const _pi::Proto2Reflection* r = |
||||
dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection()); |
||||
if (!r) return NULL; |
||||
|
||||
const _pi::Field* field = r->GetFieldLayout(f); |
||||
if (field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { |
||||
return static_cast<const proto2::Message*>( |
||||
field->weak_layout()->default_instance); |
||||
} else if (field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2) { |
||||
return field->proto2_weak_default_instance(); |
||||
} else { |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
// If "m" is a message that uses Proto2Reflection, returns the prototype of
|
||||
// the submessage (which may be OpaqueMessage for a weak field that is not
|
||||
// linked in). Otherwise returns NULL.
|
||||
static const proto2::Message* GetFieldPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f) { |
||||
// See file comment re: dynamic_cast.
|
||||
const proto2::Message* ret = GetWeakPrototype(m, f); |
||||
if (ret) { |
||||
return ret; |
||||
} else if (dynamic_cast<const _pi::Proto2Reflection*>(m.GetReflection())) { |
||||
// Since proto1 has no dynamic message, it must be from the generated
|
||||
// factory.
|
||||
assert(f->cpp_type() == proto2::FieldDescriptor::CPPTYPE_MESSAGE); |
||||
ret = proto2::MessageFactory::generated_factory()->GetPrototype( |
||||
f->message_type()); |
||||
assert(ret); |
||||
return ret; |
||||
} else { |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
class FieldOffset { |
||||
public: |
||||
FieldOffset( |
||||
const proto2::FieldDescriptor* f, |
||||
const _pi::Proto2Reflection* r) |
||||
: offset_(GetOffset(f, r)), |
||||
is_repeated_(f->is_repeated()) { |
||||
if (!is_repeated_) { |
||||
int64_t hasbit = GetHasbit(f, r); |
||||
hasbyte_ = hasbit / 8; |
||||
mask_ = 1 << (hasbit % 8); |
||||
} |
||||
} |
||||
|
||||
template<class T> T* GetFieldPointer(void* message) const { |
||||
return GetPointer<T>(message, offset_); |
||||
} |
||||
|
||||
void SetHasbit(void* message) const { |
||||
assert(!is_repeated_); |
||||
uint8_t* byte = GetPointer<uint8_t>(message, hasbyte_); |
||||
*byte |= mask_; |
||||
} |
||||
|
||||
private: |
||||
const size_t offset_; |
||||
bool is_repeated_; |
||||
|
||||
// Only for non-repeated fields.
|
||||
int32_t hasbyte_; |
||||
int8_t mask_; |
||||
}; |
||||
|
||||
static upb_selector_t GetSelector(const upb::FieldDef* f, |
||||
upb::Handlers::Type type) { |
||||
upb::Handlers::Selector selector; |
||||
bool ok = upb::Handlers::GetSelector(f, type, &selector); |
||||
UPB_ASSERT_VAR(ok, ok); |
||||
return selector; |
||||
} |
||||
|
||||
|
||||
static int16_t GetHasbit(const proto2::FieldDescriptor* f, |
||||
const _pi::Proto2Reflection* r) { |
||||
assert(!f->is_repeated()); |
||||
return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; |
||||
} |
||||
|
||||
static uint16_t GetOffset(const proto2::FieldDescriptor* f, |
||||
const _pi::Proto2Reflection* r) { |
||||
return r->GetFieldLayout(f)->offset; |
||||
} |
||||
|
||||
// StartSequence /////////////////////////////////////////////////////////////
|
||||
|
||||
static void SetStartSequenceHandler( |
||||
const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
assert(f->IsSequence()); |
||||
h->SetStartSequenceHandler( |
||||
f, &PushOffset, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset>); |
||||
} |
||||
|
||||
static void* PushOffset(void *m, void *fval) { |
||||
const FieldOffset* offset = static_cast<FieldOffset*>(fval); |
||||
return offset->GetFieldPointer<void>(m); |
||||
} |
||||
|
||||
// Primitive Value (numeric, enum, bool) /////////////////////////////////////
|
||||
|
||||
template <typename T> static void SetPrimitiveHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetValueHandler<T>(f, &Append<T>, NULL, NULL); |
||||
} else { |
||||
upb::SetStoreValueHandler<T>( |
||||
f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r), h); |
||||
} |
||||
} |
||||
|
||||
template <typename T> |
||||
static bool Append(void *_r, void *fval, T val) { |
||||
UPB_UNUSED(fval); |
||||
// Proto1's ProtoArray class derives from proto2::RepeatedField.
|
||||
proto2::RepeatedField<T>* r = static_cast<proto2::RepeatedField<T>*>(_r); |
||||
r->Add(val); |
||||
return true; |
||||
} |
||||
|
||||
// String ////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void SetStringHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
h->SetStringHandler(f, &OnStringBuf, NULL, NULL); |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetStartStringHandler(f, &StartRepeatedString, NULL, NULL); |
||||
} else { |
||||
h->SetStartStringHandler( |
||||
f, &StartString, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset>); |
||||
} |
||||
} |
||||
|
||||
static void* StartString(void *m, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
const FieldOffset* info = static_cast<const FieldOffset*>(fval); |
||||
info->SetHasbit(m); |
||||
string* str = info->GetFieldPointer<string>(m); |
||||
str->clear(); |
||||
// reserve() here appears to hurt performance rather than help.
|
||||
return str; |
||||
} |
||||
|
||||
static size_t OnStringBuf(void *_s, void *fval, const char *buf, size_t n) { |
||||
string* s = static_cast<string*>(_s); |
||||
s->append(buf, n); |
||||
return n; |
||||
} |
||||
|
||||
static void* StartRepeatedString(void *_r, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(fval); |
||||
proto2::RepeatedPtrField<string>* r = |
||||
static_cast<proto2::RepeatedPtrField<string>*>(_r); |
||||
string* str = r->Add(); |
||||
// reserve() here appears to hurt performance rather than help.
|
||||
return str; |
||||
} |
||||
|
||||
// Out-of-line string ////////////////////////////////////////////////////////
|
||||
|
||||
static void SetOutOfLineStringHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
// This type is only used for non-repeated string fields.
|
||||
assert(!f->IsSequence()); |
||||
h->SetStartStringHandler( |
||||
f, &StartOutOfLineString, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset>); |
||||
h->SetStringHandler(f, &OnStringBuf, NULL, NULL); |
||||
} |
||||
|
||||
static void* StartOutOfLineString(void *m, void *fval, size_t size_hint) { |
||||
const FieldOffset* info = static_cast<const FieldOffset*>(fval); |
||||
info->SetHasbit(m); |
||||
string **str = info->GetFieldPointer<string*>(m); |
||||
if (*str == &::ProtocolMessage::___empty_internal_proto_string_) |
||||
*str = new string(); |
||||
(*str)->clear(); |
||||
// reserve() here appears to hurt performance rather than help.
|
||||
return *str; |
||||
} |
||||
|
||||
// Cord //////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void SetCordHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
h->SetStringHandler(f, &OnCordBuf, NULL, NULL); |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL); |
||||
} else { |
||||
h->SetStartStringHandler( |
||||
f, &StartCord, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset*>); |
||||
} |
||||
} |
||||
|
||||
static void* StartCord(void *m, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
UPB_UNUSED(fval); |
||||
const FieldOffset* offset = static_cast<const FieldOffset*>(fval); |
||||
offset->SetHasbit(m); |
||||
Cord* field = offset->GetFieldPointer<Cord>(m); |
||||
field->Clear(); |
||||
return field; |
||||
} |
||||
|
||||
static size_t OnCordBuf(void *_c, void *fval, const char *buf, size_t n) { |
||||
UPB_UNUSED(fval); |
||||
Cord* c = static_cast<Cord*>(_c); |
||||
c->Append(StringPiece(buf, n)); |
||||
return true; |
||||
} |
||||
|
||||
static void* StartRepeatedCord(void *_r, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
UPB_UNUSED(fval); |
||||
proto2::RepeatedField<Cord>* r = |
||||
static_cast<proto2::RepeatedField<Cord>*>(_r); |
||||
return r->Add(); |
||||
} |
||||
|
||||
// SubMessage ////////////////////////////////////////////////////////////////
|
||||
|
||||
class SubMessageHandlerData : public FieldOffset { |
||||
public: |
||||
SubMessageHandlerData( |
||||
const proto2::Message& prototype, |
||||
const proto2::FieldDescriptor* f, |
||||
const _pi::Proto2Reflection* r) |
||||
: FieldOffset(f, r) { |
||||
prototype_ = GetWeakPrototype(prototype, f); |
||||
if (!prototype_) |
||||
prototype_ = GetFieldPrototype(prototype, f); |
||||
} |
||||
|
||||
const proto2::Message* prototype() const { return prototype_; } |
||||
|
||||
private: |
||||
const proto2::Message* prototype_; |
||||
}; |
||||
|
||||
static void SetStartSubMessageHandler( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& m, |
||||
const _pi::Proto2Reflection* r, |
||||
upb::Handlers::StartFieldHandler* handler, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
h->SetStartSubMessageHandler( |
||||
f, handler, |
||||
new SubMessageHandlerData(m, proto2_f, r), |
||||
&upb::DeletePointer<SubMessageHandlerData>); |
||||
} |
||||
|
||||
static void SetRequiredMessageHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& m, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); |
||||
} else { |
||||
h->SetStartSubMessageHandler( |
||||
f, &StartRequiredSubMessage, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset>); |
||||
} |
||||
} |
||||
|
||||
static void* StartRequiredSubMessage(void *m, void *fval) { |
||||
const FieldOffset* offset = static_cast<FieldOffset*>(fval); |
||||
offset->SetHasbit(m); |
||||
return offset->GetFieldPointer<void>(m); |
||||
} |
||||
|
||||
static void SetMessageHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& m, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); |
||||
} else { |
||||
SetStartSubMessageHandler(proto2_f, m, r, &StartSubMessage, f, h); |
||||
} |
||||
} |
||||
|
||||
static void SetWeakMessageHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& m, |
||||
const _pi::Proto2Reflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
SetStartSubMessageHandler(proto2_f, m, r, &StartRepeatedSubMessage, f, h); |
||||
} else { |
||||
SetStartSubMessageHandler(proto2_f, m, r, &StartWeakSubMessage, f, h); |
||||
} |
||||
} |
||||
|
||||
static void* StartSubMessage(void *m, void *fval) { |
||||
const SubMessageHandlerData* info = |
||||
static_cast<const SubMessageHandlerData*>(fval); |
||||
info->SetHasbit(m); |
||||
proto2::Message **subm = info->GetFieldPointer<proto2::Message*>(m); |
||||
if (*subm == info->prototype()) *subm = (*subm)->New(); |
||||
return *subm; |
||||
} |
||||
|
||||
static void* StartWeakSubMessage(void *m, void *fval) { |
||||
const SubMessageHandlerData* info = |
||||
static_cast<const SubMessageHandlerData*>(fval); |
||||
info->SetHasbit(m); |
||||
proto2::Message **subm = info->GetFieldPointer<proto2::Message*>(m); |
||||
if (*subm == NULL) { |
||||
*subm = info->prototype()->New(); |
||||
} |
||||
return *subm; |
||||
} |
||||
|
||||
class RepeatedMessageTypeHandler { |
||||
public: |
||||
typedef void Type; |
||||
// AddAllocated() calls this, but only if other objects are sitting
|
||||
// around waiting for reuse, which we will not do.
|
||||
static void Delete(Type* t) { |
||||
(void)t; |
||||
assert(false); |
||||
} |
||||
}; |
||||
|
||||
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
|
||||
// its base class RepeatedPtrFieldBase*.
|
||||
static void* StartRepeatedSubMessage(void* _r, void *fval) { |
||||
const SubMessageHandlerData* info = |
||||
static_cast<const SubMessageHandlerData*>(fval); |
||||
proto2::internal::RepeatedPtrFieldBase *r = |
||||
static_cast<proto2::internal::RepeatedPtrFieldBase*>(_r); |
||||
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); |
||||
if (!submsg) { |
||||
submsg = info->prototype()->New(); |
||||
r->AddAllocated<RepeatedMessageTypeHandler>(submsg); |
||||
} |
||||
return submsg; |
||||
} |
||||
}; |
||||
|
||||
bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& m, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h) { |
||||
return P2R_Handlers::TrySet(proto2_f, m, upb_f, h); |
||||
} |
||||
|
||||
const proto2::Message* GetProto1WeakPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f) { |
||||
return P2R_Handlers::GetWeakPrototype(m, f); |
||||
} |
||||
|
||||
const proto2::Message* GetProto1FieldPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f) { |
||||
return P2R_Handlers::GetFieldPrototype(m, f); |
||||
} |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
@ -0,0 +1,53 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// Support for registering field handlers that can write into a legacy proto1
|
||||
// message. This functionality is only needed inside Google.
|
||||
//
|
||||
// This is a low-level interface; the high-level interface in google.h is
|
||||
// more user-friendly.
|
||||
|
||||
#ifndef UPB_GOOGLE_PROTO1_H_ |
||||
#define UPB_GOOGLE_PROTO1_H_ |
||||
|
||||
namespace proto2 { |
||||
class FieldDescriptor; |
||||
class Message; |
||||
} |
||||
|
||||
namespace upb { |
||||
class FieldDef; |
||||
class Handlers; |
||||
} |
||||
|
||||
namespace upb { |
||||
namespace google { |
||||
|
||||
// Sets field handlers in the given Handlers object for writing to a single
|
||||
// field (as described by "proto2_f" and "upb_f") into a message constructed
|
||||
// by the same factory as "prototype." Returns true if this was successful
|
||||
// (this will fail if "prototype" is not a proto1 message, or if we can't
|
||||
// handle it for some reason).
|
||||
bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& prototype, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h); |
||||
|
||||
// Returns a prototype for the given field in "m", if it is weak. The returned
|
||||
// message could be the linked-in message type or OpaqueMessage, if the weak
|
||||
// message is *not* linked in. Otherwise returns NULL.
|
||||
const proto2::Message* GetProto1WeakPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f); |
||||
|
||||
// Returns a prototype for the given non-weak field in "m".
|
||||
const proto2::Message* GetProto1FieldPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f); |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
||||
|
||||
#endif // UPB_GOOGLE_PROTO1_H_
|
@ -0,0 +1,632 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// Note that we have received an exception from c-style-artiters regarding
|
||||
// dynamic_cast<> in this file:
|
||||
// https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ
|
||||
//
|
||||
// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined
|
||||
// and once without! This allows us to provide functionality against proto2
|
||||
// and protobuf opensource both in a single binary without the two conflicting.
|
||||
// However we must be careful not to violate the ODR.
|
||||
|
||||
#include "upb/google/proto2.h" |
||||
|
||||
#include "upb/google/proto1.h" |
||||
#include "upb/bytestream.h" |
||||
#include "upb/def.h" |
||||
#include "upb/handlers.h" |
||||
|
||||
namespace upb { |
||||
namespace proto2_bridge_google3 { class FieldAccessor; } |
||||
namespace proto2_bridge_opensource { class FieldAccessor; } |
||||
} // namespace upb
|
||||
|
||||
// BEGIN DOUBLE COMPILATION TRICKERY. //////////////////////////////////////////
|
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
|
||||
// TODO(haberman): friend upb so that this isn't required.
|
||||
#define protected public |
||||
#include "net/proto2/public/repeated_field.h" |
||||
#undef protected |
||||
|
||||
#define private public |
||||
#include "net/proto2/public/generated_message_reflection.h" |
||||
#undef private |
||||
|
||||
#include "net/proto2/proto/descriptor.pb.h" |
||||
#include "net/proto2/public/descriptor.h" |
||||
#include "net/proto2/public/lazy_field.h" |
||||
#include "net/proto2/public/message.h" |
||||
#include "net/proto2/public/string_piece_field_support.h" |
||||
#include "upb/google/cord.h" |
||||
|
||||
namespace goog = ::proto2; |
||||
namespace me = ::upb::proto2_bridge_google3; |
||||
|
||||
#else |
||||
|
||||
// TODO(haberman): friend upb so that this isn't required.
|
||||
#define protected public |
||||
#include "google/protobuf/repeated_field.h" |
||||
#undef protected |
||||
|
||||
#define private public |
||||
#include "google/protobuf/generated_message_reflection.h" |
||||
#undef private |
||||
|
||||
#include "google/protobuf/descriptor.h" |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
#include "google/protobuf/message.h" |
||||
|
||||
namespace goog = ::google::protobuf; |
||||
namespace me = ::upb::proto2_bridge_opensource; |
||||
|
||||
#endif // ifdef UPB_GOOGLE3
|
||||
|
||||
// END DOUBLE COMPILATION TRICKERY. ////////////////////////////////////////////
|
||||
|
||||
// Have to define this manually since older versions of proto2 didn't define
|
||||
// an enum value for STRING.
|
||||
#define UPB_CTYPE_STRING 0 |
||||
|
||||
template<class T> static T* GetPointer(void *message, size_t offset) { |
||||
return reinterpret_cast<T*>(static_cast<char*>(message) + offset); |
||||
} |
||||
|
||||
// This class contains handlers that can write into a proto2 class whose
|
||||
// reflection class is GeneratedMessageReflection. (Despite the name, even
|
||||
// DynamicMessage uses GeneratedMessageReflection, so this covers all proto2
|
||||
// messages generated by the compiler.) To do this it must break the
|
||||
// encapsulation of GeneratedMessageReflection and therefore depends on
|
||||
// internal interfaces that are not guaranteed to be stable. This class will
|
||||
// need to be updated if any non-backward-compatible changes are made to
|
||||
// GeneratedMessageReflection.
|
||||
//
|
||||
// TODO(haberman): change class name? In retrospect, "FieldAccessor" isn't the
|
||||
// best (something more specific like GeneratedMessageReflectionHandlers or
|
||||
// GMR_Handlers would be better) but we're depending on a "friend" declaration
|
||||
// in proto2 that already specifies "FieldAccessor." No versions of proto2 have
|
||||
// been released that include the "friend FieldAccessor" declaration, so there's
|
||||
// still time to change this. On the other hand, perhaps it's simpler to just
|
||||
// rely on "#define private public" since it may be a long time before new
|
||||
// versions of proto2 open source are pervasive enough that we can remove this
|
||||
// anyway.
|
||||
class me::FieldAccessor { |
||||
public: |
||||
// Returns true if we were able to set an accessor and any other properties
|
||||
// of the FieldDef that are necessary to read/write this field to a
|
||||
// proto2::Message.
|
||||
static bool TrySet(const goog::FieldDescriptor* proto2_f, |
||||
const goog::Message& m, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h) { |
||||
const goog::Reflection* base_r = m.GetReflection(); |
||||
// See file comment re: dynamic_cast.
|
||||
const goog::internal::GeneratedMessageReflection* r = |
||||
dynamic_cast<const goog::internal::GeneratedMessageReflection*>(base_r); |
||||
if (!r) return false; |
||||
// Extensions not supported yet.
|
||||
if (proto2_f->is_extension()) return false; |
||||
|
||||
switch (proto2_f->cpp_type()) { |
||||
#define PRIMITIVE_TYPE(cpptype, cident) \ |
||||
case goog::FieldDescriptor::cpptype: \
|
||||
SetPrimitiveHandlers<cident>(proto2_f, r, upb_f, h); return true; |
||||
PRIMITIVE_TYPE(CPPTYPE_INT32, int32_t); |
||||
PRIMITIVE_TYPE(CPPTYPE_INT64, int64_t); |
||||
PRIMITIVE_TYPE(CPPTYPE_UINT32, uint32_t); |
||||
PRIMITIVE_TYPE(CPPTYPE_UINT64, uint64_t); |
||||
PRIMITIVE_TYPE(CPPTYPE_DOUBLE, double); |
||||
PRIMITIVE_TYPE(CPPTYPE_FLOAT, float); |
||||
PRIMITIVE_TYPE(CPPTYPE_BOOL, bool); |
||||
#undef PRIMITIVE_TYPE |
||||
case goog::FieldDescriptor::CPPTYPE_ENUM: |
||||
SetEnumHandlers(proto2_f, r, upb_f, h); |
||||
return true; |
||||
case goog::FieldDescriptor::CPPTYPE_STRING: { |
||||
// Old versions of the open-source protobuf release erroneously default
|
||||
// to Cord even though that has never been supported in the open-source
|
||||
// release.
|
||||
int32_t ctype = proto2_f->options().has_ctype() ? |
||||
proto2_f->options().ctype() : UPB_CTYPE_STRING; |
||||
switch (ctype) { |
||||
#ifdef UPB_GOOGLE3 |
||||
case goog::FieldOptions::STRING: |
||||
SetStringHandlers<string>(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
case goog::FieldOptions::CORD: |
||||
SetCordHandlers(proto2_f, r, upb_f, h); |
||||
return true; |
||||
case goog::FieldOptions::STRING_PIECE: |
||||
SetStringPieceHandlers(proto2_f, r, upb_f, h); |
||||
return true; |
||||
#else |
||||
case UPB_CTYPE_STRING: |
||||
SetStringHandlers<std::string>(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
#endif |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
case goog::FieldDescriptor::CPPTYPE_MESSAGE: |
||||
#ifdef UPB_GOOGLE3 |
||||
if (proto2_f->options().lazy()) { |
||||
return false; // Not yet implemented.
|
||||
} else { |
||||
SetSubMessageHandlers(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
} |
||||
#else |
||||
SetSubMessageHandlers(proto2_f, m, r, upb_f, h); |
||||
return true; |
||||
#endif |
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
static const goog::Message* GetFieldPrototype( |
||||
const goog::Message& m, |
||||
const goog::FieldDescriptor* f) { |
||||
// We assume that all submessages (and extensions) will be constructed
|
||||
// using the same MessageFactory as this message. This doesn't cover the
|
||||
// case of CodedInputStream::SetExtensionRegistry().
|
||||
// See file comment re: dynamic_cast.
|
||||
const goog::internal::GeneratedMessageReflection* r = |
||||
dynamic_cast<const goog::internal::GeneratedMessageReflection*>( |
||||
m.GetReflection()); |
||||
if (!r) return NULL; |
||||
return r->message_factory_->GetPrototype(f->message_type()); |
||||
} |
||||
|
||||
private: |
||||
static upb_selector_t GetSelector(const upb::FieldDef* f, |
||||
upb::Handlers::Type type) { |
||||
upb::Handlers::Selector selector; |
||||
bool ok = upb::Handlers::GetSelector(f, type, &selector); |
||||
UPB_ASSERT_VAR(ok, ok); |
||||
return selector; |
||||
} |
||||
|
||||
static int64_t GetHasbit( |
||||
const goog::FieldDescriptor* f, |
||||
const goog::internal::GeneratedMessageReflection* r) { |
||||
// proto2 does not store hasbits for repeated fields.
|
||||
assert(!f->is_repeated()); |
||||
return (r->has_bits_offset_ * 8) + f->index(); |
||||
} |
||||
|
||||
static uint16_t GetOffset( |
||||
const goog::FieldDescriptor* f, |
||||
const goog::internal::GeneratedMessageReflection* r) { |
||||
return r->offsets_[f->index()]; |
||||
} |
||||
|
||||
class FieldOffset { |
||||
public: |
||||
FieldOffset( |
||||
const goog::FieldDescriptor* f, |
||||
const goog::internal::GeneratedMessageReflection* r) |
||||
: offset_(GetOffset(f, r)), |
||||
is_repeated_(f->is_repeated()) { |
||||
if (!is_repeated_) { |
||||
int64_t hasbit = GetHasbit(f, r); |
||||
hasbyte_ = hasbit / 8; |
||||
mask_ = 1 << (hasbit % 8); |
||||
} |
||||
} |
||||
|
||||
template<class T> T* GetFieldPointer(void *message) const { |
||||
return GetPointer<T>(message, offset_); |
||||
} |
||||
|
||||
void SetHasbit(void* m) const { |
||||
assert(!is_repeated_); |
||||
uint8_t* byte = GetPointer<uint8_t>(m, hasbyte_); |
||||
*byte |= mask_; |
||||
} |
||||
|
||||
private: |
||||
const size_t offset_; |
||||
bool is_repeated_; |
||||
|
||||
// Only for non-repeated fields.
|
||||
int32_t hasbyte_; |
||||
int8_t mask_; |
||||
}; |
||||
|
||||
// StartSequence /////////////////////////////////////////////////////////////
|
||||
|
||||
static void SetStartSequenceHandler( |
||||
const goog::FieldDescriptor* proto2_f, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
assert(f->IsSequence()); |
||||
h->SetStartSequenceHandler( |
||||
f, &PushOffset, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset>); |
||||
} |
||||
|
||||
static void* PushOffset(void *m, void *fval) { |
||||
const FieldOffset* offset = static_cast<FieldOffset*>(fval); |
||||
return offset->GetFieldPointer<void>(m); |
||||
} |
||||
|
||||
// Primitive Value (numeric, bool) ///////////////////////////////////////////
|
||||
|
||||
template <typename T> static void SetPrimitiveHandlers( |
||||
const goog::FieldDescriptor* proto2_f, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, |
||||
upb::Handlers* h) { |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetValueHandler<T>(f, &AppendPrimitive<T>, NULL, NULL); |
||||
} else { |
||||
upb::SetStoreValueHandler<T>( |
||||
f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r), h); |
||||
} |
||||
} |
||||
|
||||
template <typename T> |
||||
static bool AppendPrimitive(void *_r, void *fval, T val) { |
||||
UPB_UNUSED(fval); |
||||
goog::RepeatedField<T>* r = static_cast<goog::RepeatedField<T>*>(_r); |
||||
r->Add(val); |
||||
return true; |
||||
} |
||||
|
||||
// Enum //////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EnumHandlerData : public FieldOffset { |
||||
public: |
||||
EnumHandlerData( |
||||
const goog::FieldDescriptor* proto2_f, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f) |
||||
: FieldOffset(proto2_f, r), |
||||
field_number_(f->number()), |
||||
unknown_fields_offset_(r->unknown_fields_offset_), |
||||
enum_(upb_downcast_enumdef(f->subdef())) { |
||||
} |
||||
|
||||
bool IsValidValue(int32_t val) const { |
||||
return enum_->FindValueByNumber(val) != NULL; |
||||
} |
||||
|
||||
int32_t field_number() const { return field_number_; } |
||||
|
||||
goog::UnknownFieldSet* mutable_unknown_fields(goog::Message* m) const { |
||||
return GetPointer<goog::UnknownFieldSet>(m, unknown_fields_offset_); |
||||
} |
||||
|
||||
private: |
||||
int32_t field_number_; |
||||
size_t unknown_fields_offset_; |
||||
const upb::EnumDef* enum_; |
||||
}; |
||||
|
||||
static void SetEnumHandlers( |
||||
const goog::FieldDescriptor* proto2_f, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, |
||||
upb::Handlers* h) { |
||||
EnumHandlerData* data = new EnumHandlerData(proto2_f, r, f); |
||||
if (f->IsSequence()) { |
||||
h->SetInt32Handler( |
||||
f, &AppendEnum, data, &upb::DeletePointer<EnumHandlerData>); |
||||
} else { |
||||
h->SetInt32Handler( |
||||
f, &SetEnum, data, &upb::DeletePointer<EnumHandlerData>); |
||||
} |
||||
} |
||||
|
||||
static bool SetEnum(void *_m, void *fval, int32_t val) { |
||||
goog::Message* m = static_cast<goog::Message*>(_m); |
||||
const EnumHandlerData* data = static_cast<const EnumHandlerData*>(fval); |
||||
if (data->IsValidValue(val)) { |
||||
int32_t* message_val = data->GetFieldPointer<int32_t>(m); |
||||
*message_val = val; |
||||
data->SetHasbit(m); |
||||
} else { |
||||
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static bool AppendEnum(void *_m, void *fval, int32_t val) { |
||||
// Closure is the enclosing message. We can't use the RepeatedField<> as
|
||||
// the closure because we need to go back to the message for unrecognized
|
||||
// enum values, which go into the unknown field set.
|
||||
goog::Message* m = static_cast<goog::Message*>(_m); |
||||
const EnumHandlerData* data = static_cast<const EnumHandlerData*>(fval); |
||||
if (data->IsValidValue(val)) { |
||||
goog::RepeatedField<int32_t>* r = |
||||
data->GetFieldPointer<goog::RepeatedField<int32_t> >(m); |
||||
r->Add(val); |
||||
} else { |
||||
data->mutable_unknown_fields(m)->AddVarint(data->field_number(), val); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
// String ////////////////////////////////////////////////////////////////////
|
||||
|
||||
// For scalar (non-repeated) string fields.
|
||||
template<class T> |
||||
class StringHandlerData : public FieldOffset { |
||||
public: |
||||
StringHandlerData(const goog::FieldDescriptor* proto2_f, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const goog::Message& prototype) |
||||
: FieldOffset(proto2_f, r) { |
||||
// "prototype" isn't guaranteed to be empty, so we create a copy to get
|
||||
// the default string instance.
|
||||
goog::Message* empty = prototype.New(); |
||||
prototype_ = &r->GetStringReference(*empty, proto2_f, NULL); |
||||
delete empty; |
||||
} |
||||
|
||||
const T* prototype() const { return prototype_; } |
||||
|
||||
T** GetStringPointer(void *message) const { |
||||
return GetFieldPointer<T*>(message); |
||||
} |
||||
|
||||
private: |
||||
const T* prototype_; |
||||
}; |
||||
|
||||
template <typename T> static void SetStringHandlers( |
||||
const goog::FieldDescriptor* proto2_f, |
||||
const goog::Message& m, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, |
||||
upb::Handlers* h) { |
||||
h->SetStringHandler(f, &OnStringBuf<T>, NULL, NULL); |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetStartStringHandler(f, &StartRepeatedString<T>, NULL, NULL); |
||||
} else { |
||||
StringHandlerData<T>* data = new StringHandlerData<T>(proto2_f, r, m); |
||||
h->SetStartStringHandler( |
||||
f, &StartString<T>, data, &upb::DeletePointer<StringHandlerData<T> >); |
||||
} |
||||
} |
||||
|
||||
// This needs to be templated because google3 string is not std::string.
|
||||
template <typename T> static void* StartString( |
||||
void *m, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
const StringHandlerData<T>* data = |
||||
static_cast<const StringHandlerData<T>*>(fval); |
||||
T** str = data->GetStringPointer(m); |
||||
data->SetHasbit(m); |
||||
// If it points to the default instance, we must create a new instance.
|
||||
if (*str == data->prototype()) *str = new T(); |
||||
(*str)->clear(); |
||||
// reserve() here appears to hurt performance rather than help.
|
||||
return *str; |
||||
} |
||||
|
||||
template <typename T> static size_t OnStringBuf( |
||||
void *_str, void *fval, const char *buf, size_t n) { |
||||
UPB_UNUSED(fval); |
||||
T* str = static_cast<T*>(_str); |
||||
str->append(buf, n); |
||||
return n; |
||||
} |
||||
|
||||
|
||||
template <typename T> |
||||
static void* StartRepeatedString(void *_r, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
UPB_UNUSED(fval); |
||||
goog::RepeatedPtrField<T>* r = static_cast<goog::RepeatedPtrField<T>*>(_r); |
||||
T* str = r->Add(); |
||||
str->clear(); |
||||
// reserve() here appears to hurt performance rather than help.
|
||||
return str; |
||||
} |
||||
|
||||
// SubMessage ////////////////////////////////////////////////////////////////
|
||||
|
||||
class SubMessageHandlerData : public FieldOffset { |
||||
public: |
||||
SubMessageHandlerData( |
||||
const goog::FieldDescriptor* f, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const goog::Message* prototype) |
||||
: FieldOffset(f, r), |
||||
prototype_(prototype) { |
||||
} |
||||
|
||||
const goog::Message* prototype() const { return prototype_; } |
||||
|
||||
private: |
||||
const goog::Message* const prototype_; |
||||
}; |
||||
|
||||
static void SetSubMessageHandlers( |
||||
const goog::FieldDescriptor* proto2_f, |
||||
const goog::Message& m, |
||||
const goog::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, |
||||
upb::Handlers* h) { |
||||
SubMessageHandlerData* data = |
||||
new SubMessageHandlerData(proto2_f, r, GetFieldPrototype(m, proto2_f)); |
||||
upb::Handlers::Free* free = &upb::DeletePointer<SubMessageHandlerData>; |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetStartSubMessageHandler(f, &StartRepeatedSubMessage, data, free); |
||||
} else { |
||||
h->SetStartSubMessageHandler(f, &StartSubMessage, data, free); |
||||
} |
||||
} |
||||
|
||||
static void* StartSubMessage(void *m, void *fval) { |
||||
const SubMessageHandlerData* data = |
||||
static_cast<const SubMessageHandlerData*>(fval); |
||||
data->SetHasbit(m); |
||||
goog::Message **subm = data->GetFieldPointer<goog::Message*>(m); |
||||
if (*subm == NULL || *subm == data->prototype()) { |
||||
*subm = data->prototype()->New(); |
||||
} |
||||
return *subm; |
||||
} |
||||
|
||||
class RepeatedMessageTypeHandler { |
||||
public: |
||||
typedef void Type; |
||||
// AddAllocated() calls this, but only if other objects are sitting
|
||||
// around waiting for reuse, which we will not do.
|
||||
static void Delete(Type* t) { |
||||
(void)t; |
||||
assert(false); |
||||
} |
||||
}; |
||||
|
||||
// Closure is a RepeatedPtrField<SubMessageType>*, but we access it through
|
||||
// its base class RepeatedPtrFieldBase*.
|
||||
static void* StartRepeatedSubMessage(void* _r, void *fval) { |
||||
const SubMessageHandlerData* data = |
||||
static_cast<const SubMessageHandlerData*>(fval); |
||||
goog::internal::RepeatedPtrFieldBase *r = |
||||
static_cast<goog::internal::RepeatedPtrFieldBase*>(_r); |
||||
void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); |
||||
if (!submsg) { |
||||
submsg = data->prototype()->New(); |
||||
r->AddAllocated<RepeatedMessageTypeHandler>(submsg); |
||||
} |
||||
return submsg; |
||||
} |
||||
|
||||
// TODO(haberman): handle Extensions, Unknown Fields.
|
||||
|
||||
#ifdef UPB_GOOGLE3 |
||||
// Handlers for types/features only included in internal proto2 release:
|
||||
// Cord, StringPiece, LazyField, and MessageSet.
|
||||
// TODO(haberman): LazyField, MessageSet.
|
||||
|
||||
// Cord //////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void SetCordHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
h->SetStringHandler(f, &OnCordBuf, NULL, NULL); |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetStartStringHandler(f, &StartRepeatedCord, NULL, NULL); |
||||
} else { |
||||
h->SetStartStringHandler( |
||||
f, &StartCord, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset*>); |
||||
} |
||||
} |
||||
|
||||
static void* StartCord(void *m, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
const FieldOffset* offset = static_cast<const FieldOffset*>(fval); |
||||
offset->SetHasbit(m); |
||||
Cord* field = offset->GetFieldPointer<Cord>(m); |
||||
field->Clear(); |
||||
return field; |
||||
} |
||||
|
||||
static size_t OnCordBuf(void *_c, void *fval, const char *buf, size_t n) { |
||||
UPB_UNUSED(fval); |
||||
Cord* c = static_cast<Cord*>(_c); |
||||
c->Append(StringPiece(buf, n)); |
||||
return n; |
||||
} |
||||
|
||||
static void* StartRepeatedCord(void *_r, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
UPB_UNUSED(fval); |
||||
proto2::RepeatedField<Cord>* r = |
||||
static_cast<proto2::RepeatedField<Cord>*>(_r); |
||||
return r->Add(); |
||||
} |
||||
|
||||
// StringPiece ///////////////////////////////////////////////////////////////
|
||||
|
||||
static void SetStringPieceHandlers( |
||||
const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::internal::GeneratedMessageReflection* r, |
||||
const upb::FieldDef* f, upb::Handlers* h) { |
||||
h->SetStringHandler(f, &OnStringPieceBuf, NULL, NULL); |
||||
if (f->IsSequence()) { |
||||
SetStartSequenceHandler(proto2_f, r, f, h); |
||||
h->SetStartStringHandler(f, &StartRepeatedStringPiece, NULL, NULL); |
||||
} else { |
||||
h->SetStartStringHandler( |
||||
f, &StartStringPiece, new FieldOffset(proto2_f, r), |
||||
&upb::DeletePointer<FieldOffset*>); |
||||
} |
||||
} |
||||
|
||||
static size_t OnStringPieceBuf(void *_f, void *fval, |
||||
const char *buf, size_t len) { |
||||
UPB_UNUSED(fval); |
||||
// TODO(haberman): alias if possible and enabled on the input stream.
|
||||
// TODO(haberman): add a method to StringPieceField that lets us avoid
|
||||
// this copy/malloc/free.
|
||||
proto2::internal::StringPieceField* field = |
||||
static_cast<proto2::internal::StringPieceField*>(_f); |
||||
size_t new_len = field->size() + len; |
||||
char *data = new char[new_len]; |
||||
memcpy(data, field->data(), field->size()); |
||||
memcpy(data + field->size(), buf, len); |
||||
field->CopyFrom(StringPiece(data, new_len)); |
||||
delete[] data; |
||||
return len; |
||||
} |
||||
|
||||
static void* StartStringPiece(void *m, void *fval, size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
const FieldOffset* offset = static_cast<const FieldOffset*>(fval); |
||||
offset->SetHasbit(m); |
||||
proto2::internal::StringPieceField* field = |
||||
offset->GetFieldPointer<proto2::internal::StringPieceField>(m); |
||||
field->Clear(); |
||||
return field; |
||||
} |
||||
|
||||
static void* StartRepeatedStringPiece(void* _r, void *fval, |
||||
size_t size_hint) { |
||||
UPB_UNUSED(size_hint); |
||||
UPB_UNUSED(fval); |
||||
typedef proto2::RepeatedPtrField<proto2::internal::StringPieceField> |
||||
RepeatedStringPiece; |
||||
RepeatedStringPiece* r = static_cast<RepeatedStringPiece*>(_r); |
||||
proto2::internal::StringPieceField* field = r->Add(); |
||||
field->Clear(); |
||||
return field; |
||||
} |
||||
|
||||
#endif // UPB_GOOGLE3
|
||||
}; |
||||
|
||||
namespace upb { |
||||
namespace google { |
||||
|
||||
bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, |
||||
const goog::Message& prototype, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h) { |
||||
return me::FieldAccessor::TrySet(proto2_f, prototype, upb_f, h); |
||||
} |
||||
|
||||
const goog::Message* GetFieldPrototype( |
||||
const goog::Message& m, |
||||
const goog::FieldDescriptor* f) { |
||||
return me::FieldAccessor::GetFieldPrototype(m, f); |
||||
} |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
@ -0,0 +1,62 @@ |
||||
//
|
||||
// upb - a minimalist implementation of protocol buffers.
|
||||
//
|
||||
// Copyright (c) 2011-2012 Google Inc. See LICENSE for details.
|
||||
// Author: Josh Haberman <jhaberman@gmail.com>
|
||||
//
|
||||
// Support for registering field handlers that can write into a proto2
|
||||
// message that uses GeneratedMessageReflection (which includes all messages
|
||||
// generated by the proto2 compiler as well as DynamicMessage).
|
||||
//
|
||||
// This is a low-level interface; the high-level interface in google.h is
|
||||
// more user-friendly.
|
||||
|
||||
#ifndef UPB_GOOGLE_PROTO2_H_ |
||||
#define UPB_GOOGLE_PROTO2_H_ |
||||
|
||||
namespace proto2 { |
||||
class FieldDescriptor; |
||||
class Message; |
||||
} |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class FieldDescriptor; |
||||
class Message; |
||||
} |
||||
} |
||||
|
||||
namespace upb { |
||||
class FieldDef; |
||||
class Handlers; |
||||
} |
||||
|
||||
namespace upb { |
||||
namespace google { |
||||
|
||||
// Sets field handlers in the given Handlers object for writing to a single
|
||||
// field (as described by "proto2_f" and "upb_f") into a message constructed
|
||||
// by the same factory as "prototype." Returns true if this was successful
|
||||
// (this will fail if "prototype" is not a proto1 message, or if we can't
|
||||
// handle it for some reason).
|
||||
bool TrySetWriteHandlers(const proto2::FieldDescriptor* proto2_f, |
||||
const proto2::Message& prototype, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h); |
||||
bool TrySetWriteHandlers(const ::google::protobuf::FieldDescriptor* proto2_f, |
||||
const ::google::protobuf::Message& prototype, |
||||
const upb::FieldDef* upb_f, upb::Handlers* h); |
||||
|
||||
// Returns a prototype for the given field in "m", if it is weak. The returned
|
||||
// message could be the linked-in message type or OpaqueMessage, if the weak
|
||||
// message is *not* linked in. Otherwise returns NULL.
|
||||
const proto2::Message* GetFieldPrototype( |
||||
const proto2::Message& m, |
||||
const proto2::FieldDescriptor* f); |
||||
const ::google::protobuf::Message* GetFieldPrototype( |
||||
const ::google::protobuf::Message& m, |
||||
const ::google::protobuf::FieldDescriptor* f); |
||||
|
||||
} // namespace google
|
||||
} // namespace upb
|
||||
|
||||
#endif // UPB_GOOGLE_PROTO2_H_
|
@ -1,292 +1,385 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2011 Google Inc. See LICENSE for details. |
||||
* Copyright (c) 2011-2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include "upb/handlers.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
// Defined for the sole purpose of having a unique pointer value for
|
||||
// UPB_NO_CLOSURE.
|
||||
char _upb_noclosure; |
||||
|
||||
typedef struct { |
||||
upb_func *handler; |
||||
|
||||
// Could put either or both of these in a separate table to save memory when
|
||||
// they are sparse.
|
||||
void *data; |
||||
upb_handlerfree *cleanup; |
||||
|
||||
// TODO(haberman): this is wasteful; only the first "fieldhandler" of a
|
||||
// submessage field needs this. To reduce memory footprint we should either:
|
||||
// - put the subhandlers in a separate "fieldhandler", stored as part of
|
||||
// a union with one of the above fields.
|
||||
// - count selector offsets by individual pointers instead of by whole
|
||||
// fieldhandlers.
|
||||
const upb_handlers *subhandlers; |
||||
} fieldhandler; |
||||
|
||||
static const fieldhandler *getfh( |
||||
const upb_handlers *h, upb_selector_t selector) { |
||||
assert(selector < upb_handlers_msgdef(h)->selector_count); |
||||
fieldhandler* fhbase = (void*)&h->fh_base; |
||||
return &fhbase[selector]; |
||||
} |
||||
|
||||
/* upb_mhandlers **************************************************************/ |
||||
static fieldhandler *getfh_mutable(upb_handlers *h, upb_selector_t selector) { |
||||
return (fieldhandler*)getfh(h, selector); |
||||
} |
||||
|
||||
static upb_mhandlers *upb_mhandlers_new(void) { |
||||
upb_mhandlers *m = malloc(sizeof(*m)); |
||||
upb_inttable_init(&m->fieldtab); |
||||
m->startmsg = NULL; |
||||
m->endmsg = NULL; |
||||
m->is_group = false; |
||||
#ifdef UPB_USE_JIT_X64 |
||||
m->tablearray = NULL; |
||||
#endif |
||||
return m; |
||||
bool upb_handlers_isfrozen(const upb_handlers *h) { |
||||
return upb_refcounted_isfrozen(upb_upcast(h)); |
||||
} |
||||
|
||||
static upb_fhandlers *_upb_mhandlers_newfhandlers(upb_mhandlers *m, uint32_t n, |
||||
upb_fieldtype_t type, |
||||
bool repeated) { |
||||
const upb_value *v = upb_inttable_lookup(&m->fieldtab, n); |
||||
// TODO: design/refine the API for changing the set of fields or modifying
|
||||
// existing handlers.
|
||||
if (v) return NULL; |
||||
upb_fhandlers new_f = {type, repeated, 0, |
||||
n, -1, m, NULL, UPB_NO_VALUE, NULL, NULL, NULL, NULL, NULL, |
||||
#ifdef UPB_USE_JIT_X64 |
||||
0, 0, 0, |
||||
#endif |
||||
}; |
||||
upb_fhandlers *ptr = malloc(sizeof(*ptr)); |
||||
memcpy(ptr, &new_f, sizeof(upb_fhandlers)); |
||||
upb_inttable_insert(&m->fieldtab, n, upb_value_ptr(ptr)); |
||||
return ptr; |
||||
uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { |
||||
return upb_fielddef_isseq(f) ? 2 : 0; |
||||
} |
||||
|
||||
upb_fhandlers *upb_mhandlers_newfhandlers(upb_mhandlers *m, uint32_t n, |
||||
upb_fieldtype_t type, bool repeated) { |
||||
assert(type != UPB_TYPE(MESSAGE)); |
||||
assert(type != UPB_TYPE(GROUP)); |
||||
return _upb_mhandlers_newfhandlers(m, n, type, repeated); |
||||
uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { |
||||
uint32_t ret = 1; |
||||
if (upb_fielddef_isstring(f)) ret += 2; // STARTSTR/ENDSTR
|
||||
if (upb_fielddef_isseq(f)) ret += 2; // STARTSEQ/ENDSEQ
|
||||
if (upb_fielddef_issubmsg(f)) ret += 2; // STARTSUBMSG/ENDSUBMSG
|
||||
return ret; |
||||
} |
||||
|
||||
upb_fhandlers *upb_mhandlers_newfhandlers_subm(upb_mhandlers *m, uint32_t n, |
||||
upb_fieldtype_t type, |
||||
bool repeated, |
||||
upb_mhandlers *subm) { |
||||
assert(type == UPB_TYPE(MESSAGE) || type == UPB_TYPE(GROUP)); |
||||
assert(subm); |
||||
upb_fhandlers *f = _upb_mhandlers_newfhandlers(m, n, type, repeated); |
||||
if (!f) return NULL; |
||||
f->submsg = subm; |
||||
if (type == UPB_TYPE(GROUP)) |
||||
_upb_mhandlers_newfhandlers(subm, n, UPB_TYPE_ENDGROUP, false); |
||||
return f; |
||||
upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) { |
||||
switch (upb_fielddef_type(f)) { |
||||
case UPB_TYPE_INT32: |
||||
case UPB_TYPE_SINT32: |
||||
case UPB_TYPE_SFIXED32: |
||||
case UPB_TYPE_ENUM: |
||||
return UPB_HANDLER_INT32; |
||||
case UPB_TYPE_INT64: |
||||
case UPB_TYPE_SINT64: |
||||
case UPB_TYPE_SFIXED64: |
||||
return UPB_HANDLER_INT64; |
||||
case UPB_TYPE_UINT32: |
||||
case UPB_TYPE_FIXED32: |
||||
return UPB_HANDLER_UINT32; |
||||
case UPB_TYPE_UINT64: |
||||
case UPB_TYPE_FIXED64: |
||||
return UPB_HANDLER_UINT64; |
||||
case UPB_TYPE_FLOAT: |
||||
return UPB_HANDLER_FLOAT; |
||||
case UPB_TYPE_DOUBLE: |
||||
return UPB_HANDLER_DOUBLE; |
||||
case UPB_TYPE_BOOL: |
||||
return UPB_HANDLER_BOOL; |
||||
default: assert(false); return -1; // Invalid input.
|
||||
} |
||||
} |
||||
|
||||
upb_fhandlers *upb_mhandlers_lookup(const upb_mhandlers *m, uint32_t n) { |
||||
const upb_value *v = upb_inttable_lookup(&m->fieldtab, n); |
||||
return v ? upb_value_getptr(*v) : NULL; |
||||
bool upb_getselector( |
||||
const upb_fielddef *f, upb_handlertype_t type, upb_selector_t *s) { |
||||
// If the type checks in this function are a hot-spot, we can introduce a
|
||||
// separate function that calculates the selector assuming that the type
|
||||
// is correct (may even want to make it inline for the upb_sink fast-path.
|
||||
switch (type) { |
||||
case UPB_HANDLER_INT32: |
||||
case UPB_HANDLER_INT64: |
||||
case UPB_HANDLER_UINT32: |
||||
case UPB_HANDLER_UINT64: |
||||
case UPB_HANDLER_FLOAT: |
||||
case UPB_HANDLER_DOUBLE: |
||||
case UPB_HANDLER_BOOL: |
||||
if (!upb_fielddef_isprimitive(f) || |
||||
upb_handlers_getprimitivehandlertype(f) != type) |
||||
return false; |
||||
*s = f->selector_base; |
||||
break; |
||||
case UPB_HANDLER_STARTSTR: |
||||
if (!upb_fielddef_isstring(f)) return false; |
||||
*s = f->selector_base; |
||||
break; |
||||
case UPB_HANDLER_STRING: |
||||
if (!upb_fielddef_isstring(f)) return false; |
||||
*s = f->selector_base + 1; |
||||
break; |
||||
case UPB_HANDLER_ENDSTR: |
||||
if (!upb_fielddef_isstring(f)) return false; |
||||
*s = f->selector_base + 2; |
||||
break; |
||||
case UPB_HANDLER_STARTSEQ: |
||||
if (!upb_fielddef_isseq(f)) return false; |
||||
*s = f->selector_base - 2; |
||||
break; |
||||
case UPB_HANDLER_ENDSEQ: |
||||
if (!upb_fielddef_isseq(f)) return false; |
||||
*s = f->selector_base - 1; |
||||
break; |
||||
case UPB_HANDLER_STARTSUBMSG: |
||||
if (!upb_fielddef_issubmsg(f)) return false; |
||||
*s = f->selector_base + 1; |
||||
break; |
||||
case UPB_HANDLER_ENDSUBMSG: |
||||
if (!upb_fielddef_issubmsg(f)) return false; |
||||
*s = f->selector_base + 2; |
||||
break; |
||||
} |
||||
assert(*s < upb_fielddef_msgdef(f)->selector_count); |
||||
return true; |
||||
} |
||||
|
||||
void upb_handlers_ref(const upb_handlers *h, const void *owner) { |
||||
upb_refcounted_ref(upb_upcast(h), owner); |
||||
} |
||||
|
||||
/* upb_handlers ***************************************************************/ |
||||
void upb_handlers_unref(const upb_handlers *h, const void *owner) { |
||||
upb_refcounted_unref(upb_upcast(h), owner); |
||||
} |
||||
|
||||
upb_handlers *upb_handlers_new() { |
||||
upb_handlers *h = malloc(sizeof(*h)); |
||||
h->refcount = 1; |
||||
h->msgs_len = 0; |
||||
h->msgs_size = 4; |
||||
h->msgs = malloc(h->msgs_size * sizeof(*h->msgs)); |
||||
h->should_jit = true; |
||||
return h; |
||||
void upb_handlers_donateref( |
||||
const upb_handlers *h, const void *from, const void *to) { |
||||
upb_refcounted_donateref(upb_upcast(h), from, to); |
||||
} |
||||
|
||||
void upb_handlers_ref(upb_handlers *h) { h->refcount++; } |
||||
|
||||
void upb_handlers_unref(upb_handlers *h) { |
||||
if (--h->refcount == 0) { |
||||
for (int i = 0; i < h->msgs_len; i++) { |
||||
upb_mhandlers *mh = h->msgs[i]; |
||||
upb_inttable_iter j; |
||||
upb_inttable_begin(&j, &mh->fieldtab); |
||||
for(; !upb_inttable_done(&j); upb_inttable_next(&j)) { |
||||
free(upb_value_getptr(upb_inttable_iter_value(&j))); |
||||
} |
||||
upb_inttable_uninit(&mh->fieldtab); |
||||
#ifdef UPB_USE_JIT_X64 |
||||
free(mh->tablearray); |
||||
#endif |
||||
free(mh); |
||||
} |
||||
free(h->msgs); |
||||
free(h); |
||||
} |
||||
void upb_handlers_checkref(const upb_handlers *h, const void *owner) { |
||||
upb_refcounted_checkref(upb_upcast(h), owner); |
||||
} |
||||
|
||||
static void do_cleanup(upb_handlers* h, const upb_fielddef *f, |
||||
upb_handlertype_t type) { |
||||
upb_selector_t selector; |
||||
if (!upb_getselector(f, type, &selector)) return; |
||||
fieldhandler *fh = getfh_mutable(h, selector); |
||||
if (fh->cleanup) fh->cleanup(fh->data); |
||||
fh->cleanup = NULL; |
||||
fh->data = NULL; |
||||
} |
||||
|
||||
upb_mhandlers *upb_handlers_newmhandlers(upb_handlers *h) { |
||||
if (h->msgs_len == h->msgs_size) { |
||||
h->msgs_size *= 2; |
||||
h->msgs = realloc(h->msgs, h->msgs_size * sizeof(*h->msgs)); |
||||
static void freehandlers(upb_refcounted *r) { |
||||
upb_handlers *h = (upb_handlers*)r; |
||||
upb_msg_iter i; |
||||
for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) { |
||||
upb_fielddef *f = upb_msg_iter_field(&i); |
||||
for (upb_handlertype_t type = 0; type < UPB_HANDLER_MAX; type++) |
||||
do_cleanup(h, f, type); |
||||
} |
||||
upb_mhandlers *mh = upb_mhandlers_new(); |
||||
h->msgs[h->msgs_len++] = mh; |
||||
return mh; |
||||
upb_msgdef_unref(h->msg, h); |
||||
free(h); |
||||
} |
||||
|
||||
static upb_mhandlers *upb_regmsg_dfs(upb_handlers *h, const upb_msgdef *m, |
||||
upb_onmsgreg *msgreg_cb, |
||||
upb_onfieldreg *fieldreg_cb, |
||||
void *closure, upb_strtable *mtab) { |
||||
upb_mhandlers *mh = upb_handlers_newmhandlers(h); |
||||
upb_strtable_insert(mtab, upb_def_fullname(UPB_UPCAST(m)), upb_value_ptr(mh)); |
||||
if (msgreg_cb) msgreg_cb(closure, mh, m); |
||||
static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, |
||||
void *closure) { |
||||
const upb_handlers *h = (const upb_handlers*)r; |
||||
upb_msg_iter i; |
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { |
||||
for(upb_msg_begin(&i, h->msg); !upb_msg_done(&i); upb_msg_next(&i)) { |
||||
upb_fielddef *f = upb_msg_iter_field(&i); |
||||
upb_fhandlers *fh; |
||||
if (upb_issubmsg(f)) { |
||||
upb_mhandlers *sub_mh; |
||||
const upb_value *subm_ent; |
||||
// The table lookup is necessary to break the DFS for type cycles.
|
||||
const char *subname = upb_def_fullname(upb_fielddef_subdef(f)); |
||||
if ((subm_ent = upb_strtable_lookup(mtab, subname)) != NULL) { |
||||
sub_mh = upb_value_getptr(*subm_ent); |
||||
} else { |
||||
sub_mh = upb_regmsg_dfs( |
||||
h, upb_downcast_msgdef_const(upb_fielddef_subdef(f)), |
||||
msgreg_cb, fieldreg_cb, closure, mtab); |
||||
} |
||||
fh = upb_mhandlers_newfhandlers_subm( |
||||
mh, f->number, f->type, upb_isseq(f), sub_mh); |
||||
} else { |
||||
fh = upb_mhandlers_newfhandlers(mh, f->number, f->type, upb_isseq(f)); |
||||
} |
||||
if (fieldreg_cb) fieldreg_cb(closure, fh, f); |
||||
if (!upb_fielddef_issubmsg(f)) continue; |
||||
const upb_handlers *sub = upb_handlers_getsubhandlers(h, f); |
||||
if (sub) visit(r, upb_upcast(sub), closure); |
||||
} |
||||
return mh; |
||||
} |
||||
|
||||
upb_mhandlers *upb_handlers_regmsgdef(upb_handlers *h, const upb_msgdef *m, |
||||
upb_onmsgreg *msgreg_cb, |
||||
upb_onfieldreg *fieldreg_cb, |
||||
void *closure) { |
||||
upb_strtable mtab; |
||||
upb_strtable_init(&mtab); |
||||
upb_mhandlers *ret = |
||||
upb_regmsg_dfs(h, m, msgreg_cb, fieldreg_cb, closure, &mtab); |
||||
upb_strtable_uninit(&mtab); |
||||
return ret; |
||||
upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { |
||||
assert(upb_msgdef_isfrozen(md)); |
||||
static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers}; |
||||
size_t fhandlers_size = sizeof(fieldhandler) * md->selector_count; |
||||
upb_handlers *h = calloc(sizeof(*h) - sizeof(void*) + fhandlers_size, 1); |
||||
if (!h) return NULL; |
||||
h->msg = md; |
||||
upb_msgdef_ref(h->msg, h); |
||||
if (!upb_refcounted_init(upb_upcast(h), &vtbl, owner)) goto oom; |
||||
|
||||
// calloc() above initialized all handlers to NULL.
|
||||
return h; |
||||
|
||||
oom: |
||||
freehandlers(upb_upcast(h)); |
||||
return NULL; |
||||
} |
||||
|
||||
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { |
||||
// TODO: verify we have a transitive closure.
|
||||
return upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s); |
||||
} |
||||
|
||||
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } |
||||
|
||||
/* upb_dispatcher *************************************************************/ |
||||
|
||||
void upb_dispatcher_init(upb_dispatcher *d, upb_status *status, |
||||
upb_exit_handler UPB_NORETURN *exit, |
||||
void *srcclosure) { |
||||
d->stack[0].f = NULL; // Should never be read.
|
||||
d->limit = &d->stack[UPB_MAX_NESTING]; |
||||
d->exitjmp = exit; |
||||
d->srcclosure = srcclosure; |
||||
d->top_is_implicit = false; |
||||
d->msgent = NULL; |
||||
d->top = NULL; |
||||
d->toplevel_msgent = NULL; |
||||
d->status = status; |
||||
void upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handler *handler) { |
||||
assert(!upb_handlers_isfrozen(h)); |
||||
h->startmsg = handler; |
||||
} |
||||
|
||||
upb_dispatcher_frame *upb_dispatcher_reset(upb_dispatcher *d, void *closure, |
||||
upb_mhandlers *top) { |
||||
d->msgent = top; |
||||
d->toplevel_msgent = top; |
||||
d->top = d->stack; |
||||
d->top->closure = closure; |
||||
d->top->is_sequence = false; |
||||
d->top->is_packed = false; |
||||
return d->top; |
||||
upb_startmsg_handler *upb_handlers_getstartmsg(const upb_handlers *h) { |
||||
return h->startmsg; |
||||
} |
||||
|
||||
void upb_dispatcher_uninit(upb_dispatcher *d) { |
||||
(void)d; |
||||
void upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handler *handler) { |
||||
assert(!upb_handlers_isfrozen(h)); |
||||
h->endmsg = handler; |
||||
} |
||||
|
||||
void upb_dispatch_startmsg(upb_dispatcher *d) { |
||||
upb_flow_t flow = UPB_CONTINUE; |
||||
if (d->msgent->startmsg) d->msgent->startmsg(d->top->closure); |
||||
if (flow != UPB_CONTINUE) _upb_dispatcher_abortjmp(d); |
||||
upb_endmsg_handler *upb_handlers_getendmsg(const upb_handlers *h) { |
||||
return h->endmsg; |
||||
} |
||||
|
||||
void upb_dispatch_endmsg(upb_dispatcher *d, upb_status *status) { |
||||
assert(d->top == d->stack); |
||||
if (d->msgent->endmsg) d->msgent->endmsg(d->top->closure, d->status); |
||||
// TODO: should we avoid this copy by passing client's status obj to cbs?
|
||||
upb_status_copy(status, d->status); |
||||
// For now we stuff the subhandlers pointer into the fieldhandlers*
|
||||
// corresponding to the UPB_HANDLER_STARTSUBMSG handler.
|
||||
static const upb_handlers **subhandlersptr(upb_handlers *h, |
||||
const upb_fielddef *f) { |
||||
assert(upb_fielddef_issubmsg(f)); |
||||
upb_selector_t selector; |
||||
bool ok = upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector); |
||||
UPB_ASSERT_VAR(ok, ok); |
||||
return &getfh_mutable(h, selector)->subhandlers; |
||||
} |
||||
|
||||
upb_dispatcher_frame *upb_dispatch_startseq(upb_dispatcher *d, |
||||
upb_fhandlers *f) { |
||||
if (d->top + 1 >= d->limit) { |
||||
upb_status_seterrliteral(d->status, "Nesting too deep."); |
||||
_upb_dispatcher_abortjmp(d); |
||||
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, |
||||
const upb_handlers *sub) { |
||||
assert(!upb_handlers_isfrozen(h)); |
||||
if (!upb_fielddef_issubmsg(f)) return false; |
||||
if (sub != NULL && |
||||
upb_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { |
||||
return false; |
||||
} |
||||
const upb_handlers **stored = subhandlersptr(h, f); |
||||
const upb_handlers *old = *stored; |
||||
if (old) upb_unref2(old, h); |
||||
*stored = sub; |
||||
if (sub) upb_ref2(sub, h); |
||||
return true; |
||||
} |
||||
|
||||
upb_sflow_t sflow = UPB_CONTINUE_WITH(d->top->closure); |
||||
if (f->startseq) sflow = f->startseq(d->top->closure, f->fval); |
||||
_upb_dispatcher_sethas(d->top->closure, f->hasbit); |
||||
if (sflow.flow != UPB_CONTINUE) { |
||||
_upb_dispatcher_abortjmp(d); |
||||
} |
||||
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, |
||||
const upb_fielddef *f) { |
||||
const upb_handlers **stored = subhandlersptr((upb_handlers*)h, f); |
||||
return *stored; |
||||
} |
||||
|
||||
++d->top; |
||||
d->top->f = f; |
||||
d->top->is_sequence = true; |
||||
d->top->is_packed = false; |
||||
d->top->closure = sflow.closure; |
||||
return d->top; |
||||
#define SETTER(name, handlerctype, handlertype) \ |
||||
bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
|
||||
handlerctype val, void *data, \
|
||||
upb_handlerfree *cleanup) { \
|
||||
assert(!upb_handlers_isfrozen(h)); \
|
||||
if (upb_handlers_msgdef(h) != upb_fielddef_msgdef(f)) return false; \
|
||||
upb_selector_t selector; \
|
||||
bool ok = upb_getselector(f, handlertype, &selector); \
|
||||
if (!ok) return false; \
|
||||
do_cleanup(h, f, handlertype); \
|
||||
fieldhandler *fh = getfh_mutable(h, selector); \
|
||||
fh->handler = (upb_func*)val; \
|
||||
fh->data = (upb_func*)data; \
|
||||
fh->cleanup = (upb_func*)cleanup; \
|
||||
return true; \
|
||||
} \
|
||||
|
||||
SETTER(int32, upb_int32_handler*, UPB_HANDLER_INT32); |
||||
SETTER(int64, upb_int64_handler*, UPB_HANDLER_INT64); |
||||
SETTER(uint32, upb_uint32_handler*, UPB_HANDLER_UINT32); |
||||
SETTER(uint64, upb_uint64_handler*, UPB_HANDLER_UINT64); |
||||
SETTER(float, upb_float_handler*, UPB_HANDLER_FLOAT); |
||||
SETTER(double, upb_double_handler*, UPB_HANDLER_DOUBLE); |
||||
SETTER(bool, upb_bool_handler*, UPB_HANDLER_BOOL); |
||||
SETTER(startstr, upb_startstr_handler*, UPB_HANDLER_STARTSTR); |
||||
SETTER(string, upb_string_handler*, UPB_HANDLER_STRING); |
||||
SETTER(endstr, upb_endfield_handler*, UPB_HANDLER_ENDSTR); |
||||
SETTER(startseq, upb_startfield_handler*, UPB_HANDLER_STARTSEQ); |
||||
SETTER(startsubmsg, upb_startfield_handler*, UPB_HANDLER_STARTSUBMSG); |
||||
SETTER(endsubmsg, upb_endfield_handler*, UPB_HANDLER_ENDSUBMSG); |
||||
SETTER(endseq, upb_endfield_handler*, UPB_HANDLER_ENDSEQ); |
||||
#undef SETTER |
||||
|
||||
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s) { |
||||
return getfh(h, s)->handler; |
||||
} |
||||
|
||||
upb_dispatcher_frame *upb_dispatch_endseq(upb_dispatcher *d) { |
||||
assert(d->top > d->stack); |
||||
assert(d->top->is_sequence); |
||||
upb_fhandlers *f = d->top->f; |
||||
--d->top; |
||||
upb_flow_t flow = UPB_CONTINUE; |
||||
if (f->endseq) flow = f->endseq(d->top->closure, f->fval); |
||||
if (flow != UPB_CONTINUE) { |
||||
_upb_dispatcher_abortjmp(d); |
||||
} |
||||
d->msgent = d->top->f ? d->top->f->submsg : d->toplevel_msgent; |
||||
return d->top; |
||||
void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s) { |
||||
return getfh(h, s)->data; |
||||
} |
||||
|
||||
upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d, |
||||
upb_fhandlers *f) { |
||||
if (d->top + 1 >= d->limit) { |
||||
upb_status_seterrliteral(d->status, "Nesting too deep."); |
||||
_upb_dispatcher_abortjmp(d); |
||||
} |
||||
typedef struct { |
||||
upb_inttable tab; // maps upb_msgdef* -> upb_handlers*.
|
||||
upb_handlers_callback *callback; |
||||
void *closure; |
||||
} dfs_state; |
||||
|
||||
upb_sflow_t sflow = UPB_CONTINUE_WITH(d->top->closure); |
||||
if (f->startsubmsg) sflow = f->startsubmsg(d->top->closure, f->fval); |
||||
_upb_dispatcher_sethas(d->top->closure, f->hasbit); |
||||
if (sflow.flow != UPB_CONTINUE) { |
||||
_upb_dispatcher_abortjmp(d); |
||||
} |
||||
static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, |
||||
dfs_state *s) { |
||||
upb_handlers *h = upb_handlers_new(m, owner); |
||||
if (!h) return NULL; |
||||
if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; |
||||
|
||||
++d->top; |
||||
d->top->f = f; |
||||
d->top->is_sequence = false; |
||||
d->top->is_packed = false; |
||||
d->top->closure = sflow.closure; |
||||
d->msgent = f->submsg; |
||||
upb_dispatch_startmsg(d); |
||||
return d->top; |
||||
} |
||||
s->callback(s->closure, h); |
||||
|
||||
upb_dispatcher_frame *upb_dispatch_endsubmsg(upb_dispatcher *d) { |
||||
assert(d->top > d->stack); |
||||
assert(!d->top->is_sequence); |
||||
upb_fhandlers *f = d->top->f; |
||||
if (d->msgent->endmsg) d->msgent->endmsg(d->top->closure, d->status); |
||||
d->msgent = d->top->f->msg; |
||||
--d->top; |
||||
upb_flow_t flow = UPB_CONTINUE; |
||||
if (f->endsubmsg) f->endsubmsg(d->top->closure, f->fval); |
||||
if (flow != UPB_CONTINUE) _upb_dispatcher_abortjmp(d); |
||||
return d->top; |
||||
} |
||||
// For each submessage field, get or create a handlers object and set it as
|
||||
// the subhandlers.
|
||||
upb_msg_iter i; |
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { |
||||
upb_fielddef *f = upb_msg_iter_field(&i); |
||||
if (!upb_fielddef_issubmsg(f)) continue; |
||||
|
||||
bool upb_dispatcher_stackempty(upb_dispatcher *d) { |
||||
return d->top == d->stack; |
||||
} |
||||
bool upb_dispatcher_islegalend(upb_dispatcher *d) { |
||||
if (d->top == d->stack) return true; |
||||
if (d->top - 1 == d->stack && |
||||
d->top->is_sequence && !d->top->is_packed) return true; |
||||
return false; |
||||
const upb_msgdef *subdef = upb_downcast_msgdef(upb_fielddef_subdef(f)); |
||||
const upb_value *subm_ent = upb_inttable_lookupptr(&s->tab, subdef); |
||||
if (subm_ent) { |
||||
upb_handlers_setsubhandlers(h, f, upb_value_getptr(*subm_ent)); |
||||
} else { |
||||
upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); |
||||
if (!sub_mh) goto oom; |
||||
upb_handlers_setsubhandlers(h, f, sub_mh); |
||||
upb_handlers_unref(sub_mh, &sub_mh); |
||||
} |
||||
} |
||||
return h; |
||||
|
||||
oom: |
||||
upb_handlers_unref(h, owner); |
||||
return NULL; |
||||
} |
||||
|
||||
void _upb_dispatcher_abortjmp(upb_dispatcher *d) { |
||||
d->exitjmp(d->srcclosure); |
||||
assert(false); // Never returns.
|
||||
const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, |
||||
const void *owner, |
||||
upb_handlers_callback *callback, |
||||
void *closure) { |
||||
dfs_state state; |
||||
state.callback = callback; |
||||
state.closure = closure; |
||||
if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL; |
||||
|
||||
upb_handlers *ret = newformsg(m, owner, &state); |
||||
if (!ret) return NULL; |
||||
upb_refcounted *r = upb_upcast(ret); |
||||
upb_status status = UPB_STATUS_INIT; |
||||
bool ok = upb_refcounted_freeze(&r, 1, &status); |
||||
UPB_ASSERT_VAR(ok, ok); |
||||
upb_status_uninit(&status); |
||||
|
||||
upb_inttable_uninit(&state.tab); |
||||
return ret; |
||||
} |
||||
|
||||
#define STDMSG_WRITER(type, ctype) \ |
||||
bool upb_stdmsg_set ## type (void *_m, void *fval, ctype val) { \
|
||||
assert(_m != NULL); \
|
||||
const upb_stdmsg_fval *f = fval; \
|
||||
uint8_t *m = _m; \
|
||||
if (f->hasbit > 0) \
|
||||
*(uint8_t*)&m[f->hasbit / 8] |= 1 << (f->hasbit % 8); \
|
||||
*(ctype*)&m[f->offset] = val; \
|
||||
return true; \
|
||||
} \
|
||||
|
||||
STDMSG_WRITER(double, double) |
||||
STDMSG_WRITER(float, float) |
||||
STDMSG_WRITER(int32, int32_t) |
||||
STDMSG_WRITER(int64, int64_t) |
||||
STDMSG_WRITER(uint32, uint32_t) |
||||
STDMSG_WRITER(uint64, uint64_t) |
||||
STDMSG_WRITER(bool, bool) |
||||
#undef STDMSG_WRITER |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,52 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2010 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
*/ |
||||
|
||||
#include "upb/upb.h" |
||||
#include "upb/msg.h" |
||||
|
||||
#define UPB_ACCESSOR(type, ctype) \ |
||||
upb_flow_t upb_stdmsg_set ## type (void *_m, upb_value fval, \
|
||||
upb_value val) { \
|
||||
assert(_m != NULL); \
|
||||
const upb_fielddef *f = upb_value_getfielddef(fval); \
|
||||
uint8_t *m = _m; \
|
||||
/* Hasbit is set automatically by the handlers. */ \
|
||||
*(ctype*)&m[f->offset] = upb_value_get ## type(val); \
|
||||
return UPB_CONTINUE; \
|
||||
} \
|
||||
|
||||
UPB_ACCESSOR(double, double) |
||||
UPB_ACCESSOR(float, float) |
||||
UPB_ACCESSOR(int32, int32_t) |
||||
UPB_ACCESSOR(int64, int64_t) |
||||
UPB_ACCESSOR(uint32, uint32_t) |
||||
UPB_ACCESSOR(uint64, uint64_t) |
||||
UPB_ACCESSOR(bool, bool) |
||||
UPB_ACCESSOR(ptr, void*) |
||||
#undef UPB_ACCESSORS |
||||
|
||||
static void upb_accessors_onfreg(void *c, upb_fhandlers *fh, |
||||
const upb_fielddef *f) { |
||||
(void)c; |
||||
if (f->accessor) { |
||||
upb_fhandlers_setfval(fh, f->fval); |
||||
if (upb_isseq(f)) { |
||||
upb_fhandlers_setstartseq(fh, f->accessor->startseq); |
||||
upb_fhandlers_setvalue(fh, f->accessor->append); |
||||
upb_fhandlers_setstartsubmsg(fh, f->accessor->appendsubmsg); |
||||
} else { |
||||
upb_fhandlers_setvalue(fh, f->accessor->set); |
||||
upb_fhandlers_setstartsubmsg(fh, f->accessor->startsubmsg); |
||||
upb_fhandlers_sethasbit(fh, f->hasbit); |
||||
} |
||||
} |
||||
} |
||||
|
||||
upb_mhandlers *upb_accessors_reghandlers(upb_handlers *h, const upb_msgdef *m) { |
||||
return upb_handlers_regmsgdef(h, m, NULL, &upb_accessors_onfreg, NULL); |
||||
} |
@ -1,153 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2010-2011 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* Routines for reading and writing message data to an in-memory structure, |
||||
* similar to a C struct. |
||||
* |
||||
* upb does not define one single message object that everyone must use. |
||||
* Rather it defines an abstract interface for reading and writing members |
||||
* of a message object, and all of the parsers and serializers use this |
||||
* abstract interface. This allows upb's parsers and serializers to be used |
||||
* regardless of what memory management scheme or synchronization model the |
||||
* application is using. |
||||
* |
||||
* A standard set of accessors is provided for doing simple reads and writes at |
||||
* a known offset into the message. These accessors should be used when |
||||
* possible, because they are specially optimized -- for example, the JIT can |
||||
* recognize them and emit specialized code instead of having to call the |
||||
* function at all. The application can substitute its own accessors when the |
||||
* standard accessors are not suitable. |
||||
*/ |
||||
|
||||
#ifndef UPB_MSG_H |
||||
#define UPB_MSG_H |
||||
|
||||
#include <stdlib.h> |
||||
#include "upb/def.h" |
||||
#include "upb/handlers.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
|
||||
/* upb_accessor ***************************************************************/ |
||||
|
||||
// A upb_accessor is a table of function pointers for doing reads and writes
|
||||
// for one specific upb_fielddef. Each field has a separate accessor, which
|
||||
// lives in the fielddef.
|
||||
|
||||
typedef bool upb_has_reader(const void *m, upb_value fval); |
||||
typedef upb_value upb_value_reader(const void *m, upb_value fval); |
||||
|
||||
typedef const void *upb_seqbegin_handler(const void *s); |
||||
typedef const void *upb_seqnext_handler(const void *s, const void *iter); |
||||
typedef upb_value upb_seqget_handler(const void *iter); |
||||
INLINE bool upb_seq_done(const void *iter) { return iter == NULL; } |
||||
|
||||
typedef struct _upb_accessor_vtbl { |
||||
// Writers. These take an fval as a parameter because the callbacks are used
|
||||
// as upb_handlers, but the fval is always the fielddef for that field.
|
||||
upb_startfield_handler *startsubmsg; // Non-repeated submsg fields.
|
||||
upb_value_handler *set; // Non-repeated scalar fields.
|
||||
upb_startfield_handler *startseq; // Repeated fields only.
|
||||
upb_startfield_handler *appendsubmsg; // Repeated submsg fields.
|
||||
upb_value_handler *append; // Repeated scalar fields.
|
||||
|
||||
// TODO: expect to also need endsubmsg and endseq.
|
||||
|
||||
// Readers.
|
||||
upb_has_reader *has; |
||||
upb_value_reader *getseq; |
||||
upb_value_reader *get; |
||||
upb_seqbegin_handler *seqbegin; |
||||
upb_seqnext_handler *seqnext; |
||||
upb_seqget_handler *seqget; |
||||
} upb_accessor_vtbl; |
||||
|
||||
// Registers handlers for writing into a message of the given type using
|
||||
// whatever accessors it has defined.
|
||||
upb_mhandlers *upb_accessors_reghandlers(upb_handlers *h, const upb_msgdef *m); |
||||
|
||||
INLINE void upb_msg_clearbit(void *msg, const upb_fielddef *f) { |
||||
((char*)msg)[f->hasbit / 8] &= ~(1 << (f->hasbit % 8)); |
||||
} |
||||
|
||||
/* upb_msg/upb_seq ************************************************************/ |
||||
|
||||
// These accessor functions are simply convenience methods for reading or
|
||||
// writing to a message through its accessors.
|
||||
|
||||
INLINE bool upb_msg_has(const void *m, const upb_fielddef *f) { |
||||
return f->accessor && f->accessor->has(m, f->fval); |
||||
} |
||||
|
||||
// May only be called for fields that have accessors.
|
||||
INLINE upb_value upb_msg_get(const void *m, const upb_fielddef *f) { |
||||
assert(f->accessor && !upb_isseq(f)); |
||||
return f->accessor->get(m, f->fval); |
||||
} |
||||
|
||||
// May only be called for fields that have accessors.
|
||||
INLINE upb_value upb_msg_getseq(const void *m, const upb_fielddef *f) { |
||||
assert(f->accessor && upb_isseq(f)); |
||||
return f->accessor->getseq(m, f->fval); |
||||
} |
||||
|
||||
INLINE void upb_msg_set(void *m, const upb_fielddef *f, upb_value val) { |
||||
assert(f->accessor); |
||||
f->accessor->set(m, f->fval, val); |
||||
} |
||||
|
||||
INLINE const void *upb_seq_begin(const void *s, const upb_fielddef *f) { |
||||
assert(f->accessor); |
||||
return f->accessor->seqbegin(s); |
||||
} |
||||
INLINE const void *upb_seq_next(const void *s, const void *iter, |
||||
const upb_fielddef *f) { |
||||
assert(f->accessor); |
||||
assert(!upb_seq_done(iter)); |
||||
return f->accessor->seqnext(s, iter); |
||||
} |
||||
INLINE upb_value upb_seq_get(const void *iter, const upb_fielddef *f) { |
||||
assert(f->accessor); |
||||
assert(!upb_seq_done(iter)); |
||||
return f->accessor->seqget(iter); |
||||
} |
||||
|
||||
INLINE bool upb_msg_has_named(const void *m, const upb_msgdef *md, |
||||
const char *field_name) { |
||||
const upb_fielddef *f = upb_msgdef_ntof(md, field_name); |
||||
return f && upb_msg_has(m, f); |
||||
} |
||||
|
||||
INLINE bool upb_msg_get_named(const void *m, const upb_msgdef *md, |
||||
const char *field_name, upb_value *val) { |
||||
const upb_fielddef *f = upb_msgdef_ntof(md, field_name); |
||||
if (!f) return false; |
||||
*val = upb_msg_get(m, f); |
||||
return true; |
||||
} |
||||
|
||||
// Value writers for every in-memory type: write the data to a known offset
|
||||
// from the closure "c."
|
||||
//
|
||||
// TODO(haberman): instead of having standard writer functions, should we have
|
||||
// a bool in the accessor that says "write raw value to the field's offset"?
|
||||
upb_flow_t upb_stdmsg_setint64(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setint32(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setuint64(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setuint32(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setdouble(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setfloat(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setbool(void *c, upb_value fval, upb_value val); |
||||
upb_flow_t upb_stdmsg_setptr(void *c, upb_value fval, upb_value val); |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif |
@ -1,236 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include "upb/refcount.h" |
||||
|
||||
// TODO(haberman): require client to define these if ref debugging is on.
|
||||
#ifndef UPB_LOCK |
||||
#define UPB_LOCK |
||||
#endif |
||||
|
||||
#ifndef UPB_UNLOCK |
||||
#define UPB_UNLOCK |
||||
#endif |
||||
|
||||
/* arch-specific atomic primitives *******************************************/ |
||||
|
||||
#ifdef UPB_THREAD_UNSAFE //////////////////////////////////////////////////////
|
||||
|
||||
INLINE void upb_atomic_inc(uint32_t *a) { (*a)++; } |
||||
INLINE bool upb_atomic_dec(uint32_t *a) { return --(*a) == 0; } |
||||
|
||||
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4 ///////////////////
|
||||
|
||||
INLINE void upb_atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); } |
||||
INLINE bool upb_atomic_dec(uint32_t *a) { |
||||
return __sync_sub_and_fetch(a, 1) == 0; |
||||
} |
||||
|
||||
#elif defined(WIN32) ///////////////////////////////////////////////////////////
|
||||
|
||||
#include <Windows.h> |
||||
|
||||
INLINE void upb_atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); } |
||||
INLINE bool upb_atomic_dec(upb_atomic_t *a) { |
||||
return InterlockedDecrement(&a->val) == 0; |
||||
} |
||||
|
||||
#else |
||||
#error Atomic primitives not defined for your platform/CPU. \ |
||||
Implement them or compile with UPB_THREAD_UNSAFE. |
||||
#endif |
||||
|
||||
// Reserved index values.
|
||||
#define UPB_INDEX_UNDEFINED UINT16_MAX |
||||
#define UPB_INDEX_NOT_IN_STACK (UINT16_MAX - 1) |
||||
|
||||
static void upb_refcount_merge(upb_refcount *r, upb_refcount *from) { |
||||
if (upb_refcount_merged(r, from)) return; |
||||
*r->count += *from->count; |
||||
free(from->count); |
||||
upb_refcount *base = from; |
||||
|
||||
// Set all refcount pointers in the "from" chain to the merged refcount.
|
||||
do { from->count = r->count; } while ((from = from->next) != base); |
||||
|
||||
// Merge the two circularly linked lists by swapping their next pointers.
|
||||
upb_refcount *tmp = r->next; |
||||
r->next = base->next; |
||||
base->next = tmp; |
||||
} |
||||
|
||||
// Tarjan's algorithm, see:
|
||||
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
|
||||
typedef struct { |
||||
int index; |
||||
upb_refcount **stack; |
||||
int stack_len; |
||||
upb_getsuccessors *func; |
||||
} upb_tarjan_state; |
||||
|
||||
static void upb_refcount_dofindscc(upb_refcount *obj, upb_tarjan_state *state); |
||||
|
||||
void upb_refcount_visit(upb_refcount *obj, upb_refcount *subobj, void *_state) { |
||||
upb_tarjan_state *state = _state; |
||||
if (subobj->index == UPB_INDEX_UNDEFINED) { |
||||
// Subdef has not yet been visited; recurse on it.
|
||||
upb_refcount_dofindscc(subobj, state); |
||||
obj->lowlink = UPB_MIN(obj->lowlink, subobj->lowlink); |
||||
} else if (subobj->index != UPB_INDEX_NOT_IN_STACK) { |
||||
// Subdef is in the stack and hence in the current SCC.
|
||||
obj->lowlink = UPB_MIN(obj->lowlink, subobj->index); |
||||
} |
||||
} |
||||
|
||||
static void upb_refcount_dofindscc(upb_refcount *obj, upb_tarjan_state *state) { |
||||
obj->index = state->index; |
||||
obj->lowlink = state->index; |
||||
state->index++; |
||||
state->stack[state->stack_len++] = obj; |
||||
|
||||
state->func(obj, state); // Visit successors.
|
||||
|
||||
if (obj->lowlink == obj->index) { |
||||
upb_refcount *scc_obj; |
||||
while ((scc_obj = state->stack[--state->stack_len]) != obj) { |
||||
upb_refcount_merge(obj, scc_obj); |
||||
scc_obj->index = UPB_INDEX_NOT_IN_STACK; |
||||
} |
||||
obj->index = UPB_INDEX_NOT_IN_STACK; |
||||
} |
||||
} |
||||
|
||||
bool upb_refcount_findscc(upb_refcount **refs, int n, upb_getsuccessors *func) { |
||||
// TODO(haberman): allocate less memory. We can't use n as a bound because
|
||||
// it doesn't include fielddefs. Could either use a dynamically-resizing
|
||||
// array or think of some other way.
|
||||
upb_tarjan_state state = {0, malloc(UINT16_MAX * sizeof(void*)), 0, func}; |
||||
if (state.stack == NULL) return false; |
||||
for (int i = 0; i < n; i++) |
||||
if (refs[i]->index == UPB_INDEX_UNDEFINED) |
||||
upb_refcount_dofindscc(refs[i], &state); |
||||
free(state.stack); |
||||
return true; |
||||
} |
||||
|
||||
#ifdef UPB_DEBUG_REFS |
||||
static void upb_refcount_track(const upb_refcount *r, const void *owner) { |
||||
// Caller must not already own a ref.
|
||||
assert(upb_inttable_lookup(r->refs, (uintptr_t)owner) == NULL); |
||||
|
||||
// If a ref is leaked we want to blame the leak on the whoever leaked the
|
||||
// ref, not on who originally allocated the refcounted object. We accomplish
|
||||
// this as follows. When a ref is taken in DEBUG_REFS mode, we malloc() some
|
||||
// memory and arrange setup pointers like so:
|
||||
//
|
||||
// upb_refcount
|
||||
// +----------+ +---------+
|
||||
// | count |<-+ |
|
||||
// +----------+ +----------+
|
||||
// | table |---X-->| malloc'd |
|
||||
// +----------+ | memory |
|
||||
// +----------+
|
||||
//
|
||||
// Since the "malloc'd memory" is allocated inside of "ref" and free'd in
|
||||
// unref, it will cause a leak if not unref'd. And since the leaked memory
|
||||
// points to the object itself, the object will be considered "indirectly
|
||||
// lost" by tools like Valgrind and not shown unless requested (which is good
|
||||
// because the object's creator may not be responsible for the leak). But we
|
||||
// have to hide the pointer marked "X" above from Valgrind, otherwise the
|
||||
// malloc'd memory will appear to be indirectly leaked and the object itself
|
||||
// will still be considered the primary leak. We hide this pointer from
|
||||
// Valgrind (et all) by doing a bitwise not on it.
|
||||
const upb_refcount **target = malloc(sizeof(void*)); |
||||
uintptr_t obfuscated = ~(uintptr_t)target; |
||||
*target = r; |
||||
upb_inttable_insert(r->refs, (uintptr_t)owner, upb_value_uint64(obfuscated)); |
||||
} |
||||
|
||||
static void upb_refcount_untrack(const upb_refcount *r, const void *owner) { |
||||
upb_value v; |
||||
bool success = upb_inttable_remove(r->refs, (uintptr_t)owner, &v); |
||||
assert(success); |
||||
if (success) { |
||||
// Must un-obfuscate the pointer (see above).
|
||||
free((void*)(~upb_value_getuint64(v))); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
|
||||
/* upb_refcount **************************************************************/ |
||||
|
||||
bool upb_refcount_init(upb_refcount *r, const void *owner) { |
||||
(void)owner; |
||||
r->count = malloc(sizeof(uint32_t)); |
||||
if (!r->count) return false; |
||||
// Initializing this here means upb_refcount_findscc() can only run once for
|
||||
// each refcount; may need to revise this to be more flexible.
|
||||
r->index = UPB_INDEX_UNDEFINED; |
||||
r->next = r; |
||||
#ifdef UPB_DEBUG_REFS |
||||
// We don't detect malloc() failures for UPB_DEBUG_REFS.
|
||||
r->refs = malloc(sizeof(*r->refs)); |
||||
upb_inttable_init(r->refs); |
||||
*r->count = 0; |
||||
upb_refcount_ref(r, owner); |
||||
#else |
||||
*r->count = 1; |
||||
#endif |
||||
return true; |
||||
} |
||||
|
||||
void upb_refcount_uninit(upb_refcount *r) { |
||||
(void)r; |
||||
#ifdef UPB_DEBUG_REFS |
||||
assert(upb_inttable_count(r->refs) == 0); |
||||
upb_inttable_uninit(r->refs); |
||||
free(r->refs); |
||||
#endif |
||||
} |
||||
|
||||
// Thread-safe operations //////////////////////////////////////////////////////
|
||||
|
||||
void upb_refcount_ref(const upb_refcount *r, const void *owner) { |
||||
(void)owner; |
||||
upb_atomic_inc(r->count); |
||||
#ifdef UPB_DEBUG_REFS |
||||
UPB_LOCK; |
||||
upb_refcount_track(r, owner); |
||||
UPB_UNLOCK; |
||||
#endif |
||||
} |
||||
|
||||
bool upb_refcount_unref(const upb_refcount *r, const void *owner) { |
||||
(void)owner; |
||||
bool ret = upb_atomic_dec(r->count); |
||||
#ifdef UPB_DEBUG_REFS |
||||
UPB_LOCK; |
||||
upb_refcount_untrack(r, owner); |
||||
UPB_UNLOCK; |
||||
#endif |
||||
if (ret) free(r->count); |
||||
return ret; |
||||
} |
||||
|
||||
void upb_refcount_donateref( |
||||
const upb_refcount *r, const void *from, const void *to) { |
||||
(void)r; (void)from; (void)to; |
||||
assert(from != to); |
||||
#ifdef UPB_DEBUG_REFS |
||||
UPB_LOCK; |
||||
upb_refcount_track(r, to); |
||||
upb_refcount_untrack(r, from); |
||||
UPB_UNLOCK; |
||||
#endif |
||||
} |
||||
|
||||
bool upb_refcount_merged(const upb_refcount *r, const upb_refcount *r2) { |
||||
return r->count == r2->count; |
||||
} |
@ -1,73 +0,0 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2009 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* A thread-safe refcount that can optionally track references for debugging |
||||
* purposes. It helps avoid circular references by allowing a |
||||
* strongly-connected component in the graph to share a refcount. |
||||
* |
||||
* This interface is internal to upb. |
||||
*/ |
||||
|
||||
#ifndef UPB_REFCOUNT_H_ |
||||
#define UPB_REFCOUNT_H_ |
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
#include "upb/table.h" |
||||
|
||||
#ifndef NDEBUG |
||||
#define UPB_DEBUG_REFS |
||||
#endif |
||||
|
||||
typedef struct _upb_refcount { |
||||
uint32_t *count; |
||||
struct _upb_refcount *next; // Circularly-linked list of this SCC.
|
||||
uint16_t index; // For SCC algorithm.
|
||||
uint16_t lowlink; // For SCC algorithm.
|
||||
#ifdef UPB_DEBUG_REFS |
||||
// Make this a pointer so that we can modify it inside of const methods
|
||||
// without ugly casts.
|
||||
upb_inttable *refs; |
||||
#endif |
||||
} upb_refcount; |
||||
|
||||
// NON THREAD SAFE operations //////////////////////////////////////////////////
|
||||
|
||||
// Initializes the refcount with a single ref for the given owner. Returns
|
||||
// NULL if memory could not be allocated.
|
||||
bool upb_refcount_init(upb_refcount *r, const void *owner); |
||||
|
||||
// Uninitializes the refcount. May only be called after unref() returns true.
|
||||
void upb_refcount_uninit(upb_refcount *r); |
||||
|
||||
// Finds strongly-connected components among some set of objects and merges all
|
||||
// refcounts that share a SCC. The given function will be called when the
|
||||
// algorithm needs to visit children of a particular object; the function
|
||||
// should call upb_refcount_visit() once for each child obj.
|
||||
//
|
||||
// Returns false if memory allocation failed.
|
||||
typedef void upb_getsuccessors(upb_refcount *obj, void*); |
||||
bool upb_refcount_findscc(upb_refcount **objs, int n, upb_getsuccessors *func); |
||||
void upb_refcount_visit(upb_refcount *obj, upb_refcount *subobj, void *closure); |
||||
|
||||
// Thread-safe operations //////////////////////////////////////////////////////
|
||||
|
||||
// Increases the ref count, the new ref is owned by "owner" which must not
|
||||
// already own a ref. Circular reference chains are not allowed.
|
||||
void upb_refcount_ref(const upb_refcount *r, const void *owner); |
||||
|
||||
// Release a ref owned by owner, returns true if that was the last ref.
|
||||
bool upb_refcount_unref(const upb_refcount *r, const void *owner); |
||||
|
||||
// Moves an existing ref from ref_donor to new_owner, without changing the
|
||||
// overall ref count.
|
||||
void upb_refcount_donateref( |
||||
const upb_refcount *r, const void *from, const void *to); |
||||
|
||||
// Returns true if these two objects share a refcount.
|
||||
bool upb_refcount_merged(const upb_refcount *r, const upb_refcount *r2); |
||||
|
||||
#endif // UPB_REFCOUNT_H_
|
@ -0,0 +1,776 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* Our key invariants are: |
||||
* 1. reference cycles never span groups |
||||
* 2. for ref2(to, from), we increment to's count iff group(from) != group(to) |
||||
* |
||||
* The previous two are how we avoid leaking cycles. Other important |
||||
* invariants are: |
||||
* 3. for mutable objects "from" and "to", if there exists a ref2(to, from) |
||||
* this implies group(from) == group(to). (In practice, what we implement |
||||
* is even stronger; "from" and "to" will share a group if there has *ever* |
||||
* been a ref2(to, from), but all that is necessary for correctness is the |
||||
* weaker one). |
||||
* 4. mutable and immutable objects are never in the same group. |
||||
*/ |
||||
|
||||
#include "upb/refcounted.h" |
||||
|
||||
#include <setjmp.h> |
||||
#include <stdlib.h> |
||||
|
||||
uint32_t static_refcount = 1; |
||||
|
||||
/* arch-specific atomic primitives *******************************************/ |
||||
|
||||
#ifdef UPB_THREAD_UNSAFE //////////////////////////////////////////////////////
|
||||
|
||||
static void atomic_inc(uint32_t *a) { (*a)++; } |
||||
static bool atomic_dec(uint32_t *a) { return --(*a) == 0; } |
||||
|
||||
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || __GNUC__ > 4 ///////////////////
|
||||
|
||||
static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); } |
||||
static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; } |
||||
|
||||
#elif defined(WIN32) ///////////////////////////////////////////////////////////
|
||||
|
||||
#include <Windows.h> |
||||
|
||||
static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); } |
||||
static bool atomic_dec(upb_atomic_t *a) { |
||||
return InterlockedDecrement(&a->val) == 0; |
||||
} |
||||
|
||||
#else |
||||
#error Atomic primitives not defined for your platform/CPU. \ |
||||
Implement them or compile with UPB_THREAD_UNSAFE. |
||||
#endif |
||||
|
||||
|
||||
/* Reference tracking (debug only) ********************************************/ |
||||
|
||||
#ifdef UPB_DEBUG_REFS |
||||
|
||||
#ifdef UPB_THREAD_UNSAFE |
||||
|
||||
static void upb_lock() {} |
||||
static void upb_unlock() {} |
||||
|
||||
#else |
||||
|
||||
// User must define functions that lock/unlock a global mutex and link this
|
||||
// file against them.
|
||||
void upb_lock(); |
||||
void upb_unlock(); |
||||
|
||||
#endif |
||||
|
||||
// UPB_DEBUG_REFS mode counts on being able to malloc() memory in some
|
||||
// code-paths that can normally never fail, like upb_refcounted_ref(). Since
|
||||
// we have no way to propagage out-of-memory errors back to the user, and since
|
||||
// these errors can only occur in UPB_DEBUG_REFS mode, we immediately fail.
|
||||
#define CHECK_OOM(predicate) assert(predicate) |
||||
|
||||
typedef struct { |
||||
const upb_refcounted *obj; // Object we are taking a ref on.
|
||||
int count; // How many refs there are (duplicates only allowed for ref2).
|
||||
bool is_ref2; |
||||
} trackedref; |
||||
|
||||
trackedref *trackedref_new(const upb_refcounted *obj, bool is_ref2) { |
||||
trackedref *ret = malloc(sizeof(*ret)); |
||||
CHECK_OOM(ret); |
||||
ret->obj = obj; |
||||
ret->count = 1; |
||||
ret->is_ref2 = is_ref2; |
||||
return ret; |
||||
} |
||||
|
||||
// A reversible function for obfuscating a uintptr_t.
|
||||
// This depends on sizeof(uintptr_t) <= sizeof(uint64_t), so would fail
|
||||
// on 128-bit machines.
|
||||
static uintptr_t obfuscate(const void *x) { return ~(uintptr_t)x; } |
||||
|
||||
static upb_value obfuscate_v(const void *x) { |
||||
return upb_value_uint64(obfuscate(x)); |
||||
} |
||||
|
||||
static const void *unobfuscate_v(upb_value x) { |
||||
return (void*)~upb_value_getuint64(x); |
||||
} |
||||
|
||||
//
|
||||
// Stores tracked references according to the following scheme:
|
||||
// (upb_inttable)reftracks = {
|
||||
// (void*)owner -> (upb_inttable*) = {
|
||||
// obfuscate((upb_refcounted*)obj) -> obfuscate((trackedref*)is_ref2)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// obfuscate() is a function that hides the link from the heap checker, so
|
||||
// that it is not followed for the purposes of deciding what has "indirectly
|
||||
// leaked." Even though we have a pointer to the trackedref*, we want it to
|
||||
// appear leaked if it is not freed.
|
||||
//
|
||||
// This scheme gives us the following desirable properties:
|
||||
//
|
||||
// 1. We can easily determine whether an (owner->obj) ref already exists
|
||||
// and error out if a duplicate ref is taken.
|
||||
//
|
||||
// 2. Because the trackedref is allocated with malloc() at the point that
|
||||
// the ref is taken, that memory will be leaked if the ref is not released.
|
||||
// Because the malloc'd memory points to the refcounted object, the object
|
||||
// itself will only be considered "indirectly leaked" by smart memory
|
||||
// checkers like Valgrind. This will correctly blame the ref leaker
|
||||
// instead of the innocent code that allocated the object to begin with.
|
||||
//
|
||||
// 3. We can easily enumerate all of the ref2 refs for a given owner, which
|
||||
// allows us to double-check that the object's visit() function is
|
||||
// correctly implemented.
|
||||
//
|
||||
static upb_inttable reftracks = UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR); |
||||
|
||||
static upb_inttable *trygettab(const void *p) { |
||||
const upb_value *v = upb_inttable_lookupptr(&reftracks, p); |
||||
return v ? upb_value_getptr(*v) : NULL; |
||||
} |
||||
|
||||
// Gets or creates the tracking table for the given owner.
|
||||
static upb_inttable *gettab(const void *p) { |
||||
upb_inttable *tab = trygettab(p); |
||||
if (tab == NULL) { |
||||
tab = malloc(sizeof(*tab)); |
||||
CHECK_OOM(tab); |
||||
upb_inttable_init(tab, UPB_CTYPE_UINT64); |
||||
upb_inttable_insertptr(&reftracks, p, upb_value_ptr(tab)); |
||||
} |
||||
return tab; |
||||
} |
||||
|
||||
static void track(const upb_refcounted *r, const void *owner, bool ref2) { |
||||
upb_lock(); |
||||
upb_inttable *refs = gettab(owner); |
||||
const upb_value *v = upb_inttable_lookup(refs, obfuscate(r)); |
||||
if (v) { |
||||
trackedref *ref = (trackedref*)unobfuscate_v(*v); |
||||
// Since we allow multiple ref2's for the same to/from pair without
|
||||
// allocating separate memory for each one, we lose the fine-grained
|
||||
// tracking behavior we get with regular refs. Since ref2s only happen
|
||||
// inside upb, we'll accept this limitation until/unless there is a really
|
||||
// difficult upb-internal bug that can't be figured out without it.
|
||||
assert(ref2); |
||||
assert(ref->is_ref2); |
||||
ref->count++; |
||||
} else { |
||||
trackedref *ref = trackedref_new(r, ref2); |
||||
bool ok = upb_inttable_insert(refs, obfuscate(r), obfuscate_v(ref)); |
||||
CHECK_OOM(ok); |
||||
} |
||||
upb_unlock(); |
||||
} |
||||
|
||||
static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { |
||||
upb_lock(); |
||||
upb_inttable *refs = gettab(owner); |
||||
const upb_value *v = upb_inttable_lookup(refs, obfuscate(r)); |
||||
// This assert will fail if an owner attempts to release a ref it didn't have.
|
||||
assert(v); |
||||
trackedref *ref = (trackedref*)unobfuscate_v(*v); |
||||
assert(ref->is_ref2 == ref2); |
||||
if (--ref->count == 0) { |
||||
free(ref); |
||||
upb_inttable_remove(refs, obfuscate(r), NULL); |
||||
if (upb_inttable_count(refs) == 0) { |
||||
upb_inttable_uninit(refs); |
||||
free(refs); |
||||
upb_inttable_removeptr(&reftracks, owner, NULL); |
||||
} |
||||
} |
||||
upb_unlock(); |
||||
} |
||||
|
||||
static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { |
||||
upb_lock(); |
||||
upb_inttable *refs = gettab(owner); |
||||
const upb_value *v = upb_inttable_lookup(refs, obfuscate(r)); |
||||
assert(v); |
||||
trackedref *ref = (trackedref*)unobfuscate_v(*v); |
||||
assert(ref->obj == r); |
||||
assert(ref->is_ref2 == ref2); |
||||
upb_unlock(); |
||||
} |
||||
|
||||
// Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that
|
||||
// originate from the given owner.
|
||||
static void getref2s(const upb_refcounted *owner, upb_inttable *tab) { |
||||
upb_lock(); |
||||
upb_inttable *refs = trygettab(owner); |
||||
if (refs) { |
||||
upb_inttable_iter i; |
||||
upb_inttable_begin(&i, refs); |
||||
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
trackedref *ref = (trackedref*)unobfuscate_v(upb_inttable_iter_value(&i)); |
||||
if (ref->is_ref2) { |
||||
upb_value count = upb_value_int32(ref->count); |
||||
bool ok = upb_inttable_insertptr(tab, ref->obj, count); |
||||
CHECK_OOM(ok); |
||||
} |
||||
} |
||||
} |
||||
upb_unlock(); |
||||
} |
||||
|
||||
typedef struct { |
||||
upb_inttable ref2; |
||||
const upb_refcounted *obj; |
||||
} check_state; |
||||
|
||||
static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj, |
||||
void *closure) { |
||||
check_state *s = closure; |
||||
assert(obj == s->obj); |
||||
assert(subobj); |
||||
upb_inttable *ref2 = &s->ref2; |
||||
upb_value v; |
||||
bool removed = upb_inttable_removeptr(ref2, subobj, &v); |
||||
// The following assertion will fail if the visit() function visits a subobj
|
||||
// that it did not have a ref2 on, or visits the same subobj too many times.
|
||||
assert(removed); |
||||
int32_t newcount = upb_value_getint32(v) - 1; |
||||
if (newcount > 0) { |
||||
upb_inttable_insert(ref2, (uintptr_t)subobj, upb_value_int32(newcount)); |
||||
} |
||||
} |
||||
|
||||
static void visit(const upb_refcounted *r, upb_refcounted_visit *v, |
||||
void *closure) { |
||||
// In DEBUG_REFS mode we know what existing ref2 refs there are, so we know
|
||||
// exactly the set of nodes that visit() should visit. So we verify visit()'s
|
||||
// correctness here.
|
||||
check_state state; |
||||
state.obj = r; |
||||
bool ok = upb_inttable_init(&state.ref2, UPB_CTYPE_INT32); |
||||
CHECK_OOM(ok); |
||||
getref2s(r, &state.ref2); |
||||
|
||||
// This should visit any children in the ref2 table.
|
||||
if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state); |
||||
|
||||
// This assertion will fail if the visit() function missed any children.
|
||||
assert(upb_inttable_count(&state.ref2) == 0); |
||||
upb_inttable_uninit(&state.ref2); |
||||
if (r->vtbl->visit) r->vtbl->visit(r, v, closure); |
||||
} |
||||
|
||||
#else |
||||
|
||||
static void track(const upb_refcounted *r, const void *owner, bool ref2) { |
||||
UPB_UNUSED(r); |
||||
UPB_UNUSED(owner); |
||||
UPB_UNUSED(ref2); |
||||
} |
||||
|
||||
static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { |
||||
UPB_UNUSED(r); |
||||
UPB_UNUSED(owner); |
||||
UPB_UNUSED(ref2); |
||||
} |
||||
|
||||
static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { |
||||
UPB_UNUSED(r); |
||||
UPB_UNUSED(owner); |
||||
UPB_UNUSED(ref2); |
||||
} |
||||
|
||||
static void visit(const upb_refcounted *r, upb_refcounted_visit *v, |
||||
void *closure) { |
||||
if (r->vtbl->visit) r->vtbl->visit(r, v, closure); |
||||
} |
||||
|
||||
#endif // UPB_DEBUG_REFS
|
||||
|
||||
|
||||
/* freeze() *******************************************************************/ |
||||
|
||||
// The freeze() operation is by far the most complicated part of this scheme.
|
||||
// We compute strongly-connected components and then mutate the graph such that
|
||||
// we preserve the invariants documented at the top of this file. And we must
|
||||
// handle out-of-memory errors gracefully (without leaving the graph
|
||||
// inconsistent), which adds to the fun.
|
||||
|
||||
// The state used by the freeze operation (shared across many functions).
|
||||
typedef struct { |
||||
int depth; |
||||
int maxdepth; |
||||
uint64_t index; |
||||
// Maps upb_refcounted* -> attributes (color, etc). attr layout varies by
|
||||
// color.
|
||||
upb_inttable objattr; |
||||
upb_inttable stack; // stack of upb_refcounted* for Tarjan's algorithm.
|
||||
upb_inttable groups; // array of uint32_t*, malloc'd refcounts for new groups
|
||||
upb_status *status; |
||||
jmp_buf err; |
||||
} tarjan; |
||||
|
||||
static void release_ref2(const upb_refcounted *obj, |
||||
const upb_refcounted *subobj, |
||||
void *closure); |
||||
|
||||
// Node attributes /////////////////////////////////////////////////////////////
|
||||
|
||||
// After our analysis phase all nodes will be either GRAY or WHITE.
|
||||
|
||||
typedef enum { |
||||
BLACK = 0, // Object has not been seen.
|
||||
GRAY, // Object has been found via a refgroup but may not be reachable.
|
||||
GREEN, // Object is reachable and is currently on the Tarjan stack.
|
||||
WHITE, // Object is reachable and has been assigned a group (SCC).
|
||||
} color_t; |
||||
|
||||
UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); } |
||||
UPB_NORETURN static void oom(tarjan *t) { |
||||
upb_status_seterrliteral(t->status, "out of memory"); |
||||
err(t); |
||||
} |
||||
|
||||
uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) { |
||||
const upb_value *v = upb_inttable_lookupptr(&t->objattr, r); |
||||
return v ? upb_value_getuint64(*v) : 0; |
||||
} |
||||
|
||||
uint64_t getattr(const tarjan *t, const upb_refcounted *r) { |
||||
const upb_value *v = upb_inttable_lookupptr(&t->objattr, r); |
||||
assert(v); |
||||
return upb_value_getuint64(*v); |
||||
} |
||||
|
||||
void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) { |
||||
upb_inttable_removeptr(&t->objattr, r, NULL); |
||||
upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr)); |
||||
} |
||||
|
||||
static color_t color(tarjan *t, const upb_refcounted *r) { |
||||
return trygetattr(t, r) & 0x3; // Color is always stored in the low 2 bits.
|
||||
} |
||||
|
||||
static void set_gray(tarjan *t, const upb_refcounted *r) { |
||||
assert(color(t, r) == BLACK); |
||||
setattr(t, r, GRAY); |
||||
} |
||||
|
||||
// Pushes an obj onto the Tarjan stack and sets it to GREEN.
|
||||
static void push(tarjan *t, const upb_refcounted *r) { |
||||
assert(color(t, r) == BLACK || color(t, r) == GRAY); |
||||
// This defines the attr layout for the GREEN state. "index" and "lowlink"
|
||||
// get 31 bits, which is plenty (limit of 2B objects frozen at a time).
|
||||
setattr(t, r, GREEN | (t->index << 2) | (t->index << 33)); |
||||
if (++t->index == 0x80000000) { |
||||
upb_status_seterrliteral(t->status, "too many objects to freeze"); |
||||
err(t); |
||||
} |
||||
upb_inttable_push(&t->stack, upb_value_ptr((void*)r)); |
||||
} |
||||
|
||||
// Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its
|
||||
// SCC group.
|
||||
static upb_refcounted *pop(tarjan *t) { |
||||
upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack)); |
||||
assert(color(t, r) == GREEN); |
||||
// This defines the attr layout for nodes in the WHITE state.
|
||||
// Top of group stack is [group, NULL]; we point at group.
|
||||
setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8); |
||||
return r; |
||||
} |
||||
|
||||
static void newgroup(tarjan *t) { |
||||
uint32_t *group = malloc(sizeof(*group)); |
||||
if (!group) oom(t); |
||||
// Push group and empty group leader (we'll fill in leader later).
|
||||
if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) || |
||||
!upb_inttable_push(&t->groups, upb_value_ptr(NULL))) { |
||||
free(group); |
||||
oom(t); |
||||
} |
||||
*group = 0; |
||||
} |
||||
|
||||
static uint32_t idx(tarjan *t, const upb_refcounted *r) { |
||||
assert(color(t, r) == GREEN); |
||||
return (getattr(t, r) >> 2) & 0x7FFFFFFF; |
||||
} |
||||
|
||||
static uint32_t lowlink(tarjan *t, const upb_refcounted *r) { |
||||
if (color(t, r) == GREEN) { |
||||
return getattr(t, r) >> 33; |
||||
} else { |
||||
return UINT32_MAX; |
||||
} |
||||
} |
||||
|
||||
static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) { |
||||
assert(color(t, r) == GREEN); |
||||
setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF)); |
||||
} |
||||
|
||||
uint32_t *group(tarjan *t, upb_refcounted *r) { |
||||
assert(color(t, r) == WHITE); |
||||
uint64_t groupnum = getattr(t, r) >> 8; |
||||
const upb_value *v = upb_inttable_lookup(&t->groups, groupnum); |
||||
assert(v); |
||||
return upb_value_getptr(*v); |
||||
} |
||||
|
||||
// If the group leader for this object's group has not previously been set,
|
||||
// the given object is assigned to be its leader.
|
||||
static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) { |
||||
assert(color(t, r) == WHITE); |
||||
uint64_t leader_slot = (getattr(t, r) >> 8) + 1; |
||||
const upb_value *v = upb_inttable_lookup(&t->groups, leader_slot); |
||||
assert(v); |
||||
if (upb_value_getptr(*v)) { |
||||
return upb_value_getptr(*v); |
||||
} else { |
||||
upb_inttable_remove(&t->groups, leader_slot, NULL); |
||||
upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r)); |
||||
return r; |
||||
} |
||||
} |
||||
|
||||
|
||||
// Tarjan's algorithm //////////////////////////////////////////////////////////
|
||||
|
||||
// See:
|
||||
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
static void do_tarjan(const upb_refcounted *obj, tarjan *t); |
||||
|
||||
static void tarjan_visit(const upb_refcounted *obj, |
||||
const upb_refcounted *subobj, |
||||
void *closure) { |
||||
tarjan *t = closure; |
||||
if (++t->depth > t->maxdepth) { |
||||
upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth); |
||||
err(t); |
||||
} else if (subobj->is_frozen || color(t, subobj) == WHITE) { |
||||
// Do nothing: we don't want to visit or color already-frozen nodes,
|
||||
// and WHITE nodes have already been assigned a SCC.
|
||||
} else if (color(t, subobj) < GREEN) { |
||||
// Subdef has not yet been visited; recurse on it.
|
||||
do_tarjan(subobj, t); |
||||
set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj))); |
||||
} else if (color(t, subobj) == GREEN) { |
||||
// Subdef is in the stack and hence in the current SCC.
|
||||
set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj))); |
||||
} |
||||
--t->depth; |
||||
} |
||||
|
||||
static void do_tarjan(const upb_refcounted *obj, tarjan *t) { |
||||
if (color(t, obj) == BLACK) { |
||||
// We haven't seen this object's group; mark the whole group GRAY.
|
||||
const upb_refcounted *o = obj; |
||||
do { set_gray(t, o); } while ((o = o->next) != obj); |
||||
} |
||||
|
||||
push(t, obj); |
||||
visit(obj, tarjan_visit, t); |
||||
if (lowlink(t, obj) == idx(t, obj)) { |
||||
newgroup(t); |
||||
while (pop(t) != obj) |
||||
; |
||||
} |
||||
} |
||||
|
||||
|
||||
// freeze() ////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void crossref(const upb_refcounted *r, const upb_refcounted *subobj, |
||||
void *_t) { |
||||
tarjan *t = _t; |
||||
assert(color(t, r) > BLACK); |
||||
if (color(t, subobj) > BLACK && r->group != subobj->group) { |
||||
// Previously this ref was not reflected in subobj->group because they
|
||||
// were in the same group; now that they are split a ref must be taken.
|
||||
atomic_inc(subobj->group); |
||||
} |
||||
} |
||||
|
||||
static bool freeze(upb_refcounted *const*roots, int n, upb_status *s) { |
||||
volatile bool ret = false; |
||||
|
||||
// We run in two passes so that we can allocate all memory before performing
|
||||
// any mutation of the input -- this allows us to leave the input unchanged
|
||||
// in the case of memory allocation failure.
|
||||
tarjan t; |
||||
t.index = 0; |
||||
t.depth = 0; |
||||
t.maxdepth = UPB_MAX_TYPE_DEPTH * 2; // May want to make this a parameter.
|
||||
t.status = s; |
||||
if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1; |
||||
if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2; |
||||
if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3; |
||||
if (setjmp(t.err) != 0) goto err4; |
||||
|
||||
|
||||
for (int i = 0; i < n; i++) { |
||||
if (color(&t, roots[i]) < GREEN) { |
||||
do_tarjan(roots[i], &t); |
||||
} |
||||
} |
||||
|
||||
// If we've made it this far, no further errors are possible so it's safe to
|
||||
// mutate the objects without risk of leaving them in an inconsistent state.
|
||||
ret = true; |
||||
|
||||
// The transformation that follows requires care. The preconditions are:
|
||||
// - all objects in attr map are WHITE or GRAY, and are in mutable groups
|
||||
// (groups of all mutable objs)
|
||||
// - no ref2(to, from) refs have incremented count(to) if both "to" and
|
||||
// "from" are in our attr map (this follows from invariants (2) and (3))
|
||||
|
||||
// Pass 1: we remove WHITE objects from their mutable groups, and add them to
|
||||
// new groups according to the SCC's we computed. These new groups will
|
||||
// consist of only frozen objects. None will be immediately collectible,
|
||||
// because WHITE objects are by definition reachable from one of "roots",
|
||||
// which the caller must own refs on.
|
||||
upb_inttable_iter i; |
||||
upb_inttable_begin(&i, &t.objattr); |
||||
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i); |
||||
// Since removal from a singly-linked list requires access to the object's
|
||||
// predecessor, we consider obj->next instead of obj for moving. With the
|
||||
// while() loop we guarantee that we will visit every node's predecessor.
|
||||
// Proof:
|
||||
// 1. every node's predecessor is in our attr map.
|
||||
// 2. though the loop body may change a node's predecessor, it will only
|
||||
// change it to be the node we are currently operating on, so with a
|
||||
// while() loop we guarantee ourselves the chance to remove each node.
|
||||
while (color(&t, obj->next) == WHITE && |
||||
group(&t, obj->next) != obj->next->group) { |
||||
// Remove from old group.
|
||||
upb_refcounted *move = obj->next; |
||||
if (obj == move) { |
||||
// Removing the last object from a group.
|
||||
assert(*obj->group == obj->individual_count); |
||||
free(obj->group); |
||||
} else { |
||||
obj->next = move->next; |
||||
// This may decrease to zero; we'll collect GRAY objects (if any) that
|
||||
// remain in the group in the third pass.
|
||||
assert(*move->group >= move->individual_count); |
||||
*move->group -= move->individual_count; |
||||
} |
||||
|
||||
// Add to new group.
|
||||
upb_refcounted *leader = groupleader(&t, move); |
||||
if (move == leader) { |
||||
// First object added to new group is its leader.
|
||||
move->group = group(&t, move); |
||||
move->next = move; |
||||
*move->group = move->individual_count; |
||||
} else { |
||||
// Group already has at least one object in it.
|
||||
assert(leader->group == group(&t, move)); |
||||
move->group = group(&t, move); |
||||
move->next = leader->next; |
||||
leader->next = move; |
||||
*move->group += move->individual_count; |
||||
} |
||||
|
||||
move->is_frozen = true; |
||||
} |
||||
} |
||||
|
||||
// Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must
|
||||
// increment count(to) if group(obj) != group(to) (which could now be the
|
||||
// case if "to" was just frozen).
|
||||
upb_inttable_begin(&i, &t.objattr); |
||||
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i); |
||||
visit(obj, crossref, &t); |
||||
} |
||||
|
||||
// Pass 3: GRAY objects are collected if their group's refcount dropped to
|
||||
// zero when we removed its white nodes. This can happen if they had only
|
||||
// been kept alive by virtue of sharing a group with an object that was just
|
||||
// frozen.
|
||||
//
|
||||
// It is important that we do this last, since the GRAY object's free()
|
||||
// function could call unref2() on just-frozen objects, which will decrement
|
||||
// refs that were added in pass 2.
|
||||
upb_inttable_begin(&i, &t.objattr); |
||||
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||
upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&i); |
||||
if (obj->group == NULL || *obj->group == 0) { |
||||
if (obj->group) { |
||||
// We eagerly free() the group's count (since we can't easily determine
|
||||
// the group's remaining size it's the easiest way to ensure it gets
|
||||
// done).
|
||||
free(obj->group); |
||||
|
||||
// Visit to release ref2's (done in a separate pass since release_ref2
|
||||
// depends on o->group being unmodified so it can test merged()).
|
||||
upb_refcounted *o = obj; |
||||
do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj); |
||||
|
||||
// Mark "group" fields as NULL so we know to free the objects later in
|
||||
// this loop, but also don't try to delete the group twice.
|
||||
o = obj; |
||||
do { o->group = NULL; } while ((o = o->next) != obj); |
||||
} |
||||
obj->vtbl->free(obj); |
||||
} |
||||
} |
||||
|
||||
err4: |
||||
if (!ret) { |
||||
upb_inttable_begin(&i, &t.groups); |
||||
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) |
||||
free(upb_value_getptr(upb_inttable_iter_value(&i))); |
||||
} |
||||
upb_inttable_uninit(&t.groups); |
||||
err3: |
||||
upb_inttable_uninit(&t.stack); |
||||
err2: |
||||
upb_inttable_uninit(&t.objattr); |
||||
err1: |
||||
return ret; |
||||
} |
||||
|
||||
|
||||
/* Misc internal functions ***************************************************/ |
||||
|
||||
static bool merged(const upb_refcounted *r, const upb_refcounted *r2) { |
||||
return r->group == r2->group; |
||||
} |
||||
|
||||
static void merge(upb_refcounted *r, upb_refcounted *from) { |
||||
if (merged(r, from)) return; |
||||
*r->group += *from->group; |
||||
free(from->group); |
||||
upb_refcounted *base = from; |
||||
|
||||
// Set all refcount pointers in the "from" chain to the merged refcount.
|
||||
//
|
||||
// TODO(haberman): this linear algorithm can result in an overall O(n^2) bound
|
||||
// if the user continuously extends a group by one object. Prevent this by
|
||||
// using one of the techniques in this paper:
|
||||
// ftp://www.ncedc.org/outgoing/geomorph/dino/orals/p245-tarjan.pdf
|
||||
do { from->group = r->group; } while ((from = from->next) != base); |
||||
|
||||
// Merge the two circularly linked lists by swapping their next pointers.
|
||||
upb_refcounted *tmp = r->next; |
||||
r->next = base->next; |
||||
base->next = tmp; |
||||
} |
||||
|
||||
static void unref(const upb_refcounted *r); |
||||
|
||||
static void release_ref2(const upb_refcounted *obj, |
||||
const upb_refcounted *subobj, |
||||
void *closure) { |
||||
UPB_UNUSED(closure); |
||||
if (!merged(obj, subobj)) { |
||||
assert(subobj->is_frozen); |
||||
unref(subobj); |
||||
} |
||||
untrack(subobj, obj, true); |
||||
} |
||||
|
||||
static void unref(const upb_refcounted *r) { |
||||
if (atomic_dec(r->group)) { |
||||
free(r->group); |
||||
|
||||
// In two passes, since release_ref2 needs a guarantee that any subobjs
|
||||
// are alive.
|
||||
const upb_refcounted *o = r; |
||||
do { visit(o, release_ref2, NULL); } while((o = o->next) != r); |
||||
|
||||
o = r; |
||||
do { |
||||
const upb_refcounted *next = o->next; |
||||
assert(o->is_frozen || o->individual_count == 0); |
||||
o->vtbl->free((upb_refcounted*)o); |
||||
o = next; |
||||
} while(o != r); |
||||
} |
||||
} |
||||
|
||||
|
||||
/* Public interface ***********************************************************/ |
||||
|
||||
bool upb_refcounted_init(upb_refcounted *r, |
||||
const struct upb_refcounted_vtbl *vtbl, |
||||
const void *owner) { |
||||
r->next = r; |
||||
r->vtbl = vtbl; |
||||
r->individual_count = 0; |
||||
r->is_frozen = false; |
||||
r->group = malloc(sizeof(*r->group)); |
||||
if (!r->group) return false; |
||||
*r->group = 0; |
||||
upb_refcounted_ref(r, owner); |
||||
return true; |
||||
} |
||||
|
||||
bool upb_refcounted_isfrozen(const upb_refcounted *r) { |
||||
return r->is_frozen; |
||||
} |
||||
|
||||
void upb_refcounted_ref(const upb_refcounted *r, const void *owner) { |
||||
if (!r->is_frozen) |
||||
((upb_refcounted*)r)->individual_count++; |
||||
atomic_inc(r->group); |
||||
track(r, owner, false); |
||||
} |
||||
|
||||
void upb_refcounted_unref(const upb_refcounted *r, const void *owner) { |
||||
if (!r->is_frozen) |
||||
((upb_refcounted*)r)->individual_count--; |
||||
unref(r); |
||||
untrack(r, owner, false); |
||||
} |
||||
|
||||
void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) { |
||||
assert(!from->is_frozen); // Non-const pointer implies this.
|
||||
if (r->is_frozen) { |
||||
atomic_inc(r->group); |
||||
} else { |
||||
merge((upb_refcounted*)r, from); |
||||
} |
||||
track(r, from, true); |
||||
} |
||||
|
||||
void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) { |
||||
assert(!from->is_frozen); // Non-const pointer implies this.
|
||||
if (r->is_frozen) { |
||||
unref(r); |
||||
} else { |
||||
assert(merged(r, from)); |
||||
} |
||||
untrack(r, from, true); |
||||
} |
||||
|
||||
void upb_refcounted_donateref( |
||||
const upb_refcounted *r, const void *from, const void *to) { |
||||
assert(from != to); |
||||
assert(to != NULL); |
||||
upb_refcounted_ref(r, to); |
||||
if (from != NULL) |
||||
upb_refcounted_unref(r, from); |
||||
} |
||||
|
||||
void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) { |
||||
checkref(r, owner, false); |
||||
} |
||||
|
||||
bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s) { |
||||
for (int i = 0; i < n; i++) { |
||||
assert(!roots[i]->is_frozen); |
||||
} |
||||
return freeze(roots, n, s); |
||||
} |
@ -0,0 +1,180 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2009-2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* A refcounting scheme that supports circular refs. It accomplishes this by |
||||
* partitioning the set of objects into groups such that no cycle spans groups; |
||||
* we can then reference-count the group as a whole and ignore refs within the |
||||
* group. When objects are mutable, these groups are computed very |
||||
* conservatively; we group any objects that have ever had a link between them. |
||||
* When objects are frozen, we compute strongly-connected components which |
||||
* allows us to be precise and only group objects that are actually cyclic. |
||||
* |
||||
* This is a mixed C/C++ interface that offers a full API to both languages. |
||||
* See the top-level README for more information. |
||||
*/ |
||||
|
||||
#ifndef UPB_REFCOUNTED_H_ |
||||
#define UPB_REFCOUNTED_H_ |
||||
|
||||
#include "upb/table.h" |
||||
|
||||
// Reference tracking is designed to be used with a tool like Valgrind; when
|
||||
// enabled, it will cause reference leaks to show up as actual memory leaks
|
||||
// that are attributed to the code that leaked the ref, *not* the code that
|
||||
// originally created the object.
|
||||
#ifndef NDEBUG |
||||
#define UPB_DEBUG_REFS |
||||
#endif |
||||
|
||||
struct upb_refcounted_vtbl; |
||||
|
||||
#ifdef __cplusplus |
||||
namespace upb { class RefCounted; } |
||||
typedef upb::RefCounted upb_refcounted; |
||||
extern "C" { |
||||
#else |
||||
struct upb_refcounted; |
||||
typedef struct upb_refcounted upb_refcounted; |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
|
||||
class upb::RefCounted { |
||||
public: |
||||
// Returns true if the given object is frozen.
|
||||
bool IsFrozen() const; |
||||
|
||||
// Increases the ref count, the new ref is owned by "owner" which must not
|
||||
// already own a ref (and should not itself be a refcounted object if the ref
|
||||
// could possibly be circular; see below).
|
||||
// Thread-safe iff "this" is frozen.
|
||||
void Ref(const void *owner) const; |
||||
|
||||
// Release a ref that was acquired from upb_refcounted_ref() and collects any
|
||||
// objects it can.
|
||||
void Unref(const void *owner) const; |
||||
|
||||
// Moves an existing ref from "from" to "to", without changing the overall
|
||||
// ref count. DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
|
||||
// but "to" may not be NULL.
|
||||
void DonateRef(const void *from, const void *to) const; |
||||
|
||||
// Verifies that a ref to the given object is currently held by the given
|
||||
// owner. Only effective in UPB_DEBUG_REFS builds.
|
||||
void CheckRef(const void *owner) const; |
||||
|
||||
private: |
||||
UPB_DISALLOW_POD_OPS(RefCounted); |
||||
#else |
||||
struct upb_refcounted { |
||||
#endif |
||||
// A single reference count shared by all objects in the group.
|
||||
uint32_t *group; |
||||
|
||||
// A singly-linked list of all objects in the group.
|
||||
upb_refcounted *next; |
||||
|
||||
// Table of function pointers for this type.
|
||||
const struct upb_refcounted_vtbl *vtbl; |
||||
|
||||
// Maintained only when mutable, this tracks the number of refs (but not
|
||||
// ref2's) to this object. *group should be the sum of all individual_count
|
||||
// in the group.
|
||||
uint32_t individual_count; |
||||
|
||||
bool is_frozen; |
||||
}; |
||||
|
||||
// Native C API.
|
||||
bool upb_refcounted_isfrozen(const upb_refcounted *r); |
||||
void upb_refcounted_ref(const upb_refcounted *r, const void *owner); |
||||
void upb_refcounted_unref(const upb_refcounted *r, const void *owner); |
||||
void upb_refcounted_donateref( |
||||
const upb_refcounted *r, const void *from, const void *to); |
||||
void upb_refcounted_checkref(const upb_refcounted *r, const void *owner); |
||||
|
||||
|
||||
// Internal-to-upb Interface ///////////////////////////////////////////////////
|
||||
|
||||
typedef void upb_refcounted_visit(const upb_refcounted *r, |
||||
const upb_refcounted *subobj, |
||||
void *closure); |
||||
|
||||
struct upb_refcounted_vtbl { |
||||
// Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
|
||||
// Must be longjmp()-safe.
|
||||
void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c); |
||||
|
||||
// Must free the object and release all references to other objects.
|
||||
void (*free)(upb_refcounted *r); |
||||
}; |
||||
|
||||
// Initializes the refcounted with a single ref for the given owner. Returns
|
||||
// false if memory could not be allocated.
|
||||
bool upb_refcounted_init(upb_refcounted *r, |
||||
const struct upb_refcounted_vtbl *vtbl, |
||||
const void *owner); |
||||
|
||||
// Adds a ref from one refcounted object to another ("from" must not already
|
||||
// own a ref). These refs may be circular; cycles will be collected correctly
|
||||
// (if conservatively). These refs do not need to be freed in from's free()
|
||||
// function.
|
||||
void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from); |
||||
|
||||
// Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
|
||||
// object it can. This is only necessary when "from" no longer points to "r",
|
||||
// and not from from's "free" function.
|
||||
void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from); |
||||
|
||||
#define upb_ref2(r, from) \ |
||||
upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from) |
||||
#define upb_unref2(r, from) \ |
||||
upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from) |
||||
|
||||
// Freezes all mutable object reachable by ref2() refs from the given roots.
|
||||
// This will split refcounting groups into precise SCC groups, so that
|
||||
// refcounting of frozen objects can be more aggressive. If memory allocation
|
||||
// fails or if more than 2**31 mutable objects are reachable from "roots",
|
||||
// false is returned and the objects are unchanged.
|
||||
//
|
||||
// After this operation succeeds, the objects are frozen/const, and may not be
|
||||
// used through non-const pointers. In particular, they may not be passed as
|
||||
// the second parameter of upb_refcounted_{ref,unref}2(). On the upside, all
|
||||
// operations on frozen refcounteds are threadsafe, and objects will be freed
|
||||
// at the precise moment that they become unreachable.
|
||||
//
|
||||
// Caller must own refs on each object in the "roots" list.
|
||||
bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s); |
||||
|
||||
// Shared by all compiled-in refcounted objects.
|
||||
extern uint32_t static_refcount; |
||||
|
||||
#define UPB_REFCOUNT_INIT {&static_refcount, NULL, NULL, 0, true} |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
|
||||
// C++ Wrappers.
|
||||
namespace upb { |
||||
inline bool RefCounted::IsFrozen() const { |
||||
return upb_refcounted_isfrozen(this); |
||||
} |
||||
inline void RefCounted::Ref(const void *owner) const { |
||||
upb_refcounted_ref(this, owner); |
||||
} |
||||
inline void RefCounted::Unref(const void *owner) const { |
||||
upb_refcounted_unref(this, owner); |
||||
} |
||||
inline void RefCounted::DonateRef(const void *from, const void *to) const { |
||||
upb_refcounted_donateref(this, from, to); |
||||
} |
||||
inline void RefCounted::CheckRef(const void *owner) const { |
||||
upb_refcounted_checkref(this, owner); |
||||
} |
||||
} // namespace upb
|
||||
#endif |
||||
|
||||
#endif // UPB_REFCOUNT_H_
|
@ -0,0 +1,205 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2011-2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#include "upb/sink.h" |
||||
|
||||
static bool chkstack(upb_sink *s) { |
||||
if (s->top + 1 >= s->limit) { |
||||
upb_status_seterrliteral(&s->status, "Nesting too deep."); |
||||
return false; |
||||
} else { |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
static upb_selector_t getselector(const upb_fielddef *f, |
||||
upb_handlertype_t type) { |
||||
upb_selector_t selector; |
||||
bool ok = upb_getselector(f, type, &selector); |
||||
UPB_ASSERT_VAR(ok, ok); |
||||
return selector; |
||||
} |
||||
|
||||
void upb_sink_init(upb_sink *s, const upb_handlers *h) { |
||||
s->limit = &s->stack[UPB_MAX_NESTING]; |
||||
s->top = NULL; |
||||
s->stack[0].h = h; |
||||
upb_status_init(&s->status); |
||||
} |
||||
|
||||
void upb_sink_reset(upb_sink *s, void *closure) { |
||||
s->top = s->stack; |
||||
s->top->closure = closure; |
||||
} |
||||
|
||||
void upb_sink_uninit(upb_sink *s) { |
||||
upb_status_uninit(&s->status); |
||||
} |
||||
|
||||
bool upb_sink_startmsg(upb_sink *s) { |
||||
const upb_handlers *h = s->top->h; |
||||
upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h); |
||||
return startmsg ? startmsg(s->top->closure) : true; |
||||
} |
||||
|
||||
void upb_sink_endmsg(upb_sink *s, upb_status *status) { |
||||
UPB_UNUSED(status); |
||||
assert(s->top == s->stack); |
||||
upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); |
||||
if (endmsg) endmsg(s->top->closure, &s->status); |
||||
} |
||||
|
||||
#define PUTVAL(type, ctype, htype) \ |
||||
bool upb_sink_put ## type(upb_sink *s, const upb_fielddef *f, ctype val) { \
|
||||
upb_selector_t selector; \
|
||||
if (!upb_getselector(f, UPB_HANDLER_ ## htype, &selector)) return false; \
|
||||
upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \
|
||||
upb_handlers_gethandler(s->top->h, selector); \
|
||||
if (handler) { \
|
||||
void *data = upb_handlers_gethandlerdata(s->top->h, selector); \
|
||||
if (!handler(s->top->closure, data, val)) return false; \
|
||||
} \
|
||||
return true; \
|
||||
} |
||||
|
||||
PUTVAL(int32, int32_t, INT32); |
||||
PUTVAL(int64, int64_t, INT64); |
||||
PUTVAL(uint32, uint32_t, UINT32); |
||||
PUTVAL(uint64, uint64_t, UINT64); |
||||
PUTVAL(float, float, FLOAT); |
||||
PUTVAL(double, double, DOUBLE); |
||||
PUTVAL(bool, bool, BOOL); |
||||
#undef PUTVAL |
||||
|
||||
size_t upb_sink_putstring(upb_sink *s, const upb_fielddef *f, |
||||
const char *buf, size_t n) { |
||||
upb_selector_t selector; |
||||
if (!upb_getselector(f, UPB_HANDLER_STRING, &selector)) return false; |
||||
upb_string_handler *handler = (upb_string_handler*) |
||||
upb_handlers_gethandler(s->top->h, selector); |
||||
if (handler) { |
||||
void *data = upb_handlers_gethandlerdata(s->top->h, selector); \
|
||||
return handler(s->top->closure, data, buf, n); |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
bool upb_sink_startseq(upb_sink *s, const upb_fielddef *f) { |
||||
assert(upb_fielddef_isseq(f)); |
||||
if (!chkstack(s)) return false; |
||||
|
||||
void *subc = s->top->closure; |
||||
const upb_handlers *h = s->top->h; |
||||
upb_selector_t selector; |
||||
if (!upb_getselector(f, UPB_HANDLER_STARTSEQ, &selector)) return false; |
||||
upb_startfield_handler *startseq = |
||||
(upb_startfield_handler*)upb_handlers_gethandler(h, selector); |
||||
if (startseq) { |
||||
subc = startseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)); |
||||
if (!subc) return false; |
||||
} |
||||
|
||||
++s->top; |
||||
s->top->end = getselector(f, UPB_HANDLER_ENDSEQ); |
||||
s->top->h = h; |
||||
s->top->closure = subc; |
||||
return true; |
||||
} |
||||
|
||||
bool upb_sink_endseq(upb_sink *s, const upb_fielddef *f) { |
||||
upb_selector_t selector = s->top->end; |
||||
assert(selector == getselector(f, UPB_HANDLER_ENDSEQ)); |
||||
--s->top; |
||||
|
||||
const upb_handlers *h = s->top->h; |
||||
upb_endfield_handler *endseq = |
||||
(upb_endfield_handler*)upb_handlers_gethandler(h, selector); |
||||
return endseq ? |
||||
endseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : |
||||
true; |
||||
} |
||||
|
||||
bool upb_sink_startstr(upb_sink *s, const upb_fielddef *f, size_t size_hint) { |
||||
assert(upb_fielddef_isstring(f)); |
||||
if (!chkstack(s)) return false; |
||||
|
||||
void *subc = s->top->closure; |
||||
const upb_handlers *h = s->top->h; |
||||
upb_selector_t selector; |
||||
if (!upb_getselector(f, UPB_HANDLER_STARTSTR, &selector)) return false; |
||||
upb_startstr_handler *startstr = |
||||
(upb_startstr_handler*)upb_handlers_gethandler(h, selector); |
||||
if (startstr) { |
||||
subc = startstr( |
||||
s->top->closure, upb_handlers_gethandlerdata(h, selector), size_hint); |
||||
if (!subc) return false; |
||||
} |
||||
|
||||
++s->top; |
||||
s->top->end = getselector(f, UPB_HANDLER_ENDSTR); |
||||
s->top->h = h; |
||||
s->top->closure = subc; |
||||
return true; |
||||
} |
||||
|
||||
bool upb_sink_endstr(upb_sink *s, const upb_fielddef *f) { |
||||
upb_selector_t selector = s->top->end; |
||||
assert(selector == getselector(f, UPB_HANDLER_ENDSTR)); |
||||
--s->top; |
||||
|
||||
const upb_handlers *h = s->top->h; |
||||
upb_endfield_handler *endstr = |
||||
(upb_endfield_handler*)upb_handlers_gethandler(h, selector); |
||||
return endstr ? |
||||
endstr(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : |
||||
true; |
||||
} |
||||
|
||||
bool upb_sink_startsubmsg(upb_sink *s, const upb_fielddef *f) { |
||||
assert(upb_fielddef_issubmsg(f)); |
||||
if (!chkstack(s)) return false; |
||||
|
||||
const upb_handlers *h = s->top->h; |
||||
upb_selector_t selector; |
||||
if (!upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector)) return false; |
||||
upb_startfield_handler *startsubmsg = |
||||
(upb_startfield_handler*)upb_handlers_gethandler(h, selector); |
||||
void *subc = s->top->closure; |
||||
|
||||
if (startsubmsg) { |
||||
void *data = upb_handlers_gethandlerdata(h, selector); |
||||
subc = startsubmsg(s->top->closure, data); |
||||
if (!subc) return false; |
||||
} |
||||
|
||||
++s->top; |
||||
s->top->end = getselector(f, UPB_HANDLER_ENDSUBMSG); |
||||
s->top->h = upb_handlers_getsubhandlers(h, f); |
||||
s->top->closure = subc; |
||||
upb_sink_startmsg(s); |
||||
return true; |
||||
} |
||||
|
||||
bool upb_sink_endsubmsg(upb_sink *s, const upb_fielddef *f) { |
||||
upb_selector_t selector = s->top->end; |
||||
assert(selector == getselector(f, UPB_HANDLER_ENDSUBMSG)); |
||||
|
||||
upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); |
||||
if (endmsg) endmsg(s->top->closure, &s->status); |
||||
--s->top; |
||||
|
||||
const upb_handlers *h = s->top->h; |
||||
upb_endfield_handler *endfield = |
||||
(upb_endfield_handler*)upb_handlers_gethandler(h, selector); |
||||
return endfield ? |
||||
endfield(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : |
||||
true; |
||||
} |
||||
|
||||
const upb_handlers *upb_sink_tophandlers(upb_sink *s) { |
||||
return s->top->h; |
||||
} |
@ -0,0 +1,82 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2010-2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* A upb_sink is an object that binds a upb_handlers object to some runtime |
||||
* state. It is the object that can actually receive data via the upb_handlers |
||||
* interface. |
||||
* |
||||
* Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or |
||||
* thread-safe. You can create as many of them as you want, but each one may |
||||
* only be used in a single thread at a time. |
||||
* |
||||
* If we compare with class-based OOP, a you can think of a upb_def as an |
||||
* abstract base class, a upb_handlers as a concrete derived class, and a |
||||
* upb_sink as an object (class instance). |
||||
*/ |
||||
|
||||
#ifndef UPB_SINK_H |
||||
#define UPB_SINK_H |
||||
|
||||
#include "upb/handlers.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
|
||||
/* upb_sink *******************************************************************/ |
||||
|
||||
typedef struct { |
||||
upb_selector_t end; // From the enclosing message (unused at top-level).
|
||||
const upb_handlers *h; |
||||
void *closure; |
||||
} upb_sink_frame; |
||||
|
||||
typedef struct { |
||||
upb_sink_frame *top, *limit; |
||||
upb_sink_frame stack[UPB_MAX_NESTING]; |
||||
upb_status status; |
||||
} upb_sink; |
||||
|
||||
// Caller retains ownership of the handlers object.
|
||||
void upb_sink_init(upb_sink *s, const upb_handlers *h); |
||||
|
||||
// Resets the state of the sink so that it is ready to accept new input.
|
||||
// Any state from previously received data is discarded. "Closure" will be
|
||||
// used as the top-level closure.
|
||||
void upb_sink_reset(upb_sink *s, void *closure); |
||||
|
||||
void upb_sink_uninit(upb_sink *s); |
||||
|
||||
// Returns the handlers at the top of the stack.
|
||||
const upb_handlers *upb_sink_tophandlers(upb_sink *s); |
||||
|
||||
// Functions for pushing data into the sink.
|
||||
// These return false if processing should stop (either due to error or just
|
||||
// to suspend).
|
||||
bool upb_sink_startmsg(upb_sink *s); |
||||
void upb_sink_endmsg(upb_sink *s, upb_status *status); |
||||
bool upb_sink_putint32(upb_sink *s, const upb_fielddef *f, int32_t val); |
||||
bool upb_sink_putint64(upb_sink *s, const upb_fielddef *f, int64_t val); |
||||
bool upb_sink_putuint32(upb_sink *s, const upb_fielddef *f, uint32_t val); |
||||
bool upb_sink_putuint64(upb_sink *s, const upb_fielddef *f, uint64_t val); |
||||
bool upb_sink_putfloat(upb_sink *s, const upb_fielddef *f, float val); |
||||
bool upb_sink_putdouble(upb_sink *s, const upb_fielddef *f, double val); |
||||
bool upb_sink_putbool(upb_sink *s, const upb_fielddef *f, bool val); |
||||
bool upb_sink_startstr(upb_sink *s, const upb_fielddef *f, size_t size_hint); |
||||
size_t upb_sink_putstring(upb_sink *s, const upb_fielddef *f, const char *buf, |
||||
size_t len); |
||||
bool upb_sink_endstr(upb_sink *s, const upb_fielddef *f); |
||||
bool upb_sink_startsubmsg(upb_sink *s, const upb_fielddef *f); |
||||
bool upb_sink_endsubmsg(upb_sink *s, const upb_fielddef *f); |
||||
bool upb_sink_startseq(upb_sink *s, const upb_fielddef *f); |
||||
bool upb_sink_endseq(upb_sink *s, const upb_fielddef *f); |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
#endif |
||||
|
||||
#endif |
@ -0,0 +1,326 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2008-2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
*/ |
||||
|
||||
#include "upb/symtab.h" |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "upb/bytestream.h" |
||||
|
||||
bool upb_symtab_isfrozen(const upb_symtab *s) { |
||||
return upb_refcounted_isfrozen(upb_upcast(s)); |
||||
} |
||||
|
||||
void upb_symtab_ref(const upb_symtab *s, const void *owner) { |
||||
upb_refcounted_ref(upb_upcast(s), owner); |
||||
} |
||||
|
||||
void upb_symtab_unref(const upb_symtab *s, const void *owner) { |
||||
upb_refcounted_unref(upb_upcast(s), owner); |
||||
} |
||||
|
||||
void upb_symtab_donateref( |
||||
const upb_symtab *s, const void *from, const void *to) { |
||||
upb_refcounted_donateref(upb_upcast(s), from, to); |
||||
} |
||||
|
||||
void upb_symtab_checkref(const upb_symtab *s, const void *owner) { |
||||
upb_refcounted_checkref(upb_upcast(s), owner); |
||||
} |
||||
|
||||
static void upb_symtab_free(upb_refcounted *r) { |
||||
upb_symtab *s = (upb_symtab*)r; |
||||
upb_strtable_iter i; |
||||
upb_strtable_begin(&i, &s->symtab); |
||||
for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { |
||||
const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); |
||||
upb_def_unref(def, s); |
||||
} |
||||
upb_strtable_uninit(&s->symtab); |
||||
free(s); |
||||
} |
||||
|
||||
static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free}; |
||||
|
||||
upb_symtab *upb_symtab_new(const void *owner) { |
||||
upb_symtab *s = malloc(sizeof(*s)); |
||||
upb_refcounted_init(upb_upcast(s), &vtbl, owner); |
||||
upb_strtable_init(&s->symtab, UPB_CTYPE_PTR); |
||||
return s; |
||||
} |
||||
|
||||
const upb_def **upb_symtab_getdefs(const upb_symtab *s, upb_deftype_t type, |
||||
const void *owner, int *n) { |
||||
int total = upb_strtable_count(&s->symtab); |
||||
// We may only use part of this, depending on how many symbols are of the
|
||||
// correct type.
|
||||
const upb_def **defs = malloc(sizeof(*defs) * total); |
||||
upb_strtable_iter iter; |
||||
upb_strtable_begin(&iter, &s->symtab); |
||||
int i = 0; |
||||
for(; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { |
||||
upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); |
||||
assert(def); |
||||
if(type == UPB_DEF_ANY || def->type == type) |
||||
defs[i++] = def; |
||||
} |
||||
*n = i; |
||||
if (owner) |
||||
for(i = 0; i < *n; i++) upb_def_ref(defs[i], owner); |
||||
return defs; |
||||
} |
||||
|
||||
const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym, |
||||
const void *owner) { |
||||
const upb_value *v = upb_strtable_lookup(&s->symtab, sym); |
||||
upb_def *ret = v ? upb_value_getptr(*v) : NULL; |
||||
if (ret) upb_def_ref(ret, owner); |
||||
return ret; |
||||
} |
||||
|
||||
const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym, |
||||
const void *owner) { |
||||
const upb_value *v = upb_strtable_lookup(&s->symtab, sym); |
||||
upb_def *def = v ? upb_value_getptr(*v) : NULL; |
||||
upb_msgdef *ret = NULL; |
||||
if(def && def->type == UPB_DEF_MSG) { |
||||
ret = upb_downcast_msgdef_mutable(def); |
||||
upb_def_ref(def, owner); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
// Given a symbol and the base symbol inside which it is defined, find the
|
||||
// symbol's definition in t.
|
||||
static upb_def *upb_resolvename(const upb_strtable *t, |
||||
const char *base, const char *sym) { |
||||
if(strlen(sym) == 0) return NULL; |
||||
if(sym[0] == UPB_SYMBOL_SEPARATOR) { |
||||
// Symbols starting with '.' are absolute, so we do a single lookup.
|
||||
// Slice to omit the leading '.'
|
||||
const upb_value *v = upb_strtable_lookup(t, sym + 1); |
||||
return v ? upb_value_getptr(*v) : NULL; |
||||
} else { |
||||
// Remove components from base until we find an entry or run out.
|
||||
// TODO: This branch is totally broken, but currently not used.
|
||||
(void)base; |
||||
assert(false); |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, |
||||
const char *sym, const void *owner) { |
||||
upb_def *ret = upb_resolvename(&s->symtab, base, sym); |
||||
if (ret) upb_def_ref(ret, owner); |
||||
return ret; |
||||
} |
||||
|
||||
// Searches def and its children to find defs that have the same name as any
|
||||
// def in "addtab." Returns true if any where found, and as a side-effect adds
|
||||
// duplicates of these defs into addtab.
|
||||
//
|
||||
// We use a modified depth-first traversal that traverses each SCC (which we
|
||||
// already computed) as if it were a single node. This allows us to traverse
|
||||
// the possibly-cyclic graph as if it were a DAG and to dup the correct set of
|
||||
// nodes with O(n) time.
|
||||
static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab, |
||||
const void *new_owner, upb_inttable *seen, |
||||
upb_status *s) { |
||||
// Memoize results of this function for efficiency (since we're traversing a
|
||||
// DAG this is not needed to limit the depth of the search).
|
||||
const upb_value *v = upb_inttable_lookup(seen, (uintptr_t)def); |
||||
if (v) return upb_value_getbool(*v); |
||||
|
||||
// Visit submessages for all messages in the SCC.
|
||||
bool need_dup = false; |
||||
const upb_def *base = def; |
||||
do { |
||||
assert(upb_def_isfrozen(def)); |
||||
if (def->type == UPB_DEF_FIELD) continue; |
||||
const upb_value *v = upb_strtable_lookup(addtab, upb_def_fullname(def)); |
||||
if (v) { |
||||
// Because we memoize we should not visit a node after we have dup'd it.
|
||||
assert(((upb_def*)upb_value_getptr(*v))->came_from_user); |
||||
need_dup = true; |
||||
} |
||||
const upb_msgdef *m = upb_dyncast_msgdef(def); |
||||
if (m) { |
||||
upb_msg_iter i; |
||||
for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { |
||||
upb_fielddef *f = upb_msg_iter_field(&i); |
||||
if (!upb_fielddef_hassubdef(f)) continue; |
||||
// |= to avoid short-circuit; we need its side-effects.
|
||||
need_dup |= upb_resolve_dfs( |
||||
upb_fielddef_subdef(f), addtab, new_owner, seen, s); |
||||
if (!upb_ok(s)) return false; |
||||
} |
||||
} |
||||
} while ((def = (upb_def*)def->base.next) != base); |
||||
|
||||
if (need_dup) { |
||||
// Dup any defs that don't already have entries in addtab.
|
||||
def = base; |
||||
do { |
||||
if (def->type == UPB_DEF_FIELD) continue; |
||||
const char *name = upb_def_fullname(def); |
||||
if (upb_strtable_lookup(addtab, name) == NULL) { |
||||
upb_def *newdef = upb_def_dup(def, new_owner); |
||||
if (!newdef) goto oom; |
||||
newdef->came_from_user = false; |
||||
if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef))) |
||||
goto oom; |
||||
} |
||||
} while ((def = (upb_def*)def->base.next) != base); |
||||
} |
||||
|
||||
upb_inttable_insert(seen, (uintptr_t)def, upb_value_bool(need_dup)); |
||||
return need_dup; |
||||
|
||||
oom: |
||||
upb_status_seterrliteral(s, "out of memory"); |
||||
return false; |
||||
} |
||||
|
||||
bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, |
||||
upb_status *status) { |
||||
upb_def **add_defs = NULL; |
||||
upb_strtable addtab; |
||||
if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) { |
||||
upb_status_seterrliteral(status, "out of memory"); |
||||
return false; |
||||
} |
||||
|
||||
// Add new defs to table.
|
||||
for (int i = 0; i < n; i++) { |
||||
upb_def *def = defs[i]; |
||||
if (upb_def_isfrozen(def)) { |
||||
upb_status_seterrliteral(status, "added defs must be mutable"); |
||||
goto err; |
||||
} |
||||
assert(!upb_def_isfrozen(def)); |
||||
const char *fullname = upb_def_fullname(def); |
||||
if (!fullname) { |
||||
upb_status_seterrliteral( |
||||
status, "Anonymous defs cannot be added to a symtab"); |
||||
goto err; |
||||
} |
||||
if (upb_strtable_lookup(&addtab, fullname) != NULL) { |
||||
upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); |
||||
goto err; |
||||
} |
||||
// We need this to back out properly, because if there is a failure we need
|
||||
// to donate the ref back to the caller.
|
||||
def->came_from_user = true; |
||||
upb_def_donateref(def, ref_donor, s); |
||||
if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) |
||||
goto oom_err; |
||||
} |
||||
|
||||
// Add dups of any existing def that can reach a def with the same name as
|
||||
// one of "defs."
|
||||
upb_inttable seen; |
||||
if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err; |
||||
upb_strtable_iter i; |
||||
upb_strtable_begin(&i, &s->symtab); |
||||
for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { |
||||
upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); |
||||
upb_resolve_dfs(def, &addtab, s, &seen, status); |
||||
if (!upb_ok(status)) goto err; |
||||
} |
||||
upb_inttable_uninit(&seen); |
||||
|
||||
// Now using the table, resolve symbolic references.
|
||||
upb_strtable_begin(&i, &addtab); |
||||
for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { |
||||
upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); |
||||
upb_msgdef *m = upb_dyncast_msgdef_mutable(def); |
||||
if (!m) continue; |
||||
// Type names are resolved relative to the message in which they appear.
|
||||
const char *base = upb_def_fullname(upb_upcast(m)); |
||||
|
||||
upb_msg_iter j; |
||||
for(upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j)) { |
||||
upb_fielddef *f = upb_msg_iter_field(&j); |
||||
const char *name = upb_fielddef_subdefname(f); |
||||
if (name) { |
||||
upb_def *subdef = upb_resolvename(&addtab, base, name); |
||||
if (subdef == NULL) { |
||||
upb_status_seterrf( |
||||
status, "couldn't resolve name '%s' in message '%s'", name, base); |
||||
goto err; |
||||
} else if (!upb_fielddef_setsubdef(f, subdef)) { |
||||
upb_status_seterrf( |
||||
status, "def '%s' had the wrong type for field '%s'", |
||||
upb_def_fullname(subdef), upb_fielddef_name(f)); |
||||
goto err; |
||||
} |
||||
} |
||||
|
||||
if (!upb_fielddef_resolvedefault(f)) { |
||||
upb_byteregion *r = upb_value_getbyteregion(upb_fielddef_default(f)); |
||||
size_t len; |
||||
const char *ptr = upb_byteregion_getptr(r, 0, &len); |
||||
upb_status_seterrf(status, "couldn't resolve enum default '%s'", ptr); |
||||
goto err; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// We need an array of the defs in addtab, for passing to upb_def_freeze.
|
||||
add_defs = malloc(sizeof(void*) * upb_strtable_count(&addtab)); |
||||
if (add_defs == NULL) goto oom_err; |
||||
upb_strtable_begin(&i, &addtab); |
||||
for (n = 0; !upb_strtable_done(&i); upb_strtable_next(&i)) { |
||||
add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&i)); |
||||
} |
||||
|
||||
if (!upb_def_freeze(add_defs, n, status)) goto err; |
||||
|
||||
// This must be delayed until all errors have been detected, since error
|
||||
// recovery code uses this table to cleanup defs.
|
||||
upb_strtable_uninit(&addtab); |
||||
|
||||
// TODO(haberman) we don't properly handle errors after this point (like
|
||||
// OOM in upb_strtable_insert() below).
|
||||
for (int i = 0; i < n; i++) { |
||||
upb_def *def = add_defs[i]; |
||||
const char *name = upb_def_fullname(def); |
||||
upb_value v; |
||||
if (upb_strtable_remove(&s->symtab, name, &v)) { |
||||
const upb_def *def = upb_value_getptr(v); |
||||
upb_def_unref(def, s); |
||||
} |
||||
bool success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def)); |
||||
UPB_ASSERT_VAR(success, success == true); |
||||
} |
||||
free(add_defs); |
||||
return true; |
||||
|
||||
oom_err: |
||||
upb_status_seterrliteral(status, "out of memory"); |
||||
err: { |
||||
// For defs the user passed in, we need to donate the refs back. For defs
|
||||
// we dup'd, we need to just unref them.
|
||||
upb_strtable_iter i; |
||||
upb_strtable_begin(&i, &addtab); |
||||
for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { |
||||
upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); |
||||
if (def->came_from_user) { |
||||
upb_def_donateref(def, s, ref_donor); |
||||
} else { |
||||
upb_def_unref(def, s); |
||||
} |
||||
def->came_from_user = false; |
||||
} |
||||
} |
||||
upb_strtable_uninit(&addtab); |
||||
free(add_defs); |
||||
assert(!upb_ok(status)); |
||||
return false; |
||||
} |
@ -0,0 +1,200 @@ |
||||
/*
|
||||
* upb - a minimalist implementation of protocol buffers. |
||||
* |
||||
* Copyright (c) 2009-2012 Google Inc. See LICENSE for details. |
||||
* Author: Josh Haberman <jhaberman@gmail.com> |
||||
* |
||||
* A symtab (symbol table) stores a name->def map of upb_defs. Clients could |
||||
* always create such tables themselves, but upb_symtab has logic for resolving |
||||
* symbolic references, and in particular, for keeping a whole set of consistent |
||||
* defs when replacing some subset of those defs. This logic is nontrivial. |
||||
* |
||||
* This is a mixed C/C++ interface that offers a full API to both languages. |
||||
* See the top-level README for more information. |
||||
*/ |
||||
|
||||
#ifndef UPB_SYMTAB_H_ |
||||
#define UPB_SYMTAB_H_ |
||||
|
||||
#ifdef __cplusplus |
||||
#include <vector> |
||||
|
||||
namespace upb { class SymbolTable; } |
||||
typedef upb::SymbolTable upb_symtab; |
||||
#else |
||||
struct upb_symtab; |
||||
typedef struct upb_symtab upb_symtab; |
||||
#endif |
||||
|
||||
#include "upb/def.h" |
||||
|
||||
#ifdef __cplusplus |
||||
|
||||
class upb::SymbolTable { |
||||
public: |
||||
// Returns a new symbol table with a single ref owned by "owner."
|
||||
// Returns NULL if memory allocation failed.
|
||||
static SymbolTable* New(const void* owner); |
||||
|
||||
// Though not declared as such in C++, upb::RefCounted is the base of
|
||||
// SymbolTable and we can upcast to it.
|
||||
RefCounted* Upcast(); |
||||
const RefCounted* Upcast() const; |
||||
|
||||
// Functionality from upb::RefCounted.
|
||||
bool IsFrozen() const; |
||||
void Ref(const void* owner) const; |
||||
void Unref(const void* owner) const; |
||||
void DonateRef(const void *from, const void *to) const; |
||||
void CheckRef(const void *owner) const; |
||||
|
||||
// Resolves the given symbol using the rules described in descriptor.proto,
|
||||
// namely:
|
||||
//
|
||||
// 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).
|
||||
//
|
||||
// If a def is found, the caller owns one ref on the returned def, owned by
|
||||
// owner. Otherwise returns NULL.
|
||||
const Def* Resolve(const char* base, const char* sym, |
||||
const void* owner) const; |
||||
|
||||
// Finds an entry in the symbol table with this exact name. If a def is
|
||||
// found, the caller owns one ref on the returned def, owned by owner.
|
||||
// Otherwise returns NULL.
|
||||
const Def* Lookup(const char *sym, const void *owner) const; |
||||
const MessageDef* LookupMessage(const char *sym, const void *owner) const; |
||||
|
||||
// Gets an array of pointers to all currently active defs in this symtab.
|
||||
// The caller owns the returned array (which is of length *n) as well as a
|
||||
// ref to each symbol inside (owned by owner). If type is UPB_DEF_ANY then
|
||||
// defs of all types are returned, otherwise only defs of the required type
|
||||
// are returned.
|
||||
const Def** GetDefs(upb_deftype_t type, const void *owner, int *n) const; |
||||
|
||||
// Adds the given mutable defs to the symtab, resolving all symbols
|
||||
// (including enum default values) and finalizing the defs. Only one def per
|
||||
// name may be in the list, but defs can replace existing defs in the symtab.
|
||||
// All defs must have a name -- anonymous defs are not allowed. Anonymous
|
||||
// defs can still be frozen by calling upb_def_freeze() directly.
|
||||
//
|
||||
// Any existing defs that can reach defs that are being replaced will
|
||||
// themselves be replaced also, so that the resulting set of defs is fully
|
||||
// consistent.
|
||||
//
|
||||
// This logic implemented in this method is a convenience; ultimately it
|
||||
// calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and
|
||||
// upb_freeze(), any of which the client could call themself. However, since
|
||||
// the logic for doing so is nontrivial, we provide it here.
|
||||
//
|
||||
// The entire operation either succeeds or fails. If the operation fails,
|
||||
// the symtab is unchanged, false is returned, and status indicates the
|
||||
// error. The caller passes a ref on all defs to the symtab (even if the
|
||||
// operation fails).
|
||||
//
|
||||
// TODO(haberman): currently failure will leave the symtab unchanged, but may
|
||||
// leave the defs themselves partially resolved. Does this matter? If so we
|
||||
// could do a prepass that ensures that all symbols are resolvable and bail
|
||||
// if not, so we don't mutate anything until we know the operation will
|
||||
// succeed.
|
||||
//
|
||||
// TODO(haberman): since the defs must be mutable, refining a frozen def
|
||||
// requires making mutable copies of the entire tree. This is wasteful if
|
||||
// only a few messages are changing. We may want to add a way of adding a
|
||||
// tree of frozen defs to the symtab (perhaps an alternate constructor where
|
||||
// you pass the root of the tree?)
|
||||
bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status); |
||||
|
||||
bool Add(const std::vector<Def*>& defs, void *owner, Status* status) { |
||||
return Add((Def*const*)&defs[0], defs.size(), owner, status); |
||||
} |
||||
|
||||
private: |
||||
UPB_DISALLOW_POD_OPS(SymbolTable); |
||||
|
||||
#else |
||||
struct upb_symtab { |
||||
#endif |
||||
upb_refcounted base; |
||||
upb_strtable symtab; |
||||
}; |
||||
|
||||
// Native C API.
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
// From upb_refcounted.
|
||||
bool upb_symtab_isfrozen(const upb_symtab *s); |
||||
void upb_symtab_ref(const upb_symtab *s, const void *owner); |
||||
void upb_symtab_unref(const upb_symtab *s, const void *owner); |
||||
void upb_symtab_donateref( |
||||
const upb_symtab *s, const void *from, const void *to); |
||||
void upb_symtab_checkref(const upb_symtab *s, const void *owner); |
||||
|
||||
upb_symtab *upb_symtab_new(const void *owner); |
||||
const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, |
||||
const char *sym, const void *owner); |
||||
const upb_def *upb_symtab_lookup( |
||||
const upb_symtab *s, const char *sym, const void *owner); |
||||
const upb_msgdef *upb_symtab_lookupmsg( |
||||
const upb_symtab *s, const char *sym, const void *owner); |
||||
const upb_def **upb_symtab_getdefs( |
||||
const upb_symtab *s, upb_deftype_t type, const void *owner, int *n); |
||||
bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, |
||||
upb_status *status); |
||||
|
||||
#ifdef __cplusplus |
||||
} /* extern "C" */ |
||||
|
||||
// C++ inline wrappers.
|
||||
namespace upb { |
||||
inline SymbolTable* SymbolTable::New(const void* owner) { |
||||
return upb_symtab_new(owner); |
||||
} |
||||
|
||||
inline RefCounted* SymbolTable::Upcast() { return upb_upcast(this); } |
||||
inline const RefCounted* SymbolTable::Upcast() const { |
||||
return upb_upcast(this); |
||||
} |
||||
inline bool SymbolTable::IsFrozen() const { |
||||
return upb_symtab_isfrozen(this); |
||||
} |
||||
inline void SymbolTable::Ref(const void *owner) const { |
||||
upb_symtab_ref(this, owner); |
||||
} |
||||
inline void SymbolTable::Unref(const void *owner) const { |
||||
upb_symtab_unref(this, owner); |
||||
} |
||||
inline void SymbolTable::DonateRef(const void *from, const void *to) const { |
||||
upb_symtab_donateref(this, from, to); |
||||
} |
||||
inline void SymbolTable::CheckRef(const void *owner) const { |
||||
upb_symtab_checkref(this, owner); |
||||
} |
||||
|
||||
inline const Def* SymbolTable::Resolve( |
||||
const char* base, const char* sym, const void* owner) const { |
||||
return upb_symtab_resolve(this, base, sym, owner); |
||||
} |
||||
inline const Def* SymbolTable::Lookup( |
||||
const char *sym, const void *owner) const { |
||||
return upb_symtab_lookup(this, sym, owner); |
||||
} |
||||
inline const MessageDef* SymbolTable::LookupMessage( |
||||
const char *sym, const void *owner) const { |
||||
return upb_symtab_lookupmsg(this, sym, owner); |
||||
} |
||||
inline const Def** SymbolTable::GetDefs( |
||||
upb_deftype_t type, const void *owner, int *n) const { |
||||
return upb_symtab_getdefs(this, type, owner, n); |
||||
} |
||||
inline bool SymbolTable::Add( |
||||
Def*const* defs, int n, void* ref_donor, upb_status* status) { |
||||
return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status); |
||||
} |
||||
} // namespace upb
|
||||
#endif |
||||
|
||||
#endif /* UPB_SYMTAB_H_ */ |
Loading…
Reference in new issue