From 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 15 Feb 2013 16:27:18 -0800 Subject: Sync with 8 months of Google-internal development. Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink). --- upb/symtab.h | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 upb/symtab.h (limited to 'upb/symtab.h') diff --git a/upb/symtab.h b/upb/symtab.h new file mode 100644 index 0000000..883324a --- /dev/null +++ b/upb/symtab.h @@ -0,0 +1,200 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009-2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * A symtab (symbol table) stores a name->def map of upb_defs. Clients could + * always create such tables themselves, but upb_symtab has logic for resolving + * symbolic references, and in particular, for keeping a whole set of consistent + * defs when replacing some subset of those defs. This logic is nontrivial. + * + * This is a mixed C/C++ interface that offers a full API to both languages. + * See the top-level README for more information. + */ + +#ifndef UPB_SYMTAB_H_ +#define UPB_SYMTAB_H_ + +#ifdef __cplusplus +#include + +namespace upb { class SymbolTable; } +typedef upb::SymbolTable upb_symtab; +#else +struct upb_symtab; +typedef struct upb_symtab upb_symtab; +#endif + +#include "upb/def.h" + +#ifdef __cplusplus + +class upb::SymbolTable { + public: + // Returns a new symbol table with a single ref owned by "owner." + // Returns NULL if memory allocation failed. + static SymbolTable* New(const void* owner); + + // Though not declared as such in C++, upb::RefCounted is the base of + // SymbolTable and we can upcast to it. + RefCounted* Upcast(); + const RefCounted* Upcast() const; + + // Functionality from upb::RefCounted. + bool IsFrozen() const; + void Ref(const void* owner) const; + void Unref(const void* owner) const; + void DonateRef(const void *from, const void *to) const; + void CheckRef(const void *owner) const; + + // Resolves the given symbol using the rules described in descriptor.proto, + // namely: + // + // If the name starts with a '.', it is fully-qualified. Otherwise, + // C++-like scoping rules are used to find the type (i.e. first the nested + // types within this message are searched, then within the parent, on up + // to the root namespace). + // + // If a def is found, the caller owns one ref on the returned def, owned by + // owner. Otherwise returns NULL. + const Def* Resolve(const char* base, const char* sym, + const void* owner) const; + + // Finds an entry in the symbol table with this exact name. If a def is + // found, the caller owns one ref on the returned def, owned by owner. + // Otherwise returns NULL. + const Def* Lookup(const char *sym, const void *owner) const; + const MessageDef* LookupMessage(const char *sym, const void *owner) const; + + // Gets an array of pointers to all currently active defs in this symtab. + // The caller owns the returned array (which is of length *n) as well as a + // ref to each symbol inside (owned by owner). If type is UPB_DEF_ANY then + // defs of all types are returned, otherwise only defs of the required type + // are returned. + const Def** GetDefs(upb_deftype_t type, const void *owner, int *n) const; + + // Adds the given mutable defs to the symtab, resolving all symbols + // (including enum default values) and finalizing the defs. Only one def per + // name may be in the list, but defs can replace existing defs in the symtab. + // All defs must have a name -- anonymous defs are not allowed. Anonymous + // defs can still be frozen by calling upb_def_freeze() directly. + // + // Any existing defs that can reach defs that are being replaced will + // themselves be replaced also, so that the resulting set of defs is fully + // consistent. + // + // This logic implemented in this method is a convenience; ultimately it + // calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and + // upb_freeze(), any of which the client could call themself. However, since + // the logic for doing so is nontrivial, we provide it here. + // + // The entire operation either succeeds or fails. If the operation fails, + // the symtab is unchanged, false is returned, and status indicates the + // error. The caller passes a ref on all defs to the symtab (even if the + // operation fails). + // + // TODO(haberman): currently failure will leave the symtab unchanged, but may + // leave the defs themselves partially resolved. Does this matter? If so we + // could do a prepass that ensures that all symbols are resolvable and bail + // if not, so we don't mutate anything until we know the operation will + // succeed. + // + // TODO(haberman): since the defs must be mutable, refining a frozen def + // requires making mutable copies of the entire tree. This is wasteful if + // only a few messages are changing. We may want to add a way of adding a + // tree of frozen defs to the symtab (perhaps an alternate constructor where + // you pass the root of the tree?) + bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status); + + bool Add(const std::vector& defs, void *owner, Status* status) { + return Add((Def*const*)&defs[0], defs.size(), owner, status); + } + + private: + UPB_DISALLOW_POD_OPS(SymbolTable); + +#else +struct upb_symtab { +#endif + upb_refcounted base; + upb_strtable symtab; +}; + +// Native C API. +#ifdef __cplusplus +extern "C" { +#endif +// From upb_refcounted. +bool upb_symtab_isfrozen(const upb_symtab *s); +void upb_symtab_ref(const upb_symtab *s, const void *owner); +void upb_symtab_unref(const upb_symtab *s, const void *owner); +void upb_symtab_donateref( + const upb_symtab *s, const void *from, const void *to); +void upb_symtab_checkref(const upb_symtab *s, const void *owner); + +upb_symtab *upb_symtab_new(const void *owner); +const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, + const char *sym, const void *owner); +const upb_def *upb_symtab_lookup( + const upb_symtab *s, const char *sym, const void *owner); +const upb_msgdef *upb_symtab_lookupmsg( + const upb_symtab *s, const char *sym, const void *owner); +const upb_def **upb_symtab_getdefs( + const upb_symtab *s, upb_deftype_t type, const void *owner, int *n); +bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, + upb_status *status); + +#ifdef __cplusplus +} /* extern "C" */ + +// C++ inline wrappers. +namespace upb { +inline SymbolTable* SymbolTable::New(const void* owner) { + return upb_symtab_new(owner); +} + +inline RefCounted* SymbolTable::Upcast() { return upb_upcast(this); } +inline const RefCounted* SymbolTable::Upcast() const { + return upb_upcast(this); +} +inline bool SymbolTable::IsFrozen() const { + return upb_symtab_isfrozen(this); +} +inline void SymbolTable::Ref(const void *owner) const { + upb_symtab_ref(this, owner); +} +inline void SymbolTable::Unref(const void *owner) const { + upb_symtab_unref(this, owner); +} +inline void SymbolTable::DonateRef(const void *from, const void *to) const { + upb_symtab_donateref(this, from, to); +} +inline void SymbolTable::CheckRef(const void *owner) const { + upb_symtab_checkref(this, owner); +} + +inline const Def* SymbolTable::Resolve( + const char* base, const char* sym, const void* owner) const { + return upb_symtab_resolve(this, base, sym, owner); +} +inline const Def* SymbolTable::Lookup( + const char *sym, const void *owner) const { + return upb_symtab_lookup(this, sym, owner); +} +inline const MessageDef* SymbolTable::LookupMessage( + const char *sym, const void *owner) const { + return upb_symtab_lookupmsg(this, sym, owner); +} +inline const Def** SymbolTable::GetDefs( + upb_deftype_t type, const void *owner, int *n) const { + return upb_symtab_getdefs(this, type, owner, n); +} +inline bool SymbolTable::Add( + Def*const* defs, int n, void* ref_donor, upb_status* status) { + return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status); +} +} // namespace upb +#endif + +#endif /* UPB_SYMTAB_H_ */ -- cgit v1.2.3