/* * upb - a minimalist implementation of protocol buffers. * * Copyright (c) 2009 Google Inc. See LICENSE for details. * Author: Josh Haberman * * This file contains shared definitions that are widely used across upb. * * 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_H_ #define UPB_H_ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif // inline if possible, emit standalone code if required. #ifdef __cplusplus #define UPB_INLINE inline #else #define UPB_INLINE static inline #endif #if __STDC_VERSION__ >= 199901L #define UPB_C99 #endif #if ((defined(__cplusplus) && __cplusplus >= 201103L) || \ defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11) #define UPB_CXX11 #endif #ifdef UPB_CXX11 #define UPB_DISALLOW_POD_OPS(class_name) \ class_name() = delete; \ ~class_name() = delete; \ class_name(const class_name&) = delete; \ void operator=(const class_name&) = delete; #else #define UPB_DISALLOW_POD_OPS(class_name) \ class_name(); \ ~class_name(); \ class_name(const class_name&); \ 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 // anything else. This prevents "unused variable" warnings when compiling in // 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 /* upb::Status ****************************************************************/ #ifdef __cplusplus namespace upb { class Status; } typedef upb::Status upb_status; #else struct upb_status; typedef struct upb_status upb_status; #endif typedef enum { UPB_OK, // The operation completed successfully. UPB_SUSPENDED, // The operation was suspended and may be resumed later. UPB_ERROR, // An error occurred. } upb_success_t; typedef struct { const char *name; // Writes a NULL-terminated string to "buf" containing an error message for // the given error code, returning false if the message was too large to fit. bool (*code_to_string)(int code, char *buf, size_t len); } upb_errorspace; #ifdef __cplusplus class upb::Status { public: typedef upb_success_t Success; Status(); ~Status(); bool ok() const; bool eof() const; const char *GetString() const; void SetEof(); void SetErrorLiteral(const char* msg); void Clear(); private: #else struct upb_status { #endif bool error; bool eof_; // Specific status code defined by some error space (optional). int code; upb_errorspace *space; // Error message (optional). const char *str; // NULL when no message is present. NULL-terminated. char *buf; // Owned by the status. size_t bufsize; }; #define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0} void upb_status_init(upb_status *status); void upb_status_uninit(upb_status *status); bool upb_ok(const upb_status *status); bool upb_eof(const upb_status *status); // Any of the functions that write to a status object allow status to be NULL, // to support use cases where the function's caller does not care about the // status message. void upb_status_clear(upb_status *status); void upb_status_seterrliteral(upb_status *status, const char *msg); void upb_status_seterrf(upb_status *status, const char *msg, ...); void upb_status_setcode(upb_status *status, upb_errorspace *space, int code); void upb_status_seteof(upb_status *status); // The returned string is invalidated by any other call into the 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 T GetValue(Value v); template Value MakeValue(T v); #define UPB_VALUE_ACCESSORS(type, ctype) \ template <> inline ctype GetValue(Value v) { \ return upb_value_get ## type(v); \ } \ template <> inline Value MakeValue(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 inline T* GetPtrValue(Value v) { return static_cast(upb_value_getptr(v)); } template inline Value MakePtrValue(T* v) { return upb_value_ptr(static_cast(v)); } // C++ Wrappers inline Status::Status() { upb_status_init(this); } inline Status::~Status() { upb_status_uninit(this); } inline bool Status::ok() const { return upb_ok(this); } inline bool Status::eof() const { return upb_eof(this); } inline const char *Status::GetString() const { return upb_status_getstr(this); } inline void Status::SetEof() { upb_status_seteof(this); } inline void Status::SetErrorLiteral(const char* msg) { upb_status_seterrliteral(this, msg); } inline void Status::Clear() { upb_status_clear(this); } } // namespace upb #endif #endif /* UPB_H_ */