summaryrefslogtreecommitdiff
path: root/upb/symtab.h
blob: f9a0a95f72782f658cdc58cada03707e4b50bdfa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 * 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_

#include "upb/def.h"

#ifdef __cplusplus
#include <vector>
namespace upb { class SymbolTable; }
#endif

UPB_DECLARE_DERIVED_TYPE(upb::SymbolTable, upb::RefCounted,
                         upb_symtab, upb_refcounted)

typedef struct {
 UPB_PRIVATE_FOR_CPP
  upb_strtable_iter iter;
  upb_deftype_t type;
} upb_symtab_iter;

#ifdef __cplusplus

/* Non-const methods in upb::SymbolTable are NOT thread-safe. */
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();

  /* Include RefCounted base methods. */
  UPB_REFCOUNTED_CPPMETHODS

  /* For all lookup functions, the returned pointer is not owned by the
   * caller; it may be invalidated by any non-const call or unref of the
   * SymbolTable!  To protect against this, take a ref if desired. */

  /* Freezes the symbol table: prevents further modification of it.
   * After the Freeze() operation is successful, the SymbolTable must only be
   * accessed via a const pointer.
   *
   * Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not
   * a necessary step in using a SymbolTable.  If you have no need for it to be
   * immutable, there is no need to freeze it ever.  However sometimes it is
   * useful, and SymbolTables that are statically compiled into the binary are
   * always frozen by nature. */
  void Freeze();

  /* 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. */
  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. */
  const Def* Lookup(const char *sym) const;
  const MessageDef* LookupMessage(const char *sym) const;
  const EnumDef* LookupEnum(const char *sym) const;

  /* TODO: introduce a C++ iterator, but make it nice and templated so that if
   * you ask for an iterator of MessageDef the iterated elements are strongly
   * typed as MessageDef*. */

  /* 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)
};

#endif  /* __cplusplus */

UPB_BEGIN_EXTERN_C

/* Native C API. */

/* Include refcounted methods like upb_symtab_ref(). */
UPB_REFCOUNTED_CMETHODS(upb_symtab, upb_symtab_upcast)

upb_symtab *upb_symtab_new(const void *owner);
void upb_symtab_freeze(upb_symtab *s);
const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
                                  const char *sym);
const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym);
const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym);
const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
                    upb_status *status);

/* upb_symtab_iter i;
 * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i);
 *     upb_symtab_next(&i)) {
 *   const upb_def *def = upb_symtab_iter_def(&i);
 *    // ...
 * }
 *
 * For C we don't have separate iterators for const and non-const.
 * It is the caller's responsibility to cast the upb_fielddef* to
 * const if the upb_msgdef* is const. */
void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
                      upb_deftype_t type);
void upb_symtab_next(upb_symtab_iter *iter);
bool upb_symtab_done(const upb_symtab_iter *iter);
const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter);

UPB_END_EXTERN_C

#ifdef __cplusplus
/* C++ inline wrappers. */
namespace upb {
inline reffed_ptr<SymbolTable> SymbolTable::New() {
  upb_symtab *s = upb_symtab_new(&s);
  return reffed_ptr<SymbolTable>(s, &s);
}

inline void SymbolTable::Freeze() {
  return upb_symtab_freeze(this);
}
inline const Def *SymbolTable::Resolve(const char *base,
                                       const char *sym) const {
  return upb_symtab_resolve(this, base, sym);
}
inline const Def* SymbolTable::Lookup(const char *sym) const {
  return upb_symtab_lookup(this, sym);
}
inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const {
  return upb_symtab_lookupmsg(this, sym);
}
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_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback