blob: 0708e375440f2ec3f85845acb994957937616969 [file] [log] [blame]
// Ruby is still using proto3 enum semantics for proto2
#define UPB_DISABLE_CLOSED_ENUM_CHECKING
/* Amalgamated source file */
/*
* This is where we define internal portability macros used across upb.
*
* All of these macros are undef'd in undef.inc to avoid leaking them to users.
*
* The correct usage is:
*
* #include "upb/foobar.h"
* #include "upb/baz.h"
*
* // MUST be last included header.
* #include "upb/port/def.inc"
*
* // Code for this file.
* // <...>
*
* // Can be omitted for .c files, required for .h.
* #include "upb/port/undef.inc"
*
* This file is private and must not be included by users!
*/
#if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
(defined(__cplusplus) && __cplusplus >= 201402L) || \
(defined(_MSC_VER) && _MSC_VER >= 1900))
#error upb requires C99 or C++14 or MSVC >= 2015.
#endif
// Portable check for GCC minimum version:
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define UPB_GNUC_MIN(x, y) \
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else
#define UPB_GNUC_MIN(x, y) 0
#endif
#include <assert.h>
#include <setjmp.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef UINTPTR_MAX
Error, UINTPTR_MAX is undefined
#endif
#if UINTPTR_MAX == 0xffffffff
#define UPB_SIZE(size32, size64) size32
#else
#define UPB_SIZE(size32, size64) size64
#endif
/* If we always read/write as a consistent type to each address, this shouldn't
* violate aliasing.
*/
#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs)))
#define UPB_MAPTYPE_STRING 0
// UPB_EXPORT: always generate a public symbol.
#if defined(__GNUC__) || defined(__clang__)
#define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used))
#else
#define UPB_EXPORT
#endif
// UPB_INLINE: inline if possible, emit standalone code if required.
#ifdef __cplusplus
#define UPB_INLINE inline
#elif defined (__GNUC__) || defined(__clang__)
#define UPB_INLINE static __inline__
#else
#define UPB_INLINE static
#endif
#ifdef UPB_BUILD_API
#define UPB_API UPB_EXPORT
#define UPB_API_INLINE UPB_EXPORT
#else
#define UPB_API
#define UPB_API_INLINE UPB_INLINE
#endif
#ifdef EXPORT_UPBC
#define UPBC_API UPB_EXPORT
#else
#define UPBC_API
#endif
#define UPB_MALLOC_ALIGN 8
#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align))
#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align))
#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN)
#ifdef __clang__
#define UPB_ALIGN_OF(type) _Alignof(type)
#else
#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member)
#endif
#ifdef _MSC_VER
// Some versions of our Windows compiler don't support the C11 syntax.
#define UPB_ALIGN_AS(x) __declspec(align(x))
#else
#define UPB_ALIGN_AS(x) _Alignas(x)
#endif
// Hints to the compiler about likely/unlikely branches.
#if defined (__GNUC__) || defined(__clang__)
#define UPB_LIKELY(x) __builtin_expect((bool)(x), 1)
#define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0)
#else
#define UPB_LIKELY(x) (x)
#define UPB_UNLIKELY(x) (x)
#endif
// Macros for function attributes on compilers that support them.
#ifdef __GNUC__
#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static
#define UPB_NOINLINE __attribute__((noinline))
#define UPB_NORETURN __attribute__((__noreturn__))
#define UPB_PRINTF(str, first_vararg) __attribute__((format (printf, str, first_vararg)))
#elif defined(_MSC_VER)
#define UPB_NOINLINE
#define UPB_FORCEINLINE static
#define UPB_NORETURN __declspec(noreturn)
#define UPB_PRINTF(str, first_vararg)
#else /* !defined(__GNUC__) */
#define UPB_FORCEINLINE static
#define UPB_NOINLINE
#define UPB_NORETURN
#define UPB_PRINTF(str, first_vararg)
#endif
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
#define UPB_UNUSED(var) (void)var
// UPB_ASSUME(): in release mode, we tell the compiler to assume this is true.
#ifdef NDEBUG
#ifdef __GNUC__
#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable()
#elif defined _MSC_VER
#define UPB_ASSUME(expr) if (!(expr)) __assume(0)
#else
#define UPB_ASSUME(expr) do {} while (false && (expr))
#endif
#else
#define UPB_ASSUME(expr) assert(expr)
#endif
/* UPB_ASSERT(): in release mode, we use the expression without letting it be
* evaluated. This prevents "unused variable" warnings. */
#ifdef NDEBUG
#define UPB_ASSERT(expr) do {} while (false && (expr))
#else
#define UPB_ASSERT(expr) assert(expr)
#endif
#if defined(__GNUC__) || defined(__clang__)
#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0)
#elif defined(_MSC_VER)
#define UPB_UNREACHABLE() \
do { \
assert(0); \
__assume(0); \
} while (0)
#else
#define UPB_UNREACHABLE() do { assert(0); } while(0)
#endif
/* UPB_SETJMP() / UPB_LONGJMP(): avoid setting/restoring signal mask. */
#ifdef __APPLE__
#define UPB_SETJMP(buf) _setjmp(buf)
#define UPB_LONGJMP(buf, val) _longjmp(buf, val)
#elif defined(WASM_WAMR)
#define UPB_SETJMP(buf) 0
#define UPB_LONGJMP(buf, val) abort()
#else
#define UPB_SETJMP(buf) setjmp(buf)
#define UPB_LONGJMP(buf, val) longjmp(buf, val)
#endif
#ifdef __GNUC__
#define UPB_USE_C11_ATOMICS
#define UPB_ATOMIC(T) _Atomic(T)
#else
#define UPB_ATOMIC(T) T
#endif
/* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */
#define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr))
#define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only
#ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY
#define UPB_ONLYBITS(x) x
#else
#define UPB_ONLYBITS(x) UPB_PRIVATE(x)
#endif
/* Configure whether fasttable is switched on or not. *************************/
#ifdef __has_attribute
#define UPB_HAS_ATTRIBUTE(x) __has_attribute(x)
#else
#define UPB_HAS_ATTRIBUTE(x) 0
#endif
#if UPB_HAS_ATTRIBUTE(musttail)
#define UPB_MUSTTAIL __attribute__((musttail))
#else
#define UPB_MUSTTAIL
#endif
#undef UPB_HAS_ATTRIBUTE
/* This check is not fully robust: it does not require that we have "musttail"
* support available. We need tail calls to avoid consuming arbitrary amounts
* of stack space.
*
* GCC/Clang can mostly be trusted to generate tail calls as long as
* optimization is enabled, but, debug builds will not generate tail calls
* unless "musttail" is available.
*
* We should probably either:
* 1. require that the compiler supports musttail.
* 2. add some fallback code for when musttail isn't available (ie. return
* instead of tail calling). This is safe and portable, but this comes at
* a CPU cost.
*/
#if (defined(__x86_64__) || defined(__aarch64__)) && defined(__GNUC__)
#define UPB_FASTTABLE_SUPPORTED 1
#else
#define UPB_FASTTABLE_SUPPORTED 0
#endif
/* define UPB_ENABLE_FASTTABLE to force fast table support.
* This is useful when we want to ensure we are really getting fasttable,
* for example for testing or benchmarking. */
#if defined(UPB_ENABLE_FASTTABLE)
#if !UPB_FASTTABLE_SUPPORTED
#error fasttable is x86-64/ARM64 only and requires GCC or Clang.
#endif
#define UPB_FASTTABLE 1
/* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible.
* This is useful for releasing code that might be used on multiple platforms,
* for example the PHP or Ruby C extensions. */
#elif defined(UPB_TRY_ENABLE_FASTTABLE)
#define UPB_FASTTABLE UPB_FASTTABLE_SUPPORTED
#else
#define UPB_FASTTABLE 0
#endif
/* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully
* degrade to non-fasttable if the runtime or platform do not support it. */
#if !UPB_FASTTABLE
#define UPB_FASTTABLE_INIT(...)
#define UPB_FASTTABLE_MASK(mask) -1
#else
#define UPB_FASTTABLE_INIT(...) __VA_ARGS__
#define UPB_FASTTABLE_MASK(mask) mask
#endif
#undef UPB_FASTTABLE_SUPPORTED
/* ASAN poisoning (for arena).
* If using UPB from an interpreted language like Ruby, a build of the
* interpreter compiled with ASAN enabled must be used in order to get sane and
* expected behavior.
*/
/* Due to preprocessor limitations, the conditional logic for setting
* UPN_CLANG_ASAN below cannot be consolidated into a portable one-liner.
* See https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html.
*/
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
#define UPB_CLANG_ASAN 1
#else
#define UPB_CLANG_ASAN 0
#endif
#else
#define UPB_CLANG_ASAN 0
#endif
#if defined(__SANITIZE_ADDRESS__) || UPB_CLANG_ASAN
#define UPB_ASAN 1
#define UPB_ASAN_GUARD_SIZE 32
#ifdef __cplusplus
extern "C" {
#endif
void __asan_poison_memory_region(void const volatile *addr, size_t size);
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
#ifdef __cplusplus
} /* extern "C" */
#endif
#define UPB_POISON_MEMORY_REGION(addr, size) \
__asan_poison_memory_region((addr), (size))
#define UPB_UNPOISON_MEMORY_REGION(addr, size) \
__asan_unpoison_memory_region((addr), (size))
#else
#define UPB_ASAN 0
#define UPB_ASAN_GUARD_SIZE 0
#define UPB_POISON_MEMORY_REGION(addr, size) \
((void)(addr), (void)(size))
#define UPB_UNPOISON_MEMORY_REGION(addr, size) \
((void)(addr), (void)(size))
#endif
/* Disable proto2 arena behavior (TEMPORARY) **********************************/
#ifdef UPB_DISABLE_CLOSED_ENUM_CHECKING
#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 1
#else
#define UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN 0
#endif
#if defined(__cplusplus)
#if defined(__clang__) || UPB_GNUC_MIN(6, 0)
// https://gcc.gnu.org/gcc-6/changes.html
#if __cplusplus >= 201402L
#define UPB_DEPRECATED [[deprecated]]
#else
#define UPB_DEPRECATED __attribute__((deprecated))
#endif
#else
#define UPB_DEPRECATED
#endif
#else
#define UPB_DEPRECATED
#endif
#if defined(UPB_IS_GOOGLE3) && \
(!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0)
#define UPB_DESC(sym) proto2_##sym
#define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init
#elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0
#define UPB_DESC(sym) google_protobuf_##sym
#define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init()
#else
#define UPB_DESC(sym) google_protobuf_##sym
#define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init
#endif
#undef UPB_IS_GOOGLE3
// Linker arrays combine elements from multiple translation units into a single
// array that can be iterated over at runtime.
//
// It is an alternative to pre-main "registration" functions.
//
// Usage:
//
// // In N translation units.
// UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3};
//
// // At runtime:
// UPB_LINKARR_DECLARE(foo_array, int);
//
// void f() {
// const int* start = UPB_LINKARR_START(foo_array);
// const int* stop = UPB_LINKARR_STOP(foo_array);
// for (const int* p = start; p < stop; p++) {
// // Windows can introduce zero padding, so we have to skip zeroes.
// if (*p != 0) {
// vec.push_back(*p);
// }
// }
// }
#if defined(__ELF__) || defined(__wasm__)
#define UPB_LINKARR_APPEND(name) \
__attribute__((retain, used, section("linkarr_" #name), \
no_sanitize("address")))
#define UPB_LINKARR_DECLARE(name, type) \
extern type const __start_linkarr_##name; \
extern type const __stop_linkarr_##name; \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
#elif defined(__MACH__)
/* As described in: https://stackoverflow.com/a/22366882 */
#define UPB_LINKARR_APPEND(name) \
__attribute__((retain, used, section("__DATA,__la_" #name), \
no_sanitize("address")))
#define UPB_LINKARR_DECLARE(name, type) \
extern type const __start_linkarr_##name __asm( \
"section$start$__DATA$__la_" #name); \
extern type const __stop_linkarr_##name __asm( \
"section$end$__DATA$" \
"__la_" #name); \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1]
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
#elif defined(_MSC_VER) && defined(__clang__)
/* See:
* https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155
* https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165
* https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */
// Usage of __attribute__ here probably means this is Clang-specific, and would
// not work on MSVC.
#define UPB_LINKARR_APPEND(name) \
__declspec(allocate("la_" #name "$j")) \
__attribute__((retain, used, no_sanitize("address")))
#define UPB_LINKARR_DECLARE(name, type) \
__declspec(allocate("la_" #name "$a")) type __start_linkarr_##name; \
__declspec(allocate("la_" #name "$z")) type __stop_linkarr_##name; \
UPB_LINKARR_APPEND(name) type UPB_linkarr_internal_empty_##name[1] = {0}
#define UPB_LINKARR_START(name) (&__start_linkarr_##name)
#define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name)
#else
// Linker arrays are not supported on this platform. Make appends a no-op but
// don't define the other macros.
#define UPB_LINKARR_APPEND(name)
#endif
// Future versions of upb will include breaking changes to some APIs.
// This macro can be set to enable these API changes ahead of time, so that
// user code can be updated before upgrading versions of protobuf.
#ifdef UPB_FUTURE_BREAKING_CHANGES
// Properly enforce closed enums in python.
// Owner: mkruskal@
#define UPB_FUTURE_PYTHON_CLOSED_ENUM_ENFORCEMENT 1
#endif
#ifndef UPB_BASE_STATUS_H_
#define UPB_BASE_STATUS_H_
#include <stdarg.h>
// Must be last.
#define _kUpb_Status_MaxMessage 511
typedef struct {
bool ok;
char msg[_kUpb_Status_MaxMessage]; // Error message; NULL-terminated.
} upb_Status;
#ifdef __cplusplus
extern "C" {
#endif
UPB_API const char* upb_Status_ErrorMessage(const upb_Status* status);
UPB_API bool upb_Status_IsOk(const upb_Status* status);
// These are no-op if |status| is NULL.
UPB_API void upb_Status_Clear(upb_Status* status);
void upb_Status_SetErrorMessage(upb_Status* status, const char* msg);
void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...)
UPB_PRINTF(2, 3);
void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt,
va_list args) UPB_PRINTF(2, 0);
void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt,
va_list args) UPB_PRINTF(2, 0);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_BASE_STATUS_H_ */
#ifndef UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
#define UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
#include <string.h>
/* upb_Arena is a specific allocator implementation that uses arena allocation.
* The user provides an allocator that will be used to allocate the underlying
* arena blocks. Arenas by nature do not require the individual allocations
* to be freed. However the Arena does allow users to register cleanup
* functions that will run when the arena is destroyed.
*
* A upb_Arena is *not* thread-safe.
*
* You could write a thread-safe arena allocator that satisfies the
* upb_alloc interface, but it would not be as efficient for the
* single-threaded case. */
#ifndef UPB_MEM_ARENA_H_
#define UPB_MEM_ARENA_H_
#include <stddef.h>
#include <stdint.h>
#ifndef UPB_MEM_ALLOC_H_
#define UPB_MEM_ALLOC_H_
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct upb_alloc upb_alloc;
/* A combined `malloc()`/`free()` function.
* If `size` is 0 then the function acts like `free()`, otherwise it acts like
* `realloc()`. Only `oldsize` bytes from a previous allocation are
* preserved. */
typedef void* upb_alloc_func(upb_alloc* alloc, void* ptr, size_t oldsize,
size_t size);
/* A upb_alloc is a possibly-stateful allocator object.
*
* It could either be an arena allocator (which doesn't require individual
* `free()` calls) or a regular `malloc()` (which does). The client must
* therefore free memory unless it knows that the allocator is an arena
* allocator. */
struct upb_alloc {
upb_alloc_func* func;
};
UPB_INLINE void* upb_malloc(upb_alloc* alloc, size_t size) {
UPB_ASSERT(alloc);
return alloc->func(alloc, NULL, 0, size);
}
UPB_INLINE void* upb_realloc(upb_alloc* alloc, void* ptr, size_t oldsize,
size_t size) {
UPB_ASSERT(alloc);
return alloc->func(alloc, ptr, oldsize, size);
}
UPB_INLINE void upb_free(upb_alloc* alloc, void* ptr) {
UPB_ASSERT(alloc);
alloc->func(alloc, ptr, 0, 0);
}
// The global allocator used by upb. Uses the standard malloc()/free().
extern upb_alloc upb_alloc_global;
/* Functions that hard-code the global malloc.
*
* We still get benefit because we can put custom logic into our global
* allocator, like injecting out-of-memory faults in debug/testing builds. */
UPB_INLINE void* upb_gmalloc(size_t size) {
return upb_malloc(&upb_alloc_global, size);
}
UPB_INLINE void* upb_grealloc(void* ptr, size_t oldsize, size_t size) {
return upb_realloc(&upb_alloc_global, ptr, oldsize, size);
}
UPB_INLINE void upb_gfree(void* ptr) { upb_free(&upb_alloc_global, ptr); }
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MEM_ALLOC_H_ */
#ifndef UPB_MEM_INTERNAL_ARENA_H_
#define UPB_MEM_INTERNAL_ARENA_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
// Must be last.
// This is QUITE an ugly hack, which specifies the number of pointers needed
// to equal (or exceed) the storage required for one upb_Arena.
//
// We need this because the decoder inlines a upb_Arena for performance but
// the full struct is not visible outside of arena.c. Yes, I know, it's awful.
#define UPB_ARENA_SIZE_HACK 7
// LINT.IfChange(upb_Arena)
struct upb_Arena {
char* UPB_ONLYBITS(ptr);
char* UPB_ONLYBITS(end);
};
// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/arena.ts:upb_Arena)
#ifdef __cplusplus
extern "C" {
#endif
void UPB_PRIVATE(_upb_Arena_SwapIn)(struct upb_Arena* des,
const struct upb_Arena* src);
void UPB_PRIVATE(_upb_Arena_SwapOut)(struct upb_Arena* des,
const struct upb_Arena* src);
// Returns whether |ptr| was allocated directly by |a| (so care must be used
// with fused arenas).
UPB_API bool UPB_ONLYBITS(_upb_Arena_Contains)(const struct upb_Arena* a,
void* ptr);
UPB_INLINE size_t UPB_PRIVATE(_upb_ArenaHas)(const struct upb_Arena* a) {
return (size_t)(a->UPB_ONLYBITS(end) - a->UPB_ONLYBITS(ptr));
}
UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size) {
void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(struct upb_Arena * a, size_t size);
size = UPB_ALIGN_MALLOC(size);
const size_t span = size + UPB_ASAN_GUARD_SIZE;
if (UPB_UNLIKELY(UPB_PRIVATE(_upb_ArenaHas)(a) < span)) {
return UPB_PRIVATE(_upb_Arena_SlowMalloc)(a, span);
}
// We have enough space to do a fast malloc.
void* ret = a->UPB_ONLYBITS(ptr);
UPB_ASSERT(UPB_ALIGN_MALLOC((uintptr_t)ret) == (uintptr_t)ret);
UPB_ASSERT(UPB_ALIGN_MALLOC(size) == size);
UPB_UNPOISON_MEMORY_REGION(ret, size);
a->UPB_ONLYBITS(ptr) += span;
return ret;
}
UPB_API_INLINE void* upb_Arena_Realloc(struct upb_Arena* a, void* ptr,
size_t oldsize, size_t size) {
oldsize = UPB_ALIGN_MALLOC(oldsize);
size = UPB_ALIGN_MALLOC(size);
bool is_most_recent_alloc =
(uintptr_t)ptr + oldsize == (uintptr_t)a->UPB_ONLYBITS(ptr);
if (is_most_recent_alloc) {
ptrdiff_t diff = size - oldsize;
if ((ptrdiff_t)UPB_PRIVATE(_upb_ArenaHas)(a) >= diff) {
a->UPB_ONLYBITS(ptr) += diff;
return ptr;
}
} else if (size <= oldsize) {
return ptr;
}
void* ret = upb_Arena_Malloc(a, size);
if (ret && oldsize > 0) {
memcpy(ret, ptr, UPB_MIN(oldsize, size));
}
return ret;
}
UPB_API_INLINE void upb_Arena_ShrinkLast(struct upb_Arena* a, void* ptr,
size_t oldsize, size_t size) {
oldsize = UPB_ALIGN_MALLOC(oldsize);
size = UPB_ALIGN_MALLOC(size);
// Must be the last alloc.
UPB_ASSERT((char*)ptr + oldsize ==
a->UPB_ONLYBITS(ptr) - UPB_ASAN_GUARD_SIZE);
UPB_ASSERT(size <= oldsize);
a->UPB_ONLYBITS(ptr) = (char*)ptr + size;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MEM_INTERNAL_ARENA_H_ */
// Must be last.
typedef struct upb_Arena upb_Arena;
#ifdef __cplusplus
extern "C" {
#endif
// Creates an arena from the given initial block (if any -- n may be 0).
// Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this
// is a fixed-size arena and cannot grow.
UPB_API upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc);
UPB_API void upb_Arena_Free(upb_Arena* a);
UPB_API bool upb_Arena_Fuse(upb_Arena* a, upb_Arena* b);
bool upb_Arena_IncRefFor(upb_Arena* a, const void* owner);
void upb_Arena_DecRefFor(upb_Arena* a, const void* owner);
size_t upb_Arena_SpaceAllocated(upb_Arena* a, size_t* fused_count);
uint32_t upb_Arena_DebugRefCount(upb_Arena* a);
UPB_API_INLINE upb_Arena* upb_Arena_New(void) {
return upb_Arena_Init(NULL, 0, &upb_alloc_global);
}
UPB_API_INLINE void* upb_Arena_Malloc(struct upb_Arena* a, size_t size);
UPB_API_INLINE void* upb_Arena_Realloc(upb_Arena* a, void* ptr, size_t oldsize,
size_t size);
// Sets the maximum block size for all arenas. This is a global configuration
// setting that will affect all existing and future arenas. If
// upb_Arena_Malloc() is called with a size larger than this, we will exceed
// this size and allocate a larger block.
//
// This API is meant for experimentation only. It will likely be removed in
// the future.
void upb_Arena_SetMaxBlockSize(size_t max);
// Shrinks the last alloc from arena.
// REQUIRES: (ptr, oldsize) was the last malloc/realloc from this arena.
// We could also add a upb_Arena_TryShrinkLast() which is simply a no-op if
// this was not the last alloc.
UPB_API_INLINE void upb_Arena_ShrinkLast(upb_Arena* a, void* ptr,
size_t oldsize, size_t size);
#ifdef UPB_TRACING_ENABLED
void upb_Arena_SetTraceHandler(void (*initArenaTraceHandler)(const upb_Arena*,
size_t size),
void (*fuseArenaTraceHandler)(const upb_Arena*,
const upb_Arena*),
void (*freeArenaTraceHandler)(const upb_Arena*));
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MEM_ARENA_H_ */
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
// The maximum number of bytes a single protobuf field can take up in the
// wire format. We only want to do one bounds check per field, so the input
// stream guarantees that after upb_EpsCopyInputStream_IsDone() is called,
// the decoder can read this many bytes without performing another bounds
// check. The stream will copy into a patch buffer as necessary to guarantee
// this invariant.
#define kUpb_EpsCopyInputStream_SlopBytes 16
enum {
kUpb_EpsCopyInputStream_NoAliasing = 0,
kUpb_EpsCopyInputStream_OnPatch = 1,
kUpb_EpsCopyInputStream_NoDelta = 2
};
typedef struct {
const char* end; // Can read up to SlopBytes bytes beyond this.
const char* limit_ptr; // For bounds checks, = end + UPB_MIN(limit, 0)
uintptr_t aliasing;
int limit; // Submessage limit relative to end
bool error; // To distinguish between EOF and error.
char patch[kUpb_EpsCopyInputStream_SlopBytes * 2];
} upb_EpsCopyInputStream;
// Returns true if the stream is in the error state. A stream enters the error
// state when the user reads past a limit (caught in IsDone()) or the
// ZeroCopyInputStream returns an error.
UPB_INLINE bool upb_EpsCopyInputStream_IsError(upb_EpsCopyInputStream* e) {
return e->error;
}
typedef const char* upb_EpsCopyInputStream_BufferFlipCallback(
upb_EpsCopyInputStream* e, const char* old_end, const char* new_start);
typedef const char* upb_EpsCopyInputStream_IsDoneFallbackFunc(
upb_EpsCopyInputStream* e, const char* ptr, int overrun);
// Initializes a upb_EpsCopyInputStream using the contents of the buffer
// [*ptr, size]. Updates `*ptr` as necessary to guarantee that at least
// kUpb_EpsCopyInputStream_SlopBytes are available to read.
UPB_INLINE void upb_EpsCopyInputStream_Init(upb_EpsCopyInputStream* e,
const char** ptr, size_t size,
bool enable_aliasing) {
if (size <= kUpb_EpsCopyInputStream_SlopBytes) {
memset(&e->patch, 0, 32);
if (size) memcpy(&e->patch, *ptr, size);
e->aliasing = enable_aliasing ? (uintptr_t)*ptr - (uintptr_t)e->patch
: kUpb_EpsCopyInputStream_NoAliasing;
*ptr = e->patch;
e->end = *ptr + size;
e->limit = 0;
} else {
e->end = *ptr + size - kUpb_EpsCopyInputStream_SlopBytes;
e->limit = kUpb_EpsCopyInputStream_SlopBytes;
e->aliasing = enable_aliasing ? kUpb_EpsCopyInputStream_NoDelta
: kUpb_EpsCopyInputStream_NoAliasing;
}
e->limit_ptr = e->end;
e->error = false;
}
typedef enum {
// The current stream position is at a limit.
kUpb_IsDoneStatus_Done,
// The current stream position is not at a limit.
kUpb_IsDoneStatus_NotDone,
// The current stream position is not at a limit, and the stream needs to
// be flipped to a new buffer before more data can be read.
kUpb_IsDoneStatus_NeedFallback,
} upb_IsDoneStatus;
// Returns the status of the current stream position. This is a low-level
// function, it is simpler to call upb_EpsCopyInputStream_IsDone() if possible.
UPB_INLINE upb_IsDoneStatus upb_EpsCopyInputStream_IsDoneStatus(
upb_EpsCopyInputStream* e, const char* ptr, int* overrun) {
*overrun = ptr - e->end;
if (UPB_LIKELY(ptr < e->limit_ptr)) {
return kUpb_IsDoneStatus_NotDone;
} else if (UPB_LIKELY(*overrun == e->limit)) {
return kUpb_IsDoneStatus_Done;
} else {
return kUpb_IsDoneStatus_NeedFallback;
}
}
// Returns true if the stream has hit a limit, either the current delimited
// limit or the overall end-of-stream. As a side effect, this function may flip
// the pointer to a new buffer if there are less than
// kUpb_EpsCopyInputStream_SlopBytes of data to be read in the current buffer.
//
// Postcondition: if the function returns false, there are at least
// kUpb_EpsCopyInputStream_SlopBytes of data available to read at *ptr.
UPB_INLINE bool upb_EpsCopyInputStream_IsDoneWithCallback(
upb_EpsCopyInputStream* e, const char** ptr,
upb_EpsCopyInputStream_IsDoneFallbackFunc* func) {
int overrun;
switch (upb_EpsCopyInputStream_IsDoneStatus(e, *ptr, &overrun)) {
case kUpb_IsDoneStatus_Done:
return true;
case kUpb_IsDoneStatus_NotDone:
return false;
case kUpb_IsDoneStatus_NeedFallback:
*ptr = func(e, *ptr, overrun);
return *ptr == NULL;
}
UPB_UNREACHABLE();
}
const char* _upb_EpsCopyInputStream_IsDoneFallbackNoCallback(
upb_EpsCopyInputStream* e, const char* ptr, int overrun);
// A simpler version of IsDoneWithCallback() that does not support a buffer flip
// callback. Useful in cases where we do not need to insert custom logic at
// every buffer flip.
//
// If this returns true, the user must call upb_EpsCopyInputStream_IsError()
// to distinguish between EOF and error.
UPB_INLINE bool upb_EpsCopyInputStream_IsDone(upb_EpsCopyInputStream* e,
const char** ptr) {
return upb_EpsCopyInputStream_IsDoneWithCallback(
e, ptr, _upb_EpsCopyInputStream_IsDoneFallbackNoCallback);
}
// Returns the total number of bytes that are safe to read from the current
// buffer without reading uninitialized or unallocated memory.
//
// Note that this check does not respect any semantic limits on the stream,
// either limits from PushLimit() or the overall stream end, so some of these
// bytes may have unpredictable, nonsense values in them. The guarantee is only
// that the bytes are valid to read from the perspective of the C language
// (ie. you can read without triggering UBSAN or ASAN).
UPB_INLINE size_t upb_EpsCopyInputStream_BytesAvailable(
upb_EpsCopyInputStream* e, const char* ptr) {
return (e->end - ptr) + kUpb_EpsCopyInputStream_SlopBytes;
}
// Returns true if the given delimited field size is valid (it does not extend
// beyond any previously-pushed limits). `ptr` should point to the beginning
// of the field data, after the delimited size.
//
// Note that this does *not* guarantee that all of the data for this field is in
// the current buffer.
UPB_INLINE bool upb_EpsCopyInputStream_CheckSize(
const upb_EpsCopyInputStream* e, const char* ptr, int size) {
UPB_ASSERT(size >= 0);
return ptr - e->end + size <= e->limit;
}
UPB_INLINE bool _upb_EpsCopyInputStream_CheckSizeAvailable(
upb_EpsCopyInputStream* e, const char* ptr, int size, bool submessage) {
// This is one extra branch compared to the more normal:
// return (size_t)(end - ptr) < size;
// However it is one less computation if we are just about to use "ptr + len":
// https://godbolt.org/z/35YGPz
// In microbenchmarks this shows a small improvement.
uintptr_t uptr = (uintptr_t)ptr;
uintptr_t uend = (uintptr_t)e->limit_ptr;
uintptr_t res = uptr + (size_t)size;
if (!submessage) uend += kUpb_EpsCopyInputStream_SlopBytes;
// NOTE: this check depends on having a linear address space. This is not
// technically guaranteed by uintptr_t.
bool ret = res >= uptr && res <= uend;
if (size < 0) UPB_ASSERT(!ret);
return ret;
}
// Returns true if the given delimited field size is valid (it does not extend
// beyond any previously-pushed limited) *and* all of the data for this field is
// available to be read in the current buffer.
//
// If the size is negative, this function will always return false. This
// property can be useful in some cases.
UPB_INLINE bool upb_EpsCopyInputStream_CheckDataSizeAvailable(
upb_EpsCopyInputStream* e, const char* ptr, int size) {
return _upb_EpsCopyInputStream_CheckSizeAvailable(e, ptr, size, false);
}
// Returns true if the given sub-message size is valid (it does not extend
// beyond any previously-pushed limited) *and* all of the data for this
// sub-message is available to be parsed in the current buffer.
//
// This implies that all fields from the sub-message can be parsed from the
// current buffer while maintaining the invariant that we always have at least
// kUpb_EpsCopyInputStream_SlopBytes of data available past the beginning of
// any individual field start.
//
// If the size is negative, this function will always return false. This
// property can be useful in some cases.
UPB_INLINE bool upb_EpsCopyInputStream_CheckSubMessageSizeAvailable(
upb_EpsCopyInputStream* e, const char* ptr, int size) {
return _upb_EpsCopyInputStream_CheckSizeAvailable(e, ptr, size, true);
}
// Returns true if aliasing_enabled=true was passed to
// upb_EpsCopyInputStream_Init() when this stream was initialized.
UPB_INLINE bool upb_EpsCopyInputStream_AliasingEnabled(
upb_EpsCopyInputStream* e) {
return e->aliasing != kUpb_EpsCopyInputStream_NoAliasing;
}
// Returns true if aliasing_enabled=true was passed to
// upb_EpsCopyInputStream_Init() when this stream was initialized *and* we can
// alias into the region [ptr, size] in an input buffer.
UPB_INLINE bool upb_EpsCopyInputStream_AliasingAvailable(
upb_EpsCopyInputStream* e, const char* ptr, size_t size) {
// When EpsCopyInputStream supports streaming, this will need to become a
// runtime check.
return upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size) &&
e->aliasing >= kUpb_EpsCopyInputStream_NoDelta;
}
// Returns a pointer into an input buffer that corresponds to the parsing
// pointer `ptr`. The returned pointer may be the same as `ptr`, but also may
// be different if we are currently parsing out of the patch buffer.
//
// REQUIRES: Aliasing must be available for the given pointer. If the input is a
// flat buffer and aliasing is enabled, then aliasing will always be available.
UPB_INLINE const char* upb_EpsCopyInputStream_GetAliasedPtr(
upb_EpsCopyInputStream* e, const char* ptr) {
UPB_ASSUME(upb_EpsCopyInputStream_AliasingAvailable(e, ptr, 0));
uintptr_t delta =
e->aliasing == kUpb_EpsCopyInputStream_NoDelta ? 0 : e->aliasing;
return (const char*)((uintptr_t)ptr + delta);
}
// Reads string data from the input, aliasing into the input buffer instead of
// copying. The parsing pointer is passed in `*ptr`, and will be updated if
// necessary to point to the actual input buffer. Returns the new parsing
// pointer, which will be advanced past the string data.
//
// REQUIRES: Aliasing must be available for this data region (test with
// upb_EpsCopyInputStream_AliasingAvailable().
UPB_INLINE const char* upb_EpsCopyInputStream_ReadStringAliased(
upb_EpsCopyInputStream* e, const char** ptr, size_t size) {
UPB_ASSUME(upb_EpsCopyInputStream_AliasingAvailable(e, *ptr, size));
const char* ret = *ptr + size;
*ptr = upb_EpsCopyInputStream_GetAliasedPtr(e, *ptr);
UPB_ASSUME(ret != NULL);
return ret;
}
// Skips `size` bytes of data from the input and returns a pointer past the end.
// Returns NULL on end of stream or error.
UPB_INLINE const char* upb_EpsCopyInputStream_Skip(upb_EpsCopyInputStream* e,
const char* ptr, int size) {
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size)) return NULL;
return ptr + size;
}
// Copies `size` bytes of data from the input `ptr` into the buffer `to`, and
// returns a pointer past the end. Returns NULL on end of stream or error.
UPB_INLINE const char* upb_EpsCopyInputStream_Copy(upb_EpsCopyInputStream* e,
const char* ptr, void* to,
int size) {
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, ptr, size)) return NULL;
memcpy(to, ptr, size);
return ptr + size;
}
// Reads string data from the stream and advances the pointer accordingly.
// If aliasing was enabled when the stream was initialized, then the returned
// pointer will point into the input buffer if possible, otherwise new data
// will be allocated from arena and copied into. We may be forced to copy even
// if aliasing was enabled if the input data spans input buffers.
//
// Returns NULL if memory allocation failed, or we reached a premature EOF.
UPB_INLINE const char* upb_EpsCopyInputStream_ReadString(
upb_EpsCopyInputStream* e, const char** ptr, size_t size,
upb_Arena* arena) {
if (upb_EpsCopyInputStream_AliasingAvailable(e, *ptr, size)) {
return upb_EpsCopyInputStream_ReadStringAliased(e, ptr, size);
} else {
// We need to allocate and copy.
if (!upb_EpsCopyInputStream_CheckDataSizeAvailable(e, *ptr, size)) {
return NULL;
}
UPB_ASSERT(arena);
char* data = (char*)upb_Arena_Malloc(arena, size);
if (!data) return NULL;
const char* ret = upb_EpsCopyInputStream_Copy(e, *ptr, data, size);
*ptr = data;
return ret;
}
}
UPB_INLINE void _upb_EpsCopyInputStream_CheckLimit(upb_EpsCopyInputStream* e) {
UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit));
}
// Pushes a limit onto the stack of limits for the current stream. The limit
// will extend for `size` bytes beyond the position in `ptr`. Future calls to
// upb_EpsCopyInputStream_IsDone() will return `true` when the stream position
// reaches this limit.
//
// Returns a delta that the caller must store and supply to PopLimit() below.
UPB_INLINE int upb_EpsCopyInputStream_PushLimit(upb_EpsCopyInputStream* e,
const char* ptr, int size) {
int limit = size + (int)(ptr - e->end);
int delta = e->limit - limit;
_upb_EpsCopyInputStream_CheckLimit(e);
UPB_ASSERT(limit <= e->limit);
e->limit = limit;
e->limit_ptr = e->end + UPB_MIN(0, limit);
_upb_EpsCopyInputStream_CheckLimit(e);
return delta;
}
// Pops the last limit that was pushed on this stream. This may only be called
// once IsDone() returns true. The user must pass the delta that was returned
// from PushLimit().
UPB_INLINE void upb_EpsCopyInputStream_PopLimit(upb_EpsCopyInputStream* e,
const char* ptr,
int saved_delta) {
UPB_ASSERT(ptr - e->end == e->limit);
_upb_EpsCopyInputStream_CheckLimit(e);
e->limit += saved_delta;
e->limit_ptr = e->end + UPB_MIN(0, e->limit);
_upb_EpsCopyInputStream_CheckLimit(e);
}
UPB_INLINE const char* _upb_EpsCopyInputStream_IsDoneFallbackInline(
upb_EpsCopyInputStream* e, const char* ptr, int overrun,
upb_EpsCopyInputStream_BufferFlipCallback* callback) {
if (overrun < e->limit) {
// Need to copy remaining data into patch buffer.
UPB_ASSERT(overrun < kUpb_EpsCopyInputStream_SlopBytes);
const char* old_end = ptr;
const char* new_start = &e->patch[0] + overrun;
memset(e->patch + kUpb_EpsCopyInputStream_SlopBytes, 0,
kUpb_EpsCopyInputStream_SlopBytes);
memcpy(e->patch, e->end, kUpb_EpsCopyInputStream_SlopBytes);
ptr = new_start;
e->end = &e->patch[kUpb_EpsCopyInputStream_SlopBytes];
e->limit -= kUpb_EpsCopyInputStream_SlopBytes;
e->limit_ptr = e->end + e->limit;
UPB_ASSERT(ptr < e->limit_ptr);
if (e->aliasing != kUpb_EpsCopyInputStream_NoAliasing) {
e->aliasing = (uintptr_t)old_end - (uintptr_t)new_start;
}
return callback(e, old_end, new_start);
} else {
UPB_ASSERT(overrun > e->limit);
e->error = true;
return callback(e, NULL, NULL);
}
}
typedef const char* upb_EpsCopyInputStream_ParseDelimitedFunc(
upb_EpsCopyInputStream* e, const char* ptr, void* ctx);
// Tries to perform a fast-path handling of the given delimited message data.
// If the sub-message beginning at `*ptr` and extending for `len` is short and
// fits within this buffer, calls `func` with `ctx` as a parameter, where the
// pushing and popping of limits is handled automatically and with lower cost
// than the normal PushLimit()/PopLimit() sequence.
UPB_FORCEINLINE bool upb_EpsCopyInputStream_TryParseDelimitedFast(
upb_EpsCopyInputStream* e, const char** ptr, int len,
upb_EpsCopyInputStream_ParseDelimitedFunc* func, void* ctx) {
if (!upb_EpsCopyInputStream_CheckSubMessageSizeAvailable(e, *ptr, len)) {
return false;
}
// Fast case: Sub-message is <128 bytes and fits in the current buffer.
// This means we can preserve limit/limit_ptr verbatim.
const char* saved_limit_ptr = e->limit_ptr;
int saved_limit = e->limit;
e->limit_ptr = *ptr + len;
e->limit = e->limit_ptr - e->end;
UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit));
*ptr = func(e, *ptr, ctx);
e->limit_ptr = saved_limit_ptr;
e->limit = saved_limit;
UPB_ASSERT(e->limit_ptr == e->end + UPB_MIN(0, e->limit));
return true;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif // UPB_WIRE_EPS_COPY_INPUT_STREAM_H_
#ifndef UPB_JSON_DECODE_H_
#define UPB_JSON_DECODE_H_
#ifndef UPB_REFLECTION_DEF_H_
#define UPB_REFLECTION_DEF_H_
// IWYU pragma: begin_exports
// IWYU pragma: private, include "upb/reflection/def.h"
#ifndef UPB_REFLECTION_DEF_POOL_H_
#define UPB_REFLECTION_DEF_POOL_H_
#ifndef UPB_BASE_STRING_VIEW_H_
#define UPB_BASE_STRING_VIEW_H_
#include <string.h>
// Must be last.
#define UPB_STRINGVIEW_INIT(ptr, len) \
{ ptr, len }
#define UPB_STRINGVIEW_FORMAT "%.*s"
#define UPB_STRINGVIEW_ARGS(view) (int)(view).size, (view).data
// LINT.IfChange(struct_definition)
typedef struct {
const char* data;
size_t size;
} upb_StringView;
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE upb_StringView upb_StringView_FromDataAndSize(const char* data,
size_t size) {
upb_StringView ret;
ret.data = data;
ret.size = size;
return ret;
}
UPB_INLINE upb_StringView upb_StringView_FromString(const char* data) {
return upb_StringView_FromDataAndSize(data, strlen(data));
}
UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b) {
return (a.size == b.size) && (!a.size || !memcmp(a.data, b.data, a.size));
}
// LINT.ThenChange(
// GoogleInternalName1,
// //depot/google3/third_party/upb/bits/golang/accessor.go:map_go_string,
// //depot/google3/third_party/upb/bits/typescript/string_view.ts
// )
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_BASE_STRING_VIEW_H_ */
// IWYU pragma: private, include "upb/reflection/def.h"
// Declarations common to all public def types.
#ifndef UPB_REFLECTION_COMMON_H_
#define UPB_REFLECTION_COMMON_H_
#ifndef THIRD_PARTY_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H_
#define THIRD_PARTY_UPB_UPB_REFLECTION_DESCRIPTOR_BOOTSTRAP_H_
// IWYU pragma: begin_exports
#if defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0
// This header is checked in.
#elif UPB_BOOTSTRAP_STAGE == 1
// This header is generated at build time by the bootstrapping process.
#else
// This is the normal header, generated by upb_c_proto_library().
/* This file was generated by upb_generator from the input file:
*
* google/protobuf/descriptor.proto
*
* Do not edit -- your changes will be discarded when the file is
* regenerated.
* NO CHECKED-IN PROTOBUF GENCODE */
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_
#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H__UPB_H_
#ifndef UPB_GENERATED_CODE_SUPPORT_H_
#define UPB_GENERATED_CODE_SUPPORT_H_
// IWYU pragma: begin_exports
#ifndef UPB_BASE_UPCAST_H_
#define UPB_BASE_UPCAST_H_
// Must be last.
// This macro provides a way to upcast message pointers in a way that is
// somewhat more bulletproof than blindly casting a pointer. Example:
//
// typedef struct {
// upb_Message UPB_PRIVATE(base);
// } pkg_FooMessage;
//
// void f(pkg_FooMessage* msg) {
// upb_Decode(UPB_UPCAST(msg), ...);
// }
#define UPB_UPCAST(x) (&(x)->base##_dont_copy_me__upb_internal_use_only)
#endif /* UPB_BASE_UPCAST_H_ */
#ifndef UPB_MESSAGE_ACCESSORS_H_
#define UPB_MESSAGE_ACCESSORS_H_
#include <stdint.h>
#ifndef UPB_MESSAGE_ARRAY_H_
#define UPB_MESSAGE_ARRAY_H_
#include <stddef.h>
#ifndef UPB_BASE_DESCRIPTOR_CONSTANTS_H_
#define UPB_BASE_DESCRIPTOR_CONSTANTS_H_
// Must be last.
// The types a field can have. Note that this list is not identical to the
// types defined in descriptor.proto, which gives INT32 and SINT32 separate
// types (we distinguish the two with the "integer encoding" enum below).
// This enum is an internal convenience only and has no meaning outside of upb.
typedef enum {
kUpb_CType_Bool = 1,
kUpb_CType_Float = 2,
kUpb_CType_Int32 = 3,
kUpb_CType_UInt32 = 4,
kUpb_CType_Enum = 5, // Enum values are int32. TODO: rename
kUpb_CType_Message = 6,
kUpb_CType_Double = 7,
kUpb_CType_Int64 = 8,
kUpb_CType_UInt64 = 9,
kUpb_CType_String = 10,
kUpb_CType_Bytes = 11
} upb_CType;
// The repeated-ness of each field; this matches descriptor.proto.
typedef enum {
kUpb_Label_Optional = 1,
kUpb_Label_Required = 2,
kUpb_Label_Repeated = 3
} upb_Label;
// Descriptor types, as defined in descriptor.proto.
typedef enum {
kUpb_FieldType_Double = 1,
kUpb_FieldType_Float = 2,
kUpb_FieldType_Int64 = 3,
kUpb_FieldType_UInt64 = 4,
kUpb_FieldType_Int32 = 5,
kUpb_FieldType_Fixed64 = 6,
kUpb_FieldType_Fixed32 = 7,
kUpb_FieldType_Bool = 8,
kUpb_FieldType_String = 9,
kUpb_FieldType_Group = 10,
kUpb_FieldType_Message = 11,
kUpb_FieldType_Bytes = 12,
kUpb_FieldType_UInt32 = 13,
kUpb_FieldType_Enum = 14,
kUpb_FieldType_SFixed32 = 15,
kUpb_FieldType_SFixed64 = 16,
kUpb_FieldType_SInt32 = 17,
kUpb_FieldType_SInt64 = 18,
} upb_FieldType;
#define kUpb_FieldType_SizeOf 19
#ifdef __cplusplus
extern "C" {
#endif
// Convert from upb_FieldType to upb_CType
UPB_INLINE upb_CType upb_FieldType_CType(upb_FieldType field_type) {
static const upb_CType c_type[] = {
kUpb_CType_Double, // kUpb_FieldType_Double
kUpb_CType_Float, // kUpb_FieldType_Float
kUpb_CType_Int64, // kUpb_FieldType_Int64
kUpb_CType_UInt64, // kUpb_FieldType_UInt64
kUpb_CType_Int32, // kUpb_FieldType_Int32
kUpb_CType_UInt64, // kUpb_FieldType_Fixed64
kUpb_CType_UInt32, // kUpb_FieldType_Fixed32
kUpb_CType_Bool, // kUpb_FieldType_Bool
kUpb_CType_String, // kUpb_FieldType_String
kUpb_CType_Message, // kUpb_FieldType_Group
kUpb_CType_Message, // kUpb_FieldType_Message
kUpb_CType_Bytes, // kUpb_FieldType_Bytes
kUpb_CType_UInt32, // kUpb_FieldType_UInt32
kUpb_CType_Enum, // kUpb_FieldType_Enum
kUpb_CType_Int32, // kUpb_FieldType_SFixed32
kUpb_CType_Int64, // kUpb_FieldType_SFixed64
kUpb_CType_Int32, // kUpb_FieldType_SInt32
kUpb_CType_Int64, // kUpb_FieldType_SInt64
};
// -1 here because the enum is one-based but the table is zero-based.
return c_type[field_type - 1];
}
UPB_INLINE bool upb_FieldType_IsPackable(upb_FieldType field_type) {
// clang-format off
const unsigned kUnpackableTypes =
(1 << kUpb_FieldType_String) |
(1 << kUpb_FieldType_Bytes) |
(1 << kUpb_FieldType_Message) |
(1 << kUpb_FieldType_Group);
// clang-format on
return (1 << field_type) & ~kUnpackableTypes;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_BASE_DESCRIPTOR_CONSTANTS_H_ */
#ifndef UPB_MESSAGE_INTERNAL_ARRAY_H_
#define UPB_MESSAGE_INTERNAL_ARRAY_H_
#include <stdint.h>
#include <string.h>
// Must be last.
#define _UPB_ARRAY_MASK_IMM 0x4 // Frozen/immutable bit.
#define _UPB_ARRAY_MASK_LG2 0x3 // Encoded elem size.
#define _UPB_ARRAY_MASK_ALL (_UPB_ARRAY_MASK_IMM | _UPB_ARRAY_MASK_LG2)
#ifdef __cplusplus
extern "C" {
#endif
// LINT.IfChange(upb_Array)
// Our internal representation for repeated fields.
struct upb_Array {
// This is a tagged pointer. Bits #0 and #1 encode the elem size as follows:
// 0 maps to elem size 1
// 1 maps to elem size 4
// 2 maps to elem size 8
// 3 maps to elem size 16
//
// Bit #2 contains the frozen/immutable flag.
uintptr_t UPB_ONLYBITS(data);
size_t UPB_ONLYBITS(size); // The number of elements in the array.
size_t UPB_PRIVATE(capacity); // Allocated storage. Measured in elements.
};
UPB_INLINE void UPB_PRIVATE(_upb_Array_ShallowFreeze)(struct upb_Array* arr) {
arr->UPB_ONLYBITS(data) |= _UPB_ARRAY_MASK_IMM;
}
UPB_API_INLINE bool upb_Array_IsFrozen(const struct upb_Array* arr) {
return (arr->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_IMM) != 0;
}
UPB_INLINE void UPB_PRIVATE(_upb_Array_SetTaggedPtr)(struct upb_Array* array,
void* data, size_t lg2) {
UPB_ASSERT(lg2 != 1);
UPB_ASSERT(lg2 <= 4);
const size_t bits = lg2 - (lg2 != 0);
array->UPB_ONLYBITS(data) = (uintptr_t)data | bits;
}
UPB_INLINE size_t
UPB_PRIVATE(_upb_Array_ElemSizeLg2)(const struct upb_Array* array) {
const size_t bits = array->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_LG2;
const size_t lg2 = bits + (bits != 0);
return lg2;
}
UPB_API_INLINE const void* upb_Array_DataPtr(const struct upb_Array* array) {
UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); // Check assertions.
return (void*)(array->UPB_ONLYBITS(data) & ~(uintptr_t)_UPB_ARRAY_MASK_ALL);
}
UPB_API_INLINE void* upb_Array_MutableDataPtr(struct upb_Array* array) {
return (void*)upb_Array_DataPtr(array);
}
UPB_INLINE struct upb_Array* UPB_PRIVATE(_upb_Array_New)(upb_Arena* arena,
size_t init_capacity,
int elem_size_lg2) {
UPB_ASSERT(elem_size_lg2 != 1);
UPB_ASSERT(elem_size_lg2 <= 4);
const size_t array_size =
UPB_ALIGN_UP(sizeof(struct upb_Array), UPB_MALLOC_ALIGN);
const size_t bytes = array_size + (init_capacity << elem_size_lg2);
struct upb_Array* array = (struct upb_Array*)upb_Arena_Malloc(arena, bytes);
if (!array) return NULL;
UPB_PRIVATE(_upb_Array_SetTaggedPtr)
(array, UPB_PTR_AT(array, array_size, void), elem_size_lg2);
array->UPB_ONLYBITS(size) = 0;
array->UPB_PRIVATE(capacity) = init_capacity;
return array;
}
// Resizes the capacity of the array to be at least min_size.
bool UPB_PRIVATE(_upb_Array_Realloc)(struct upb_Array* array, size_t min_size,
upb_Arena* arena);
UPB_API_INLINE bool upb_Array_Reserve(struct upb_Array* array, size_t size,
upb_Arena* arena) {
UPB_ASSERT(!upb_Array_IsFrozen(array));
if (array->UPB_PRIVATE(capacity) < size)
return UPB_PRIVATE(_upb_Array_Realloc)(array, size, arena);
return true;
}
// Resize without initializing new elements.
UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)(
struct upb_Array* array, size_t size, upb_Arena* arena) {
UPB_ASSERT(!upb_Array_IsFrozen(array));
UPB_ASSERT(size <= array->UPB_ONLYBITS(size) ||
arena); // Allow NULL arena when shrinking.
if (!upb_Array_Reserve(array, size, arena)) return false;
array->UPB_ONLYBITS(size) = size;
return true;
}
// This function is intended for situations where elem_size is compile-time
// constant or a known expression of the form (1 << lg2), so that the expression
// i*elem_size does not result in an actual multiplication.
UPB_INLINE void UPB_PRIVATE(_upb_Array_Set)(struct upb_Array* array, size_t i,
const void* data,
size_t elem_size) {
UPB_ASSERT(!upb_Array_IsFrozen(array));
UPB_ASSERT(i < array->UPB_ONLYBITS(size));
UPB_ASSERT(elem_size == 1U << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array));
char* arr_data = (char*)upb_Array_MutableDataPtr(array);
memcpy(arr_data + (i * elem_size), data, elem_size);
}
UPB_API_INLINE size_t upb_Array_Size(const struct upb_Array* arr) {
return arr->UPB_ONLYBITS(size);
}
// LINT.ThenChange(GoogleInternalName0)
#ifdef __cplusplus
} /* extern "C" */
#endif
#undef _UPB_ARRAY_MASK_IMM
#undef _UPB_ARRAY_MASK_LG2
#undef _UPB_ARRAY_MASK_ALL
#endif /* UPB_MESSAGE_INTERNAL_ARRAY_H_ */
// Users should include array.h or map.h instead.
// IWYU pragma: private, include "upb/message/array.h"
#ifndef UPB_MESSAGE_VALUE_H_
#define UPB_MESSAGE_VALUE_H_
#include <stdint.h>
#include <string.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
typedef union {
bool bool_val;
float float_val;
double double_val;
int32_t int32_val;
int64_t int64_val;
uint32_t uint32_val;
uint64_t uint64_val;
const struct upb_Array* array_val;
const struct upb_Map* map_val;
const struct upb_Message* msg_val;
upb_StringView str_val;
// EXPERIMENTAL: A tagged upb_Message*. Users must use this instead of
// msg_val if unlinked sub-messages may possibly be in use. See the
// documentation in kUpb_DecodeOption_ExperimentalAllowUnlinked for more
// information.
uintptr_t tagged_msg_val; // upb_TaggedMessagePtr
} upb_MessageValue;
UPB_API_INLINE upb_MessageValue upb_MessageValue_Zero(void) {
upb_MessageValue zero;
memset(&zero, 0, sizeof(zero));
return zero;
}
typedef union {
struct upb_Array* array;
struct upb_Map* map;
struct upb_Message* msg;
} upb_MutableMessageValue;
UPB_API_INLINE upb_MutableMessageValue upb_MutableMessageValue_Zero(void) {
upb_MutableMessageValue zero;
memset(&zero, 0, sizeof(zero));
return zero;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_VALUE_H_ */
#ifndef UPB_MINI_TABLE_FIELD_H_
#define UPB_MINI_TABLE_FIELD_H_
#include <stdint.h>
#ifndef UPB_MINI_TABLE_INTERNAL_FIELD_H_
#define UPB_MINI_TABLE_INTERNAL_FIELD_H_
#include <stddef.h>
#include <stdint.h>
#ifndef UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_
#define UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_
#include <stddef.h>
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
// Return the log2 of the storage size in bytes for a upb_CType
UPB_INLINE int UPB_PRIVATE(_upb_CType_SizeLg2)(upb_CType c_type) {
static const int8_t size[] = {
0, // kUpb_CType_Bool
2, // kUpb_CType_Float
2, // kUpb_CType_Int32
2, // kUpb_CType_UInt32
2, // kUpb_CType_Enum
UPB_SIZE(2, 3), // kUpb_CType_Message
3, // kUpb_CType_Double
3, // kUpb_CType_Int64
3, // kUpb_CType_UInt64
UPB_SIZE(3, 4), // kUpb_CType_String
UPB_SIZE(3, 4), // kUpb_CType_Bytes
};
// -1 here because the enum is one-based but the table is zero-based.
return size[c_type - 1];
}
// Return the log2 of the storage size in bytes for a upb_FieldType
UPB_INLINE int UPB_PRIVATE(_upb_FieldType_SizeLg2)(upb_FieldType field_type) {
static const int8_t size[] = {
3, // kUpb_FieldType_Double
2, // kUpb_FieldType_Float
3, // kUpb_FieldType_Int64
3, // kUpb_FieldType_UInt64
2, // kUpb_FieldType_Int32
3, // kUpb_FieldType_Fixed64
2, // kUpb_FieldType_Fixed32
0, // kUpb_FieldType_Bool
UPB_SIZE(3, 4), // kUpb_FieldType_String
UPB_SIZE(2, 3), // kUpb_FieldType_Group
UPB_SIZE(2, 3), // kUpb_FieldType_Message
UPB_SIZE(3, 4), // kUpb_FieldType_Bytes
2, // kUpb_FieldType_UInt32
2, // kUpb_FieldType_Enum
2, // kUpb_FieldType_SFixed32
3, // kUpb_FieldType_SFixed64
2, // kUpb_FieldType_SInt32
3, // kUpb_FieldType_SInt64
};
// -1 here because the enum is one-based but the table is zero-based.
return size[field_type - 1];
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_SIZE_LOG2_H_ */
// Must be last.
// LINT.IfChange(struct_definition)
struct upb_MiniTableField {
uint32_t UPB_ONLYBITS(number);
uint16_t UPB_ONLYBITS(offset);
int16_t presence; // If >0, hasbit_index. If <0, ~oneof_index
// Indexes into `upb_MiniTable.subs`
// Will be set to `kUpb_NoSub` if `descriptortype` != MESSAGE/GROUP/ENUM
uint16_t UPB_PRIVATE(submsg_index);
uint8_t UPB_PRIVATE(descriptortype);
// upb_FieldMode | upb_LabelFlags | (upb_FieldRep << kUpb_FieldRep_Shift)
uint8_t UPB_ONLYBITS(mode);
};
#define kUpb_NoSub ((uint16_t) - 1)
typedef enum {
kUpb_FieldMode_Map = 0,
kUpb_FieldMode_Array = 1,
kUpb_FieldMode_Scalar = 2,
} upb_FieldMode;
// Mask to isolate the upb_FieldMode from field.mode.
#define kUpb_FieldMode_Mask 3
// Extra flags on the mode field.
typedef enum {
kUpb_LabelFlags_IsPacked = 4,
kUpb_LabelFlags_IsExtension = 8,
// Indicates that this descriptor type is an "alternate type":
// - for Int32, this indicates that the actual type is Enum (but was
// rewritten to Int32 because it is an open enum that requires no check).
// - for Bytes, this indicates that the actual type is String (but does
// not require any UTF-8 check).
kUpb_LabelFlags_IsAlternate = 16,
} upb_LabelFlags;
// Note: we sort by this number when calculating layout order.
typedef enum {
kUpb_FieldRep_1Byte = 0,
kUpb_FieldRep_4Byte = 1,
kUpb_FieldRep_StringView = 2,
kUpb_FieldRep_8Byte = 3,
kUpb_FieldRep_NativePointer =
UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte),
kUpb_FieldRep_Max = kUpb_FieldRep_8Byte,
} upb_FieldRep;
#define kUpb_FieldRep_Shift 6
#ifdef __cplusplus
extern "C" {
#endif
UPB_INLINE upb_FieldMode
UPB_PRIVATE(_upb_MiniTableField_Mode)(const struct upb_MiniTableField* f) {
return (upb_FieldMode)(f->UPB_ONLYBITS(mode) & kUpb_FieldMode_Mask);
}
UPB_INLINE upb_FieldRep
UPB_PRIVATE(_upb_MiniTableField_GetRep)(const struct upb_MiniTableField* f) {
return (upb_FieldRep)(f->UPB_ONLYBITS(mode) >> kUpb_FieldRep_Shift);
}
UPB_API_INLINE bool upb_MiniTableField_IsArray(
const struct upb_MiniTableField* f) {
return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Array;
}
UPB_API_INLINE bool upb_MiniTableField_IsMap(
const struct upb_MiniTableField* f) {
return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Map;
}
UPB_API_INLINE bool upb_MiniTableField_IsScalar(
const struct upb_MiniTableField* f) {
return UPB_PRIVATE(_upb_MiniTableField_Mode)(f) == kUpb_FieldMode_Scalar;
}
UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_IsAlternate)(
const struct upb_MiniTableField* f) {
return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsAlternate) != 0;
}
UPB_API_INLINE bool upb_MiniTableField_IsExtension(
const struct upb_MiniTableField* f) {
return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsExtension) != 0;
}
UPB_API_INLINE bool upb_MiniTableField_IsPacked(
const struct upb_MiniTableField* f) {
return (f->UPB_ONLYBITS(mode) & kUpb_LabelFlags_IsPacked) != 0;
}
UPB_API_INLINE upb_FieldType
upb_MiniTableField_Type(const struct upb_MiniTableField* f) {
const upb_FieldType type = (upb_FieldType)f->UPB_PRIVATE(descriptortype);
if (UPB_PRIVATE(_upb_MiniTableField_IsAlternate)(f)) {
if (type == kUpb_FieldType_Int32) return kUpb_FieldType_Enum;
if (type == kUpb_FieldType_Bytes) return kUpb_FieldType_String;
UPB_ASSERT(false);
}
return type;
}
UPB_API_INLINE
upb_CType upb_MiniTableField_CType(const struct upb_MiniTableField* f) {
return upb_FieldType_CType(upb_MiniTableField_Type(f));
}
UPB_INLINE bool UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(
const struct upb_MiniTableField* f) {
return f->presence > 0;
}
UPB_INLINE char UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(
const struct upb_MiniTableField* f) {
UPB_ASSERT(UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f));
const size_t index = f->presence;
return 1 << (index % 8);
}
UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(
const struct upb_MiniTableField* f) {
UPB_ASSERT(UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(f));
const size_t index = f->presence;
return index / 8;
}
UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum(
const struct upb_MiniTableField* f) {
return f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Enum;
}
UPB_API_INLINE bool upb_MiniTableField_IsInOneof(
const struct upb_MiniTableField* f) {
return f->presence < 0;
}
UPB_API_INLINE bool upb_MiniTableField_IsSubMessage(
const struct upb_MiniTableField* f) {
return f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Message ||
f->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group;
}
UPB_API_INLINE bool upb_MiniTableField_HasPresence(
const struct upb_MiniTableField* f) {
if (upb_MiniTableField_IsExtension(f)) {
return upb_MiniTableField_IsScalar(f);
} else {
return f->presence != 0;
}
}
UPB_API_INLINE uint32_t
upb_MiniTableField_Number(const struct upb_MiniTableField* f) {
return f->UPB_ONLYBITS(number);
}
UPB_INLINE uint16_t
UPB_PRIVATE(_upb_MiniTableField_Offset)(const struct upb_MiniTableField* f) {
return f->UPB_ONLYBITS(offset);
}
UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_OneofOffset)(
const struct upb_MiniTableField* f) {
UPB_ASSERT(upb_MiniTableField_IsInOneof(f));
return ~(ptrdiff_t)f->presence;
}
UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(
const struct upb_MiniTableField* f) {
UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) ==
kUpb_FieldRep_NativePointer);
UPB_ASSUME(upb_MiniTableField_IsArray(f));
UPB_ASSUME(f->presence == 0);
}
UPB_INLINE void UPB_PRIVATE(_upb_MiniTableField_CheckIsMap)(
const struct upb_MiniTableField* f) {
UPB_ASSUME(UPB_PRIVATE(_upb_MiniTableField_GetRep)(f) ==
kUpb_FieldRep_NativePointer);
UPB_ASSUME(upb_MiniTableField_IsMap(f));
UPB_ASSUME(f->presence == 0);
}
UPB_INLINE size_t UPB_PRIVATE(_upb_MiniTableField_ElemSizeLg2)(
const struct upb_MiniTableField* f) {
const upb_FieldType field_type = upb_MiniTableField_Type(f);
return UPB_PRIVATE(_upb_FieldType_SizeLg2)(field_type);
}
// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/mini_table_field.ts)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_FIELD_H_ */
// Must be last.
typedef struct upb_MiniTableField upb_MiniTableField;
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE upb_CType upb_MiniTableField_CType(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_HasPresence(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsArray(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsClosedEnum(
const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsExtension(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsInOneof(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsMap(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsPacked(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsScalar(const upb_MiniTableField* f);
UPB_API_INLINE bool upb_MiniTableField_IsSubMessage(
const upb_MiniTableField* f);
UPB_API_INLINE uint32_t upb_MiniTableField_Number(const upb_MiniTableField* f);
UPB_API_INLINE upb_FieldType
upb_MiniTableField_Type(const upb_MiniTableField* f);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_FIELD_H_ */
#ifndef UPB_MINI_TABLE_MESSAGE_H_
#define UPB_MINI_TABLE_MESSAGE_H_
#ifndef UPB_MINI_TABLE_ENUM_H_
#define UPB_MINI_TABLE_ENUM_H_
#include <stdint.h>
#ifndef UPB_MINI_TABLE_INTERNAL_ENUM_H_
#define UPB_MINI_TABLE_INTERNAL_ENUM_H_
#include <stdint.h>
// Must be last.
struct upb_MiniTableEnum {
uint32_t UPB_PRIVATE(mask_limit); // Highest that can be tested with mask.
uint32_t UPB_PRIVATE(value_count); // Number of values after the bitfield.
uint32_t UPB_PRIVATE(data)[]; // Bitmask + enumerated values follow.
};
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE bool upb_MiniTableEnum_CheckValue(
const struct upb_MiniTableEnum* e, uint32_t val) {
if (UPB_LIKELY(val < 64)) {
const uint64_t mask =
e->UPB_PRIVATE(data)[0] | ((uint64_t)e->UPB_PRIVATE(data)[1] << 32);
const uint64_t bit = 1ULL << val;
return (mask & bit) != 0;
}
if (UPB_LIKELY(val < e->UPB_PRIVATE(mask_limit))) {
const uint32_t mask = e->UPB_PRIVATE(data)[val / 32];
const uint32_t bit = 1ULL << (val % 32);
return (mask & bit) != 0;
}
// OPT: binary search long lists?
const uint32_t* start =
&e->UPB_PRIVATE(data)[e->UPB_PRIVATE(mask_limit) / 32];
const uint32_t* limit = &e->UPB_PRIVATE(
data)[e->UPB_PRIVATE(mask_limit) / 32 + e->UPB_PRIVATE(value_count)];
for (const uint32_t* p = start; p < limit; p++) {
if (*p == val) return true;
}
return false;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_ENUM_H_ */
// Must be last
typedef struct upb_MiniTableEnum upb_MiniTableEnum;
#ifdef __cplusplus
extern "C" {
#endif
// Validates enum value against range defined by enum mini table.
UPB_API_INLINE bool upb_MiniTableEnum_CheckValue(const upb_MiniTableEnum* e,
uint32_t val);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_ENUM_H_ */
#ifndef UPB_MINI_TABLE_INTERNAL_MESSAGE_H_
#define UPB_MINI_TABLE_INTERNAL_MESSAGE_H_
#include <stddef.h>
#include <stdint.h>
#ifndef UPB_MINI_TABLE_INTERNAL_SUB_H_
#define UPB_MINI_TABLE_INTERNAL_SUB_H_
// Must be last.
typedef union {
const struct upb_MiniTable* const* UPB_PRIVATE(submsg);
const struct upb_MiniTableEnum* UPB_PRIVATE(subenum);
} upb_MiniTableSubInternal;
union upb_MiniTableSub {
const struct upb_MiniTable* UPB_PRIVATE(submsg);
const struct upb_MiniTableEnum* UPB_PRIVATE(subenum);
};
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE union upb_MiniTableSub upb_MiniTableSub_FromEnum(
const struct upb_MiniTableEnum* subenum) {
union upb_MiniTableSub out;
out.UPB_PRIVATE(subenum) = subenum;
return out;
}
UPB_API_INLINE union upb_MiniTableSub upb_MiniTableSub_FromMessage(
const struct upb_MiniTable* submsg) {
union upb_MiniTableSub out;
out.UPB_PRIVATE(submsg) = submsg;
return out;
}
UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTableSub_Enum(
const union upb_MiniTableSub sub) {
return sub.UPB_PRIVATE(subenum);
}
UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableSub_Message(
const union upb_MiniTableSub sub) {
return sub.UPB_PRIVATE(submsg);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_SUB_H_ */
// Must be last.
struct upb_Decoder;
struct upb_Message;
typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
struct upb_Message* msg, intptr_t table,
uint64_t hasbits, uint64_t data);
typedef struct {
uint64_t field_data;
_upb_FieldParser* field_parser;
} _upb_FastTable_Entry;
typedef enum {
kUpb_ExtMode_NonExtendable = 0, // Non-extendable message.
kUpb_ExtMode_Extendable = 1, // Normal extendable message.
kUpb_ExtMode_IsMessageSet = 2, // MessageSet message.
kUpb_ExtMode_IsMessageSet_ITEM =
3, // MessageSet item (temporary only, see decode.c)
// During table building we steal a bit to indicate that the message is a map
// entry. *Only* used during table building!
kUpb_ExtMode_IsMapEntry = 4,
} upb_ExtMode;
// upb_MiniTable represents the memory layout of a given upb_MessageDef.
// The members are public so generated code can initialize them,
// but users MUST NOT directly read or write any of its members.
// LINT.IfChange(minitable_struct_definition)
struct upb_MiniTable {
const upb_MiniTableSubInternal* UPB_PRIVATE(subs);
const struct upb_MiniTableField* UPB_ONLYBITS(fields);
// Must be aligned to sizeof(void*). Doesn't include internal members like
// unknown fields, extension dict, pointer to msglayout, etc.
uint16_t UPB_PRIVATE(size);
uint16_t UPB_ONLYBITS(field_count);
uint8_t UPB_PRIVATE(ext); // upb_ExtMode, uint8_t here so sizeof(ext) == 1
uint8_t UPB_PRIVATE(dense_below);
uint8_t UPB_PRIVATE(table_mask);
uint8_t UPB_PRIVATE(required_count); // Required fields have the low hasbits.
#ifdef UPB_TRACING_ENABLED
const char* UPB_PRIVATE(full_name);
#endif
#ifdef UPB_FASTTABLE_ENABLED
// To statically initialize the tables of variable length, we need a flexible
// array member, and we need to compile in gnu99 mode (constant initialization
// of flexible array members is a GNU extension, not in C99 unfortunately.
_upb_FastTable_Entry UPB_PRIVATE(fasttable)[];
#endif
};
// LINT.ThenChange(//depot/google3/third_party/upb/bits/typescript/mini_table.ts)
#ifdef __cplusplus
extern "C" {
#endif
UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(
_upb_MiniTable_StrongReference)(const struct upb_MiniTable* mt) {
#if defined(__GNUC__)
__asm__("" : : "r"(mt));
#else
const struct upb_MiniTable* volatile unused = mt;
(void)&unused; // Use address to avoid an extra load of "unused".
#endif
return mt;
}
UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(_upb_MiniTable_Empty)(void) {
extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty);
return &UPB_PRIVATE(_kUpb_MiniTable_Empty);
}
UPB_API_INLINE int upb_MiniTable_FieldCount(const struct upb_MiniTable* m) {
return m->UPB_ONLYBITS(field_count);
}
UPB_INLINE bool UPB_PRIVATE(_upb_MiniTable_IsEmpty)(
const struct upb_MiniTable* m) {
extern const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_Empty);
return m == &UPB_PRIVATE(_kUpb_MiniTable_Empty);
}
UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_GetFieldByIndex(
const struct upb_MiniTable* m, uint32_t i) {
return &m->UPB_ONLYBITS(fields)[i];
}
UPB_INLINE const struct upb_MiniTable* UPB_PRIVATE(
_upb_MiniTable_GetSubTableByIndex)(const struct upb_MiniTable* m,
uint32_t i) {
return *m->UPB_PRIVATE(subs)[i].UPB_PRIVATE(submsg);
}
UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_SubMessage(
const struct upb_MiniTable* m, const struct upb_MiniTableField* f) {
if (upb_MiniTableField_CType(f) != kUpb_CType_Message) {
return NULL;
}
return UPB_PRIVATE(_upb_MiniTable_GetSubTableByIndex)(
m, f->UPB_PRIVATE(submsg_index));
}
UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_GetSubMessageTable(
const struct upb_MiniTable* m, const struct upb_MiniTableField* f) {
UPB_ASSUME(upb_MiniTableField_CType(f) == kUpb_CType_Message);
const struct upb_MiniTable* ret = upb_MiniTable_SubMessage(m, f);
UPB_ASSUME(ret);
return UPB_PRIVATE(_upb_MiniTable_IsEmpty)(ret) ? NULL : ret;
}
UPB_API_INLINE bool upb_MiniTable_FieldIsLinked(
const struct upb_MiniTable* m, const struct upb_MiniTableField* f) {
return upb_MiniTable_GetSubMessageTable(m, f) != NULL;
}
UPB_API_INLINE const struct upb_MiniTable* upb_MiniTable_MapEntrySubMessage(
const struct upb_MiniTable* m, const struct upb_MiniTableField* f) {
UPB_ASSERT(upb_MiniTable_FieldIsLinked(m, f)); // Map entries must be linked.
UPB_ASSERT(upb_MiniTableField_IsMap(f)); // Function precondition.
return upb_MiniTable_SubMessage(m, f);
}
UPB_API_INLINE const struct upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable(
const struct upb_MiniTable* m, const struct upb_MiniTableField* f) {
UPB_ASSERT(upb_MiniTableField_CType(f) == kUpb_CType_Enum);
return m->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)].UPB_PRIVATE(
subenum);
}
UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_MapKey(
const struct upb_MiniTable* m) {
UPB_ASSERT(upb_MiniTable_FieldCount(m) == 2);
const struct upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, 0);
UPB_ASSERT(upb_MiniTableField_Number(f) == 1);
return f;
}
UPB_API_INLINE const struct upb_MiniTableField* upb_MiniTable_MapValue(
const struct upb_MiniTable* m) {
UPB_ASSERT(upb_MiniTable_FieldCount(m) == 2);
const struct upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, 1);
UPB_ASSERT(upb_MiniTableField_Number(f) == 2);
return f;
}
// Computes a bitmask in which the |m->required_count| lowest bits are set.
//
// Sample output:
// RequiredMask(1) => 0b1 (0x1)
// RequiredMask(5) => 0b11111 (0x1f)
UPB_INLINE uint64_t
UPB_PRIVATE(_upb_MiniTable_RequiredMask)(const struct upb_MiniTable* m) {
int n = m->UPB_PRIVATE(required_count);
UPB_ASSERT(0 < n && n <= 64);
return (1ULL << n) - 1;
}
#ifdef UPB_TRACING_ENABLED
UPB_INLINE const char* upb_MiniTable_FullName(
const struct upb_MiniTable* mini_table) {
return mini_table->UPB_PRIVATE(full_name);
}
// Initializes tracing proto name from language runtimes that construct
// mini tables dynamically at runtime. The runtime is responsible for passing
// controlling lifetime of name such as storing in same arena as mini_table.
UPB_INLINE void upb_MiniTable_SetFullName(struct upb_MiniTable* mini_table,
const char* full_name) {
mini_table->UPB_PRIVATE(full_name) = full_name;
}
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_MESSAGE_H_ */
// Must be last.
typedef struct upb_MiniTable upb_MiniTable;
#ifdef __cplusplus
extern "C" {
#endif
UPB_API const upb_MiniTableField* upb_MiniTable_FindFieldByNumber(
const upb_MiniTable* m, uint32_t number);
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_GetFieldByIndex(
const upb_MiniTable* m, uint32_t index);
UPB_API_INLINE int upb_MiniTable_FieldCount(const upb_MiniTable* m);
// DEPRECATED: use upb_MiniTable_SubMessage() instead
// Returns the MiniTable for a message field, NULL if the field is unlinked.
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable(
const upb_MiniTable* m, const upb_MiniTableField* f);
// Returns the MiniTable for a message field if it is a submessage, otherwise
// returns NULL.
//
// WARNING: if dynamic tree shaking is in use, the return value may be the
// "empty", zero-field placeholder message instead of the real message type.
// If the message is later linked, this function will begin returning the real
// message type.
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_SubMessage(
const upb_MiniTable* m, const upb_MiniTableField* f);
// Returns the MiniTable for a map field. The given field must refer to a map.
UPB_API_INLINE const upb_MiniTable* upb_MiniTable_MapEntrySubMessage(
const upb_MiniTable* m, const upb_MiniTableField* f);
// Returns the MiniTableEnum for a message field, NULL if the field is unlinked.
UPB_API_INLINE const upb_MiniTableEnum* upb_MiniTable_GetSubEnumTable(
const upb_MiniTable* m, const upb_MiniTableField* f);
// Returns the MiniTableField for the key of a map.
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapKey(
const upb_MiniTable* m);
// Returns the MiniTableField for the value of a map.
UPB_API_INLINE const upb_MiniTableField* upb_MiniTable_MapValue(
const upb_MiniTable* m);
// Returns true if this MiniTable field is linked to a MiniTable for the
// sub-message.
UPB_API_INLINE bool upb_MiniTable_FieldIsLinked(const upb_MiniTable* m,
const upb_MiniTableField* f);
// If this field is in a oneof, returns the first field in the oneof.
//
// Otherwise returns NULL.
//
// Usage:
// const upb_MiniTableField* field = upb_MiniTable_GetOneof(m, f);
// do {
// ..
// } while (upb_MiniTable_NextOneofField(m, &field);
//
const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m,
const upb_MiniTableField* f);
// Iterates to the next field in the oneof. If this is the last field in the
// oneof, returns false. The ordering of fields in the oneof is not
// guaranteed.
// REQUIRES: |f| is the field initialized by upb_MiniTable_GetOneof and updated
// by prior upb_MiniTable_NextOneofField calls.
bool upb_MiniTable_NextOneofField(const upb_MiniTable* m,
const upb_MiniTableField** f);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_MESSAGE_H_ */
// Must be last.
typedef struct upb_Array upb_Array;
#ifdef __cplusplus
extern "C" {
#endif
// Creates a new array on the given arena that holds elements of this type.
UPB_API upb_Array* upb_Array_New(upb_Arena* a, upb_CType type);
// Returns the number of elements in the array.
UPB_API_INLINE size_t upb_Array_Size(const upb_Array* arr);
// Returns the given element, which must be within the array's current size.
UPB_API upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i);
// Returns a mutating pointer to the given element, which must be within the
// array's current size.
UPB_API upb_MutableMessageValue upb_Array_GetMutable(upb_Array* arr, size_t i);
// Sets the given element, which must be within the array's current size.
UPB_API void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val);
// Appends an element to the array. Returns false on allocation failure.
UPB_API bool upb_Array_Append(upb_Array* array, upb_MessageValue val,
upb_Arena* arena);
// Moves elements within the array using memmove().
// Like memmove(), the source and destination elements may be overlapping.
UPB_API void upb_Array_Move(upb_Array* array, size_t dst_idx, size_t src_idx,
size_t count);
// Inserts one or more empty elements into the array.
// Existing elements are shifted right.
// The new elements have undefined state and must be set with `upb_Array_Set()`.
// REQUIRES: `i <= upb_Array_Size(arr)`
UPB_API bool upb_Array_Insert(upb_Array* array, size_t i, size_t count,
upb_Arena* arena);
// Deletes one or more elements from the array.
// Existing elements are shifted left.
// REQUIRES: `i + count <= upb_Array_Size(arr)`
UPB_API void upb_Array_Delete(upb_Array* array, size_t i, size_t count);
// Reserves |size| elements of storage for the array.
UPB_API_INLINE bool upb_Array_Reserve(struct upb_Array* array, size_t size,
upb_Arena* arena);
// Changes the size of a vector. New elements are initialized to NULL/0.
// Returns false on allocation failure.
UPB_API bool upb_Array_Resize(upb_Array* array, size_t size, upb_Arena* arena);
// Returns pointer to array data.
UPB_API_INLINE const void* upb_Array_DataPtr(const upb_Array* arr);
// Returns mutable pointer to array data.
UPB_API_INLINE void* upb_Array_MutableDataPtr(upb_Array* arr);
// Mark an array and all of its descendents as frozen/immutable.
// If the array elements are messages then |m| must point to the minitable for
// those messages. Otherwise |m| must be NULL.
UPB_API void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m);
// Returns whether an array has been frozen.
UPB_API_INLINE bool upb_Array_IsFrozen(const upb_Array* arr);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_ARRAY_H_ */
#ifndef UPB_MESSAGE_INTERNAL_ACCESSORS_H_
#define UPB_MESSAGE_INTERNAL_ACCESSORS_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifndef UPB_BASE_INTERNAL_ENDIAN_H_
#define UPB_BASE_INTERNAL_ENDIAN_H_
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
UPB_INLINE bool upb_IsLittleEndian(void) {
const int x = 1;
return *(char*)&x == 1;
}
UPB_INLINE uint32_t upb_BigEndian32(uint32_t val) {
if (upb_IsLittleEndian()) return val;
return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
}
UPB_INLINE uint64_t upb_BigEndian64(uint64_t val) {
if (upb_IsLittleEndian()) return val;
const uint64_t hi = ((uint64_t)upb_BigEndian32((uint32_t)val)) << 32;
const uint64_t lo = upb_BigEndian32((uint32_t)(val >> 32));
return hi | lo;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_BASE_INTERNAL_ENDIAN_H_ */
#ifndef UPB_MESSAGE_INTERNAL_EXTENSION_H_
#define UPB_MESSAGE_INTERNAL_EXTENSION_H_
#include <stddef.h>
#ifndef UPB_MINI_TABLE_EXTENSION_H_
#define UPB_MINI_TABLE_EXTENSION_H_
#include <stdint.h>
#ifndef UPB_MINI_TABLE_INTERNAL_EXTENSION_H_
#define UPB_MINI_TABLE_INTERNAL_EXTENSION_H_
#include <stddef.h>
#include <stdint.h>
// Must be last.
struct upb_MiniTableExtension {
// Do not move this field. We need to be able to alias pointers.
struct upb_MiniTableField UPB_PRIVATE(field);
const struct upb_MiniTable* UPB_PRIVATE(extendee);
union upb_MiniTableSub UPB_PRIVATE(sub); // NULL unless submsg or proto2 enum
};
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE upb_CType
upb_MiniTableExtension_CType(const struct upb_MiniTableExtension* e) {
return upb_MiniTableField_CType(&e->UPB_PRIVATE(field));
}
UPB_API_INLINE uint32_t
upb_MiniTableExtension_Number(const struct upb_MiniTableExtension* e) {
return e->UPB_PRIVATE(field).UPB_ONLYBITS(number);
}
UPB_API_INLINE const struct upb_MiniTable* upb_MiniTableExtension_GetSubMessage(
const struct upb_MiniTableExtension* e) {
if (upb_MiniTableExtension_CType(e) != kUpb_CType_Message) {
return NULL;
}
return upb_MiniTableSub_Message(e->UPB_PRIVATE(sub));
}
UPB_API_INLINE void upb_MiniTableExtension_SetSubMessage(
struct upb_MiniTableExtension* e, const struct upb_MiniTable* m) {
e->UPB_PRIVATE(sub).UPB_PRIVATE(submsg) = m;
}
UPB_INLINE upb_FieldRep UPB_PRIVATE(_upb_MiniTableExtension_GetRep)(
const struct upb_MiniTableExtension* e) {
return UPB_PRIVATE(_upb_MiniTableField_GetRep)(&e->UPB_PRIVATE(field));
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_EXTENSION_H_ */
// Must be last.
typedef struct upb_MiniTableExtension upb_MiniTableExtension;
#ifdef __cplusplus
extern "C" {
#endif
UPB_API_INLINE upb_CType
upb_MiniTableExtension_CType(const upb_MiniTableExtension* e);
UPB_API_INLINE uint32_t
upb_MiniTableExtension_Number(const upb_MiniTableExtension* e);
UPB_API_INLINE const upb_MiniTable* upb_MiniTableExtension_GetSubMessage(
const upb_MiniTableExtension* e);
UPB_API_INLINE void upb_MiniTableExtension_SetSubMessage(
upb_MiniTableExtension* e, const upb_MiniTable* m);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_EXTENSION_H_ */
// Must be last.
// The internal representation of an extension is self-describing: it contains
// enough information that we can serialize it to binary format without needing
// to look it up in a upb_ExtensionRegistry.
//
// This representation allocates 16 bytes to data on 64-bit platforms.
// This is rather wasteful for scalars (in the extreme case of bool,
// it wastes 15 bytes). We accept this because we expect messages to be
// the most common extension type.
typedef struct {
const upb_MiniTableExtension* ext;
upb_MessageValue data;
} upb_Extension;
#ifdef __cplusplus
extern "C" {
#endif
// Adds the given extension data to the given message.
// |ext| is copied into the message instance.
// This logically replaces any previously-added extension with this number.
upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(
struct upb_Message* msg, const upb_MiniTableExtension* ext,
upb_Arena* arena);
// Returns an array of extensions for this message.
// Note: the array is ordered in reverse relative to the order of creation.
const upb_Extension* UPB_PRIVATE(_upb_Message_Getexts)(
const struct upb_Message* msg, size_t* count);
// Returns an extension for a message with a given mini table,
// or NULL if no extension exists with this mini table.
const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)(
const struct upb_Message* msg, const upb_MiniTableExtension* ext);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_INTERNAL_EXTENSION_H_ */
#ifndef UPB_MESSAGE_INTERNAL_MAP_H_
#define UPB_MESSAGE_INTERNAL_MAP_H_
#include <stddef.h>
#include <string.h>
#ifndef UPB_HASH_STR_TABLE_H_
#define UPB_HASH_STR_TABLE_H_
/*
* upb_table
*
* This header is INTERNAL-ONLY! Its interfaces are not public or stable!
* This file defines very fast int->upb_value (inttable) and string->upb_value
* (strtable) hash tables.
*
* The table uses chained scatter with Brent's variation (inspired by the Lua
* implementation of hash tables). The hash function for strings is Austin
* Appleby's "MurmurHash."
*
* The inttable uses uintptr_t as its key, which guarantees it can be used to
* store pointers or integers of at least 32 bits (upb isn't really useful on
* systems where sizeof(void*) < 4).
*
* The table must be homogeneous (all values of the same type). In debug
* mode, we check this on insert and lookup.
*/
#ifndef UPB_HASH_COMMON_H_
#define UPB_HASH_COMMON_H_
#include <string.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
/* upb_value ******************************************************************/
typedef struct {
uint64_t val;
} upb_value;
UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; }
/* For each value ctype, 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 FUNCS(name, membername, type_t, converter) \
UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \
val->val = (converter)cval; \
} \
UPB_INLINE upb_value upb_value_##name(type_t val) { \
upb_value ret; \
upb_value_set##name(&ret, val); \
return ret; \
} \
UPB_INLINE type_t upb_value_get##name(upb_value val) { \
return (type_t)(converter)val.val; \
}
FUNCS(int32, int32, int32_t, int32_t)
FUNCS(int64, int64, int64_t, int64_t)
FUNCS(uint32, uint32, uint32_t, uint32_t)
FUNCS(uint64, uint64, uint64_t, uint64_t)
FUNCS(bool, _bool, bool, bool)
FUNCS(cstr, cstr, char*, uintptr_t)
FUNCS(uintptr, uptr, uintptr_t, uintptr_t)
FUNCS(ptr, ptr, void*, uintptr_t)
FUNCS(constptr, constptr, const void*, uintptr_t)
#undef FUNCS
UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) {
memcpy(&val->val, &cval, sizeof(cval));
}
UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) {
memcpy(&val->val, &cval, sizeof(cval));
}
UPB_INLINE upb_value upb_value_float(float cval) {
upb_value ret;
upb_value_setfloat(&ret, cval);
return ret;
}
UPB_INLINE upb_value upb_value_double(double cval) {
upb_value ret;
upb_value_setdouble(&ret, cval);
return ret;
}
/* upb_tabkey *****************************************************************/
/* Either:
* 1. an actual integer key, or
* 2. a pointer to a string prefixed by its uint32_t length, owned by us.
*
* ...depending on whether this is a string table or an int table. We would
* make this a union of those two types, but C89 doesn't support statically
* initializing a non-first union member. */
typedef uintptr_t upb_tabkey;
UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) {
char* mem = (char*)key;
if (len) memcpy(len, mem, sizeof(*len));
return mem + sizeof(*len);
}
UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) {
upb_StringView ret;
uint32_t len;
ret.data = upb_tabstr(key, &len);
ret.size = len;
return ret;
}
/* upb_tabval *****************************************************************/
typedef struct upb_tabval {
uint64_t val;
} upb_tabval;
#define UPB_TABVALUE_EMPTY_INIT \
{ -1 }
/* upb_table ******************************************************************/
typedef struct _upb_tabent {
upb_tabkey key;
upb_tabval val;
/* Internal chaining. This is const so we can create static initializers for
* tables. We cast away const sometimes, but *only* when the containing
* upb_table is known to be non-const. This requires a bit of care, but
* the subtlety is confined to table.c. */
const struct _upb_tabent* next;
} upb_tabent;
typedef struct {
size_t count; /* Number of entries in the hash part. */
uint32_t mask; /* Mask to turn hash value -> bucket. */
uint32_t max_count; /* Max count before we hit our load limit. */
uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */
upb_tabent* entries;
} upb_table;
UPB_INLINE size_t upb_table_size(const upb_table* t) {
return t->size_lg2 ? 1 << t->size_lg2 : 0;
}
// Internal-only functions, in .h file only out of necessity.
UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; }
uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_HASH_COMMON_H_ */
// Must be last.
typedef struct {
upb_table t;
} upb_strtable;
#ifdef __cplusplus
extern "C" {
#endif
// Initialize a table. If memory allocation failed, false is returned and
// the table is uninitialized.
bool upb_strtable_init(upb_strtable* table, size_t expected_size, upb_Arena* a);
// Returns the number of values in the table.
UPB_INLINE size_t upb_strtable_count(const upb_strtable* t) {
return t->t.count;
}
void upb_strtable_clear(upb_strtable* t);
// Inserts the given key into the hashtable with the given value.
// The key must not already exist in the hash table. The key is not required
// to be NULL-terminated, and the table will make an internal copy of the key.
//
// If a table resize was required but memory allocation failed, false is
// returned and the table is unchanged. */
bool upb_strtable_insert(upb_strtable* t, const char* key, size_t len,
upb_value val, upb_Arena* a);
// Looks up key in this table, returning "true" if the key was found.
// If v is non-NULL, copies the value for this key into *v.
bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
upb_value* v);
// For NULL-terminated strings.
UPB_INLINE bool upb_strtable_lookup(const upb_strtable* t, const char* key,
upb_value* v) {
return upb_strtable_lookup2(t, key, strlen(key), v);
}
// Removes an item from the table. Returns true if the remove was successful,
// and stores the removed item in *val if non-NULL.
bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
upb_value* val);
UPB_INLINE bool upb_strtable_remove(upb_strtable* t, const char* key,
upb_value* v) {
return upb_strtable_remove2(t, key, strlen(key), v);
}
// Exposed for testing only.
bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a);
/* Iteration over strtable:
*
* intptr_t iter = UPB_STRTABLE_BEGIN;
* upb_StringView key;
* upb_value val;
* while (upb_strtable_next2(t, &key, &val, &iter)) {
* // ...
* }
*/
#define UPB_STRTABLE_BEGIN -1
bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key,
upb_value* val, intptr_t* iter);
void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter);
void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v);
/* DEPRECATED iterators, slated for removal.
*
* Iterators for string tables. We are subject to some kind of unusual
* design constraints:
*
* For high-level languages:
* - we must be able to guarantee that we don't crash or corrupt memory even if
* the program accesses an invalidated iterator.
*
* For C++11 range-based for:
* - iterators must be copyable
* - iterators must be comparable
* - it must be possible to construct an "end" value.
*
* Iteration order is undefined.
*
* Modifying the table invalidates iterators. upb_{str,int}table_done() is
* guaranteed to work even on an invalidated iterator, as long as the table it
* is iterating over has not been freed. Calling next() or accessing data from
* an invalidated iterator yields unspecified elements from the table, but it is
* guaranteed not to crash and to return real table elements (except when done()
* is true). */
/* upb_strtable_iter **********************************************************/
/* upb_strtable_iter i;
* upb_strtable_begin(&i, t);
* for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
* const char *key = upb_strtable_iter_key(&i);
* const upb_value val = upb_strtable_iter_value(&i);
* // ...
* }
*/
typedef struct {
const upb_strtable* t;
size_t index;
} upb_strtable_iter;
UPB_INLINE const upb_tabent* str_tabent(const upb_strtable_iter* i) {
return &i->t->t.entries[i->index];
}
void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t);
void upb_strtable_next(upb_strtable_iter* i);
bool upb_strtable_done(const upb_strtable_iter* i);
upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i);
upb_value upb_strtable_iter_value(const upb_strtable_iter* i);
void upb_strtable_iter_setdone(upb_strtable_iter* i);
bool upb_strtable_iter_isequal(const upb_strtable_iter* i1,
const upb_strtable_iter* i2);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_HASH_STR_TABLE_H_ */
// Must be last.
typedef enum {
kUpb_MapInsertStatus_Inserted = 0,
kUpb_MapInsertStatus_Replaced = 1,
kUpb_MapInsertStatus_OutOfMemory = 2,
} upb_MapInsertStatus;
// EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE /////////////////////////
struct upb_Map {
// Size of key and val, based on the map type.
// Strings are represented as '0' because they must be handled specially.
char key_size;
char val_size;
bool UPB_PRIVATE(is_frozen);
upb_strtable table;
};
#ifdef __cplusplus
extern "C" {
#endif
UPB_INLINE void UPB_PRIVATE(_upb_Map_ShallowFreeze)(struct upb_Map* map) {
map->UPB_PRIVATE(is_frozen) = true;
}
UPB_API_INLINE bool upb_Map_IsFrozen(const struct upb_Map* map) {
return map->UPB_PRIVATE(is_frozen);
}
// Converting between internal table representation and user values.
//
// _upb_map_tokey() and _upb_map_fromkey() are inverses.
// _upb_map_tovalue() and _upb_map_fromvalue() are inverses.
//
// These functions account for the fact that strings are treated differently
// from other types when stored in a map.
UPB_INLINE upb_StringView _upb_map_tokey(const void* key, size_t size) {
if (size == UPB_MAPTYPE_STRING) {
return *(upb_StringView*)key;
} else {
return upb_StringView_FromDataAndSize((const char*)key, size);
}
}
UPB_INLINE void _upb_map_fromkey(upb_StringView key, void* out, size_t size) {
if (size == UPB_MAPTYPE_STRING) {
memcpy(out, &key, sizeof(key));
} else {
memcpy(out, key.data, size);
}
}
UPB_INLINE bool _upb_map_tovalue(const void* val, size_t size,
upb_value* msgval, upb_Arena* a) {
if (size == UPB_MAPTYPE_STRING) {
upb_StringView* strp = (upb_StringView*)upb_Arena_Malloc(a, sizeof(*strp));
if (!strp) return false;
*strp = *(upb_StringView*)val;
*msgval = upb_value_ptr(strp);
} else {
memcpy(msgval, val, size);
}
return true;
}
UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) {
if (size == UPB_MAPTYPE_STRING) {
const upb_StringView* strp = (const upb_StringView*)upb_value_getptr(val);
memcpy(out, strp, sizeof(upb_StringView));
} else {
memcpy(out, &val, size);
}
}
UPB_INLINE void* _upb_map_next(const struct upb_Map* map, size_t* iter) {
upb_strtable_iter it;
it.t = &map->table;
it.index = *iter;
upb_strtable_next(&it);
*iter = it.index;
if (upb_strtable_done(&it)) return NULL;
return (void*)str_tabent(&it);
}
UPB_INLINE void _upb_Map_Clear(struct upb_Map* map) {
UPB_ASSERT(!upb_Map_IsFrozen(map));
upb_strtable_clear(&map->table);
}
UPB_INLINE bool _upb_Map_Delete(struct upb_Map* map, const void* key,
size_t key_size, upb_value* val) {
UPB_ASSERT(!upb_Map_IsFrozen(map));
upb_StringView k = _upb_map_tokey(key, key_size);
return upb_strtable_remove2(&map->table, k.data, k.size, val);
}
UPB_INLINE bool _upb_Map_Get(const struct upb_Map* map, const void* key,
size_t key_size, void* val, size_t val_size) {
upb_value tabval;
upb_StringView k = _upb_map_tokey(key, key_size);
bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval);
if (ret && val) {
_upb_map_fromvalue(tabval, val, val_size);
}
return ret;
}
UPB_INLINE upb_MapInsertStatus _upb_Map_Insert(struct upb_Map* map,
const void* key, size_t key_size,
void* val, size_t val_size,
upb_Arena* a) {
UPB_ASSERT(!upb_Map_IsFrozen(map));
upb_StringView strkey = _upb_map_tokey(key, key_size);
upb_value tabval = {0};
if (!_upb_map_tovalue(val, val_size, &tabval, a)) {
return kUpb_MapInsertStatus_OutOfMemory;
}
// TODO: add overwrite operation to minimize number of lookups.
bool removed =
upb_strtable_remove2(&map->table, strkey.data, strkey.size, NULL);
if (!upb_strtable_insert(&map->table, strkey.data, strkey.size, tabval, a)) {
return kUpb_MapInsertStatus_OutOfMemory;
}
return removed ? kUpb_MapInsertStatus_Replaced
: kUpb_MapInsertStatus_Inserted;
}
UPB_INLINE size_t _upb_Map_Size(const struct upb_Map* map) {
return map->table.t.count;
}
// Strings/bytes are special-cased in maps.
extern char _upb_Map_CTypeSizeTable[12];
UPB_INLINE size_t _upb_Map_CTypeSize(upb_CType ctype) {
return _upb_Map_CTypeSizeTable[ctype];
}
// Creates a new map on the given arena with this key/value type.
struct upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_INTERNAL_MAP_H_ */
/*
** Our memory representation for parsing tables and messages themselves.
** Functions in this file are used by generated code and possibly reflection.
**
** The definitions in this file are internal to upb.
**/
#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_
#define UPB_MESSAGE_INTERNAL_MESSAGE_H_
#include <stdlib.h>
#include <string.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
extern const float kUpb_FltInfinity;
extern const double kUpb_Infinity;
extern const double kUpb_NaN;
// Internal members of a upb_Message that track unknown fields and/or
// extensions. We can change this without breaking binary compatibility.
typedef struct upb_Message_Internal {
// Total size of this structure, including the data that follows.
// Must be aligned to 8, which is alignof(upb_Extension)
uint32_t size;
/* Offsets relative to the beginning of this structure.
*
* Unknown data grows forward from the beginning to unknown_end.
* Extension data grows backward from size to ext_begin.
* When the two meet, we're out of data and have to realloc.
*
* If we imagine that the final member of this struct is:
* char data[size - overhead]; // overhead = sizeof(upb_Message_Internal)
*
* Then we have:
* unknown data: data[0 .. (unknown_end - overhead)]
* extensions data: data[(ext_begin - overhead) .. (size - overhead)] */
uint32_t unknown_end;
uint32_t ext_begin;
// Data follows, as if there were an array:
// char data[size - sizeof(upb_Message_Internal)];
} upb_Message_Internal;
#ifdef UPB_TRACING_ENABLED
UPB_API void upb_Message_LogNewMessage(const upb_MiniTable* m,
const upb_Arena* arena);
UPB_API void upb_Message_SetNewMessageTraceHandler(
void (*handler)(const upb_MiniTable*, const upb_Arena*));
#endif // UPB_TRACING_ENABLED
// Inline version upb_Message_New(), for internal use.
UPB_INLINE struct upb_Message* _upb_Message_New(const upb_MiniTable* m,
upb_Arena* a) {
#ifdef UPB_TRACING_ENABLED
upb_Message_LogNewMessage(m, a);
#endif // UPB_TRACING_ENABLED
const int size = m->UPB_PRIVATE(size);
struct upb_Message* msg = (struct upb_Message*)upb_Arena_Malloc(a, size);
if (UPB_UNLIKELY(!msg)) return NULL;
memset(msg, 0, size);
return msg;
}
// Discards the unknown fields for this message only.
void _upb_Message_DiscardUnknown_shallow(struct upb_Message* msg);
// Adds unknown data (serialized protobuf data) to the given message.
// The data is copied into the message instance.
bool UPB_PRIVATE(_upb_Message_AddUnknown)(struct upb_Message* msg,
const char* data, size_t len,
upb_Arena* arena);
bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need,
upb_Arena* arena);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MESSAGE_INTERNAL_MESSAGE_H_ */
#ifndef UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_
#define UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_
#include <stdint.h>
// Must be last.
#ifdef __cplusplus
extern "C" {
#endif
// Internal-only because empty messages cannot be created by the user.
UPB_INLINE uintptr_t
UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(struct upb_Message* ptr, bool empty) {
UPB_ASSERT(((uintptr_t)ptr & 1) == 0);
return (uintptr_t)ptr | (empty ? 1 : 0);
}
UPB_API_INLINE bool upb_TaggedMessagePtr_IsEmpty(uintptr_t ptr) {
return ptr & 1;
}
UPB_INLINE struct upb_Message* UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(
uintptr_t ptr) {
return (struct upb_Message*)(ptr & ~(uintptr_t)1);
}
UPB_API_INLINE struct upb_Message* upb_TaggedMessagePtr_GetNonEmptyMessage(
uintptr_t ptr) {
UPB_ASSERT(!upb_TaggedMessagePtr_IsEmpty(ptr));
return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(ptr);
}
UPB_INLINE struct upb_Message* UPB_PRIVATE(
_upb_TaggedMessagePtr_GetEmptyMessage)(uintptr_t ptr) {
UPB_ASSERT(upb_TaggedMessagePtr_IsEmpty(ptr));
return UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(ptr);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_MINI_TABLE_INTERNAL_TAGGED_PTR_H_ */
#ifndef UPB_MESSAGE_INTERNAL_TYPES_H_
#define UPB_MESSAGE_INTERNAL_TYPES_H_
#include <stdint.h>
// Must be last.
#define UPB_OPAQUE(x) x##_opaque
struct upb_Message {
union {
uintptr_t UPB_OPAQUE(internal); // tagged pointer, low bit == frozen
double d; // Forces same size for 32-bit/64-bit builds
};
};
#ifdef __cplusplus
extern "C" {
#endif
UPB_INLINE void UPB_PRIVATE(_upb_Message_ShallowFreeze)(
struct upb_Message* msg) {
msg->UPB_OPAQUE(internal) |= 1ULL;
}
UPB_API_INLINE bool upb_Message_IsFrozen(const struct upb_Message* msg) {
return (msg->UPB_OPAQUE(internal) & 1ULL) != 0;
}
UPB_INLINE struct upb_Message_Internal* UPB_PRIVATE(_upb_Message_GetInternal)(
const struct upb_Message* msg) {
const uintptr_t tmp = msg->UPB_OPAQUE(internal) & ~1ULL;
return (struct upb_Message_Internal*)tmp;
}
UPB_INLINE void UPB_PRIVATE(_upb_Message_SetInternal)(
struct upb_Message* msg, struct upb_Message_Internal* internal) {
UPB_ASSERT(!upb_Message_IsFrozen(msg));
msg->UPB_OPAQUE(internal) = (uintptr_t)internal;
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#undef UPB_OPAQUE
#endif /* UPB_MESSAGE_INTERNAL_TYPES_H_ */
// Must be last.
#if defined(__GNUC__) && !defined(__clang__)
// GCC raises incorrect warnings in these functions. It thinks that we are
// overrunning buffers, but we carefully write the functions in this file to
// guarantee that this is impossible. GCC gets this wrong due it its failure
// to perform constant propagation as we expect:
// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108217
// - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108226
//
// Unfortunately this also indicates that GCC is not optimizing away the
// switch() in cases where it should be, compromising the performance.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#if __GNUC__ >= 11
#pragma GCC diagnostic ignored "-Wstringop-overread"
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
// LINT.IfChange(presence_logic)
// Hasbit access ///////////////////////////////////////////////////////////////
UPB_INLINE bool UPB_PRIVATE(_upb_Message_GetHasbit)(
const struct upb_Message* msg, const upb_MiniTableField* f) {
const size_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f);
const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f);
return (*UPB_PTR_AT(msg, offset, const char) & mask) != 0;
}
UPB_INLINE void UPB_PRIVATE(_upb_Message_SetHasbit)(
const struct upb_Message* msg, const upb_MiniTableField* f) {
const size_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f);
const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f);
(*UPB_PTR_AT(msg, offset, char)) |= mask;
}
UPB_INLINE void UPB_PRIVATE(_upb_Message_ClearHasbit)(
const struct upb_Message* msg, const upb_MiniTableField* f) {
const size_t offset = UPB_PRIVATE(_upb_MiniTableField_HasbitOffset)(f);
const char mask = UPB_PRIVATE(_upb_MiniTableField_HasbitMask)(f);