diff options
author | Josh Haberman <jhaberman@gmail.com> | 2013-10-24 12:43:19 -0700 |
---|---|---|
committer | Josh Haberman <jhaberman@gmail.com> | 2013-10-24 12:43:19 -0700 |
commit | 26d98ca94f2f049e8767b4a9a33d185a3d7ea0fd (patch) | |
tree | 340bcf495f06ed05c9f3fb423f210caf4edce2b1 /upb/upb.h | |
parent | 61109fca1f967771c21dc7184aee35f3b439c577 (diff) |
Merge from Google-internal development:
- rewritten decoder; interpreted decoder is bytecode-based,
JIT decoder no longer falls back to the interpreter.
- C++ improvements: C++11-compatible iterators, upb::reffed_ptr
for RAII refcounting, better upcast/downcast support.
- removed the gross upb_value abstraction from public upb.h.
Diffstat (limited to 'upb/upb.h')
-rw-r--r-- | upb/upb.h | 366 |
1 files changed, 37 insertions, 329 deletions
@@ -13,16 +13,8 @@ #ifndef UPB_H_ #define UPB_H_ -#include <assert.h> -#include <limits.h> -#include <stdarg.h> #include <stdbool.h> #include <stddef.h> -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif // inline if possible, emit standalone code if required. #ifdef __cplusplus @@ -54,108 +46,15 @@ extern "C" { void operator=(const class_name&); #endif -#if defined(__clang__) && defined(LANG_CXX11) && defined(__has_warning) -#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") -#define UPB_FALLTHROUGH_INTENDED [[clang::fallthrough]] -#endif -#endif - -#ifndef UPB_FALLTHROUGH_INTENDED -#define UPB_FALLTHROUGH_INTENDED do { } while (0) -#endif - #ifdef __GNUC__ #define UPB_NORETURN __attribute__((__noreturn__)) #else #define UPB_NORETURN #endif -// Type detection and typedefs for integer types. -// For platforms where there are multiple 32-bit or 64-bit types, we need to be -// able to enumerate them so we can properly create overloads for all variants. -// -// If any platform existed where there were three integer types with the same -// size, this would have to become more complicated. For example, short, int, -// and long could all be 32-bits. Even more diabolically, short, int, long, -// and long long could all be 64 bits and still be standard-compliant. -// However, few platforms are this strange, and it's unlikely that upb will be -// used on the strangest ones. - -// Can't count on stdint.h limits like INT32_MAX, because in C++ these are -// only defined when __STDC_LIMIT_MACROS are defined before the *first* include -// of stdint.h. We can't guarantee that someone else didn't include these first -// without defining __STDC_LIMIT_MACROS. -#define UPB_INT32_MAX 0x7fffffffLL -#define UPB_INT32_MIN (-UPB_INT32_MAX - 1) -#define UPB_INT64_MAX 0x7fffffffffffffffLL -#define UPB_INT64_MIN (-UPB_INT64_MAX - 1) - -#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN -#define UPB_INT_IS_32BITS 1 -#endif - -#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN -#define UPB_LONG_IS_32BITS 1 -#endif - -#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN -#define UPB_LONG_IS_64BITS 1 -#endif - -#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN -#define UPB_LLONG_IS_64BITS 1 -#endif - -#if UPB_INT_IS_32BITS -typedef int upb_int32_t; -typedef unsigned int upb_uint32_t; -#define UPB_INT32_CTYPE i - -#if UPB_LONG_IS_32BITS -#define UPB_TWO_32BIT_TYPES 1 -typedef long upb_int32alt_t; -typedef unsigned long upb_uint32alt_t; -#define UPB_INT32_CTYPE2 l -#endif // UPB_LONG_IS_32BITS - -#elif UPB_LONG_IS_32BITS // && !UPB_INT_IS_32BITS -typedef long upb_int32_t; -typedef unsigned long upb_uint32_t; -#define UPB_INT32_CTYPE l -#endif // UPB_INT_IS_32BITS - - -#if UPB_LONG_IS_64BITS -typedef long upb_int64_t; -typedef unsigned long upb_uint64_t; -#define UPB_INT64_CTYPE l - -#if UPB_LLONG_IS_64BITS -#define UPB_TWO_64BIT_TYPES 1 -typedef long long upb_int64alt_t; -typedef unsigned long long upb_uint64alt_t; -#define UPB_INT64_CTYPE2 ll -#endif // UPB_LLONG_IS_64BITS - -#elif UPB_LLONG_IS_64BITS // && !UPB_LONG_IS_64BITS -typedef long long upb_int64_t; -typedef unsigned long long upb_uint64_t; -#define UPB_INT64_CTYPE ll -#endif // UPB_LONG_IS_64BITS - #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) -// For our C-based inheritance, sometimes it's necessary to upcast an object to -// its base class. We try to minimize the need for this by replicating base -// class functions in the derived class -- the derived class functions simply -// forward to the base class implementations. This strategy simplifies the C++ -// API since we can't use real C++ inheritance. -#define upb_upcast(obj) (&(obj)->base) -#define upb_upcast2(obj) upb_upcast(upb_upcast(obj)) - -char *upb_strdup(const char *s); - #define UPB_UNUSED(var) (void)var // For asserting something about a variable when the variable is not used for @@ -163,42 +62,39 @@ char *upb_strdup(const char *s); // debug mode. #define UPB_ASSERT_VAR(var, predicate) UPB_UNUSED(var); assert(predicate) -#define UPB_ASSERT_STATUS(status) do { \ - if (!upb_ok(status)) { \ - fprintf(stderr, "upb status failure: %s\n", upb_status_getstr(status)); \ - assert(upb_ok(status)); \ - } \ - } while (0) - -// The maximum that any submessages can be nested. Matches proto2's limit. -// At the moment this specifies the size of several statically-sized arrays -// and therefore setting it high will cause more memory to be used. Will -// be replaced by a runtime-configurable limit and dynamically-resizing arrays. -// TODO: make this a runtime-settable property of upb_handlers. -#define UPB_MAX_NESTING 64 - -// Inherent limit of protobuf wire format and schema definition. -#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) - -// Nested type names are separated by periods. -#define UPB_SYMBOL_SEPARATOR '.' - -// The longest chain that mutually-recursive types are allowed to form. For -// example, this is a type cycle of length 2: -// message A { -// B b = 1; -// } -// message B { -// A a = 1; -// } -#define UPB_MAX_TYPE_CYCLE_LEN 16 - -// The maximum depth that the type graph can have. Note that this setting does -// not automatically constrain UPB_MAX_NESTING, because type cycles allow for -// unlimited nesting if we do not limit it. Many algorithms in upb call -// recursive functions that traverse the type graph, so we must limit this to -// avoid blowing the C stack. -#define UPB_MAX_TYPE_DEPTH 64 + +/* Casts **********************************************************************/ + +// Upcasts for C. For downcasts see the definitions of the subtypes. +#define UPB_UPCAST(obj) (&(obj)->base) +#define UPB_UPCAST2(obj) UPB_UPCAST(UPB_UPCAST(obj)) + +#ifdef __cplusplus + +// Downcasts for C++. We can't use C++ inheritance directly and maintain +// compatibility with C. So our inheritance is undeclared in C++. +// Specializations of these casting functions are defined for appropriate type +// pairs, and perform the necessary checks. +// +// Example: +// upb::Def* def = <...>; +// upb::MessageDef* = upb::dyn_cast<upb::MessageDef*>(def); +// +// For upcasts, see the Upcast() method in the types themselves. + +namespace upb { + +// Casts to a direct subclass. The caller must know that cast is correct; an +// incorrect cast will throw an assertion failure. +template<class To, class From> To down_cast(From* f); + +// Casts to a direct subclass. If the class does not actually match the given +// subtype, returns NULL. +template<class To, class From> To dyn_cast(From* f); + +} + +#endif /* upb::Status ****************************************************************/ @@ -260,6 +156,10 @@ struct upb_status { #define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0} +#ifdef __cplusplus +extern "C" { +#endif + void upb_status_init(upb_status *status); void upb_status_uninit(upb_status *status); @@ -278,203 +178,11 @@ void upb_status_seteof(upb_status *status); const char *upb_status_getstr(const upb_status *status); void upb_status_copy(upb_status *to, const upb_status *from); -// Like vasprintf (which allocates a string large enough for the result), but -// uses *buf (which can be NULL) as a starting point and reallocates it only if -// the new value will not fit. "size" is updated to reflect the allocated size -// of the buffer. Starts writing at the given offset into the string; bytes -// preceding this offset are unaffected. Returns the new length of the string, -// or -1 on memory allocation failure. -int upb_vrprintf(char **buf, size_t *size, size_t ofs, - const char *fmt, va_list args); - - -/* upb::Value *****************************************************************/ - -// TODO(haberman): upb::Value is gross and should be retired from the public -// interface (we *may* still want to keep it for internal use). upb::Handlers -// and upb::Def should replace their use of Value with one function for each C -// type. - -// Clients should not need to access these enum values; they are used internally -// to do typechecks of upb_value accesses. -typedef enum { - UPB_CTYPE_INT32 = 1, - UPB_CTYPE_INT64 = 2, - UPB_CTYPE_UINT32 = 3, - UPB_CTYPE_UINT64 = 4, - UPB_CTYPE_DOUBLE = 5, - UPB_CTYPE_FLOAT = 6, - UPB_CTYPE_BOOL = 7, - UPB_CTYPE_CSTR = 8, - UPB_CTYPE_PTR = 9, - UPB_CTYPE_BYTEREGION = 10, - UPB_CTYPE_FIELDDEF = 11, -} upb_ctype_t; - -typedef union { - uint64_t uint64; - int32_t int32; - int64_t int64; - uint32_t uint32; - double _double; - float _float; - bool _bool; - char *cstr; - void *ptr; - const void *constptr; -} _upb_value; - -// A single .proto value. The owner must have an out-of-band way of knowing -// the type, so that it knows which union member to use. -typedef struct { - _upb_value val; -#ifndef NDEBUG - // In debug mode we carry the value type around also so we can check accesses - // to be sure the right member is being read. - upb_ctype_t type; -#endif -} upb_value; - -#ifdef UPB_C99 -#define UPB_VALUE_INIT(v, member) {.member = v} -#endif -// TODO(haberman): C++ -// -// -#define UPB__VALUE_INIT_NONE UPB_VALUE_INIT(NULL, ptr) - -#ifdef NDEBUG -#define SET_TYPE(dest, val) UPB_UNUSED(val) -#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE} -#else -#define SET_TYPE(dest, val) dest = val -// Non-existent type, all reads will fail. -#define UPB_VALUE_INIT_NONE {UPB__VALUE_INIT_NONE, -1} -#endif - -#define UPB_VALUE_INIT_INT32(v) UPB_VALUE_INIT(v, int32) -#define UPB_VALUE_INIT_INT64(v) UPB_VALUE_INIT(v, int64) -#define UPB_VALUE_INIT_UINT32(v) UPB_VALUE_INIT(v, uint32) -#define UPB_VALUE_INIT_UINT64(v) UPB_VALUE_INIT(v, uint64) -#define UPB_VALUE_INIT_DOUBLE(v) UPB_VALUE_INIT(v, _double) -#define UPB_VALUE_INIT_FLOAT(v) UPB_VALUE_INIT(v, _float) -#define UPB_VALUE_INIT_BOOL(v) UPB_VALUE_INIT(v, _bool) -#define UPB_VALUE_INIT_CSTR(v) UPB_VALUE_INIT(v, cstr) -#define UPB_VALUE_INIT_PTR(v) UPB_VALUE_INIT(v, ptr) -#define UPB_VALUE_INIT_CONSTPTR(v) UPB_VALUE_INIT(v, constptr) - -UPB_INLINE void _upb_value_setval(upb_value *v, _upb_value val, - upb_ctype_t type) { - v->val = val; - SET_TYPE(v->type, type); -} - -UPB_INLINE upb_value _upb_value_val(_upb_value val, upb_ctype_t type) { - upb_value ret; - _upb_value_setval(&ret, val, type); - return ret; -} - -// For each value type, define the following set of functions: -// -// // Get/set an int32 from a upb_value. -// int32_t upb_value_getint32(upb_value val); -// void upb_value_setint32(upb_value *val, int32_t cval); -// -// // Construct a new upb_value from an int32. -// upb_value upb_value_int32(int32_t val); - -#define WRITERS(name, membername, ctype, proto_type) \ - UPB_INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ - val->val.uint64 = 0; \ - SET_TYPE(val->type, proto_type); \ - val->val.membername = cval; \ - } \ - UPB_INLINE upb_value upb_value_ ## name(ctype val) { \ - upb_value ret; \ - upb_value_set ## name(&ret, val); \ - return ret; \ - } - -#define ALL(name, membername, ctype, proto_type) \ - /* Can't reuse WRITERS() here unfortunately because "bool" is a macro \ - * that expands to _Bool, so it ends up defining eg. upb_value_set_Bool */ \ - UPB_INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ - val->val.uint64 = 0; \ - SET_TYPE(val->type, proto_type); \ - val->val.membername = cval; \ - } \ - UPB_INLINE upb_value upb_value_ ## name(ctype val) { \ - upb_value ret; \ - upb_value_set ## name(&ret, val); \ - return ret; \ - } \ - UPB_INLINE ctype upb_value_get ## name(upb_value val) { \ - assert(val.type == proto_type); \ - return val.val.membername; \ - } - -ALL(int32, int32, int32_t, UPB_CTYPE_INT32); -ALL(int64, int64, int64_t, UPB_CTYPE_INT64); -ALL(uint32, uint32, uint32_t, UPB_CTYPE_UINT32); -ALL(uint64, uint64, uint64_t, UPB_CTYPE_UINT64); -ALL(bool, _bool, bool, UPB_CTYPE_BOOL); -ALL(cstr, cstr, char*, UPB_CTYPE_CSTR); -ALL(ptr, ptr, void*, UPB_CTYPE_PTR); - -#ifdef __KERNEL__ -// Linux kernel modules are compiled without SSE and therefore are incapable -// of compiling functions that return floating-point values, so we define as -// macros instead and lose the type check. -WRITERS(double, _double, double, UPB_CTYPE_DOUBLE); -WRITERS(float, _float, float, UPB_CTYPE_FLOAT); -#define upb_value_getdouble(v) (v.val._double) -#define upb_value_getfloat(v) (v.val._float) -#else -ALL(double, _double, double, UPB_CTYPE_DOUBLE); -ALL(float, _float, float, UPB_CTYPE_FLOAT); -#endif /* __KERNEL__ */ - -#undef WRITERS -#undef ALL - -extern upb_value UPB_NO_VALUE; - #ifdef __cplusplus } // extern "C" namespace upb { -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)); -} - // C++ Wrappers inline Status::Status() { upb_status_init(this); } inline Status::~Status() { upb_status_uninit(this); } |