|
|
|
/*
|
|
|
|
* upb - a minimalist implementation of protocol buffers.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2009-2012 Google Inc. See LICENSE for details.
|
|
|
|
* Author: Josh Haberman <jhaberman@gmail.com>
|
|
|
|
*
|
|
|
|
* A symtab (symbol table) stores a name->def map of upb_defs. Clients could
|
|
|
|
* always create such tables themselves, but upb_symtab has logic for resolving
|
|
|
|
* symbolic references, and in particular, for keeping a whole set of consistent
|
|
|
|
* defs when replacing some subset of those defs. This logic is nontrivial.
|
|
|
|
*
|
|
|
|
* This is a mixed C/C++ interface that offers a full API to both languages.
|
|
|
|
* See the top-level README for more information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef UPB_SYMTAB_H_
|
|
|
|
#define UPB_SYMTAB_H_
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace upb { class SymbolTable; }
|
|
|
|
typedef upb::SymbolTable upb_symtab;
|
|
|
|
#else
|
|
|
|
struct upb_symtab;
|
|
|
|
typedef struct upb_symtab upb_symtab;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "upb/def.h"
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
|
|
|
class upb::SymbolTable {
|
|
|
|
public:
|
|
|
|
// Returns a new symbol table with a single ref owned by "owner."
|
|
|
|
// Returns NULL if memory allocation failed.
|
|
|
|
static reffed_ptr<SymbolTable> New();
|
|
|
|
|
|
|
|
// 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 not found, returns NULL.
|
|
|
|
reffed_ptr<const Def> Resolve(const char* base, const char* sym) const;
|
|
|
|
|
|
|
|
// Finds an entry in the symbol table with this exact name. If not found,
|
|
|
|
// returns NULL.
|
|
|
|
reffed_ptr<const Def> Lookup(const char *sym) const;
|
|
|
|
reffed_ptr<const MessageDef> LookupMessage(const char *sym) const;
|
|
|
|
|
|
|
|
// Gets an array of pointers to all currently active defs in this symtab.
|
|
|
|
// The caller owns the returned array (which is of length *n) as well as a
|
|
|
|
// ref to each symbol inside (owned by owner). If type is UPB_DEF_ANY then
|
|
|
|
// defs of all types are returned, otherwise only defs of the required type
|
|
|
|
// are returned.
|
|
|
|
const Def** GetDefs(upb_deftype_t type, const void *owner, int *n) const;
|
|
|
|
|
|
|
|
// Adds the given mutable defs to the symtab, resolving all symbols
|
|
|
|
// (including enum default values) and finalizing the defs. Only one def per
|
|
|
|
// name may be in the list, but defs can replace existing defs in the symtab.
|
|
|
|
// All defs must have a name -- anonymous defs are not allowed. Anonymous
|
|
|
|
// defs can still be frozen by calling upb_def_freeze() directly.
|
|
|
|
//
|
|
|
|
// Any existing defs that can reach defs that are being replaced will
|
|
|
|
// themselves be replaced also, so that the resulting set of defs is fully
|
|
|
|
// consistent.
|
|
|
|
//
|
|
|
|
// This logic implemented in this method is a convenience; ultimately it
|
|
|
|
// calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and
|
|
|
|
// upb_freeze(), any of which the client could call themself. However, since
|
|
|
|
// the logic for doing so is nontrivial, we provide it here.
|
|
|
|
//
|
|
|
|
// The entire operation either succeeds or fails. If the operation fails,
|
|
|
|
// the symtab is unchanged, false is returned, and status indicates the
|
|
|
|
// error. The caller passes a ref on all defs to the symtab (even if the
|
|
|
|
// operation fails).
|
|
|
|
//
|
|
|
|
// TODO(haberman): currently failure will leave the symtab unchanged, but may
|
|
|
|
// leave the defs themselves partially resolved. Does this matter? If so we
|
|
|
|
// could do a prepass that ensures that all symbols are resolvable and bail
|
|
|
|
// if not, so we don't mutate anything until we know the operation will
|
|
|
|
// succeed.
|
|
|
|
//
|
|
|
|
// TODO(haberman): since the defs must be mutable, refining a frozen def
|
|
|
|
// requires making mutable copies of the entire tree. This is wasteful if
|
|
|
|
// only a few messages are changing. We may want to add a way of adding a
|
|
|
|
// tree of frozen defs to the symtab (perhaps an alternate constructor where
|
|
|
|
// you pass the root of the tree?)
|
|
|
|
bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status);
|
|
|
|
|
|
|
|
bool Add(const std::vector<Def*>& defs, void *owner, Status* status) {
|
|
|
|
return Add((Def*const*)&defs[0], defs.size(), owner, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
UPB_DISALLOW_POD_OPS(SymbolTable, upb::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 {
|
|
|
|
|
|
|
|
template<>
|
|
|
|
class Pointer<SymbolTable> {
|
|
|
|
public:
|
|
|
|
explicit Pointer(SymbolTable* ptr) : ptr_(ptr) {}
|
|
|
|
operator SymbolTable*() { return ptr_; }
|
|
|
|
operator RefCounted*() { return UPB_UPCAST(ptr_); }
|
|
|
|
private:
|
|
|
|
SymbolTable* ptr_;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
class Pointer<const SymbolTable> {
|
|
|
|
public:
|
|
|
|
explicit Pointer(const SymbolTable* ptr) : ptr_(ptr) {}
|
|
|
|
operator const SymbolTable*() { return ptr_; }
|
|
|
|
operator const RefCounted*() { return UPB_UPCAST(ptr_); }
|
|
|
|
private:
|
|
|
|
const SymbolTable* ptr_;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline reffed_ptr<SymbolTable> SymbolTable::New() {
|
|
|
|
upb_symtab *s = upb_symtab_new(&s);
|
|
|
|
return reffed_ptr<SymbolTable>(s, &s);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 reffed_ptr<const Def> SymbolTable::Resolve(
|
|
|
|
const char* base, const char* sym) const {
|
|
|
|
const upb_def *def = upb_symtab_resolve(this, base, sym, &def);
|
|
|
|
return reffed_ptr<const Def>(def, &def);
|
|
|
|
}
|
|
|
|
inline reffed_ptr<const Def> SymbolTable::Lookup(const char *sym) const {
|
|
|
|
const upb_def *def = upb_symtab_lookup(this, sym, &def);
|
|
|
|
return reffed_ptr<const Def>(def, &def);
|
|
|
|
}
|
|
|
|
inline reffed_ptr<const MessageDef> SymbolTable::LookupMessage(
|
|
|
|
const char *sym) const {
|
|
|
|
const upb_msgdef *m = upb_symtab_lookupmsg(this, sym, &m);
|
|
|
|
return reffed_ptr<const MessageDef>(m, &m);
|
|
|
|
}
|
|
|
|
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_ */
|