/src/capnproto/c++/src/capnp/raw-schema.h
Line | Count | Source |
1 | | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors |
2 | | // Licensed under the MIT License: |
3 | | // |
4 | | // Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | // of this software and associated documentation files (the "Software"), to deal |
6 | | // in the Software without restriction, including without limitation the rights |
7 | | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
8 | | // copies of the Software, and to permit persons to whom the Software is |
9 | | // furnished to do so, subject to the following conditions: |
10 | | // |
11 | | // The above copyright notice and this permission notice shall be included in |
12 | | // all copies or substantial portions of the Software. |
13 | | // |
14 | | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
19 | | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
20 | | // THE SOFTWARE. |
21 | | |
22 | | #pragma once |
23 | | |
24 | | #include "common.h" // for uint and friends |
25 | | |
26 | | #if _MSC_VER && !defined(__clang__) |
27 | | #include <atomic> |
28 | | #endif |
29 | | |
30 | | CAPNP_BEGIN_HEADER |
31 | | |
32 | | namespace capnp { |
33 | | namespace _ { // private |
34 | | |
35 | | struct RawSchema; |
36 | | |
37 | | struct RawBrandedSchema { |
38 | | // Represents a combination of a schema and bindings for its generic parameters. |
39 | | // |
40 | | // Note that while we generate one `RawSchema` per type, we generate a `RawBrandedSchema` for |
41 | | // every _instance_ of a generic type -- or, at least, every instance that is actually used. For |
42 | | // generated-code types, we use template magic to initialize these. |
43 | | |
44 | | const RawSchema* generic; |
45 | | // Generic type which we're branding. |
46 | | |
47 | | struct Binding { |
48 | | uint8_t which; // Numeric value of one of schema::Type::Which. |
49 | | |
50 | | bool isImplicitParameter; |
51 | | // For AnyPointer, true if it's an implicit method parameter. |
52 | | |
53 | | uint16_t listDepth; // Number of times to wrap the base type in List(). |
54 | | |
55 | | uint16_t paramIndex; |
56 | | // For AnyPointer. If it's a type parameter (scopeId is non-zero) or it's an implicit parameter |
57 | | // (isImplicitParameter is true), then this is the parameter index. Otherwise this is a numeric |
58 | | // value of one of schema::Type::AnyPointer::Unconstrained::Which. |
59 | | |
60 | | union { |
61 | | const RawBrandedSchema* schema; // for struct, enum, interface |
62 | | uint64_t scopeId; // for AnyPointer, if it's a type parameter |
63 | | }; |
64 | | |
65 | | Binding() = default; |
66 | | inline constexpr Binding(uint8_t which, uint16_t listDepth, const RawBrandedSchema* schema) |
67 | 24 | : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(0), |
68 | 24 | schema(schema) {} |
69 | | inline constexpr Binding(uint8_t which, uint16_t listDepth, |
70 | | uint64_t scopeId, uint16_t paramIndex) |
71 | | : which(which), isImplicitParameter(false), listDepth(listDepth), paramIndex(paramIndex), |
72 | 0 | scopeId(scopeId) {} |
73 | | inline constexpr Binding(uint8_t which, uint16_t listDepth, uint16_t implicitParamIndex) |
74 | | : which(which), isImplicitParameter(true), listDepth(listDepth), |
75 | 0 | paramIndex(implicitParamIndex), scopeId(0) {} |
76 | | }; |
77 | | |
78 | | struct Scope { |
79 | | uint64_t typeId; |
80 | | // Type ID whose parameters are being bound. |
81 | | |
82 | | const Binding* bindings; |
83 | | uint bindingCount; |
84 | | // Bindings for those parameters. |
85 | | |
86 | | bool isUnbound; |
87 | | // This scope is unbound, in the sense of SchemaLoader::getUnbound(). |
88 | | }; |
89 | | |
90 | | const Scope* scopes; |
91 | | // Array of enclosing scopes for which generic variables have been bound, sorted by type ID. |
92 | | |
93 | | struct Dependency { |
94 | | uint location; |
95 | | const RawBrandedSchema* schema; |
96 | | }; |
97 | | |
98 | | const Dependency* dependencies; |
99 | | // Map of branded schemas for dependencies of this type, given our brand. Only dependencies that |
100 | | // are branded are included in this map; if a dependency is missing, use its `defaultBrand`. |
101 | | |
102 | | uint32_t scopeCount; |
103 | | uint32_t dependencyCount; |
104 | | |
105 | | enum class DepKind { |
106 | | // Component of a Dependency::location. Specifies what sort of dependency this is. |
107 | | |
108 | | INVALID, |
109 | | // Mostly defined to ensure that zero is not a valid location. |
110 | | |
111 | | FIELD, |
112 | | // Binding needed for a field's type. The index is the field index (NOT ordinal!). |
113 | | |
114 | | METHOD_PARAMS, |
115 | | // Bindings needed for a method's params type. The index is the method number. |
116 | | |
117 | | METHOD_RESULTS, |
118 | | // Bindings needed for a method's results type. The index is the method ordinal. |
119 | | |
120 | | SUPERCLASS, |
121 | | // Bindings needed for a superclass type. The index is the superclass's index in the |
122 | | // "extends" list. |
123 | | |
124 | | CONST_TYPE |
125 | | // Bindings needed for the type of a constant. The index is zero. |
126 | | }; |
127 | | |
128 | 0 | static inline uint makeDepLocation(DepKind kind, uint index) { |
129 | | // Make a number representing the location of a particular dependency within its parent |
130 | | // schema. |
131 | |
|
132 | 0 | return (static_cast<uint>(kind) << 24) | index; |
133 | 0 | } |
134 | | |
135 | | class Initializer { |
136 | | public: |
137 | | virtual void init(const RawBrandedSchema* generic) const = 0; |
138 | | }; |
139 | | |
140 | | const Initializer* lazyInitializer; |
141 | | // Lazy initializer, invoked by ensureInitialized(). |
142 | | |
143 | 0 | inline void ensureInitialized() const { |
144 | | // Lazy initialization support. Invoke to ensure that initialization has taken place. This |
145 | | // is required in particular when traversing the dependency list. RawSchemas for compiled-in |
146 | | // types are always initialized; only dynamically-loaded schemas may be lazy. |
147 | |
|
148 | 0 | #if __GNUC__ || defined(__clang__) |
149 | 0 | const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); |
150 | | #elif _MSC_VER |
151 | | const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer); |
152 | | std::atomic_thread_fence(std::memory_order_acquire); |
153 | | #else |
154 | | #error "Platform not supported" |
155 | | #endif |
156 | 0 | if (i != nullptr) i->init(this); |
157 | 0 | } |
158 | | |
159 | | inline bool isUnbound() const; |
160 | | // Checks if this schema is the result of calling SchemaLoader::getUnbound(), in which case |
161 | | // binding lookups need to be handled specially. |
162 | | }; |
163 | | |
164 | | struct RawSchema { |
165 | | // The generated code defines a constant RawSchema for every compiled declaration. |
166 | | // |
167 | | // This is an internal structure which could change in the future. |
168 | | |
169 | | uint64_t id; |
170 | | |
171 | | const word* encodedNode; |
172 | | // Encoded SchemaNode, readable via readMessageUnchecked<schema::Node>(encodedNode). |
173 | | |
174 | | uint32_t encodedSize; |
175 | | // Size of encodedNode, in words. |
176 | | |
177 | | const RawSchema* const* dependencies; |
178 | | // Pointers to other types on which this one depends, sorted by ID. The schemas in this table |
179 | | // may be uninitialized -- you must call ensureInitialized() on the one you wish to use before |
180 | | // using it. |
181 | | // |
182 | | // TODO(someday): Make this a hashtable. |
183 | | |
184 | | const uint16_t* membersByName; |
185 | | // Indexes of members sorted by name. Used to implement name lookup. |
186 | | // TODO(someday): Make this a hashtable. |
187 | | |
188 | | uint32_t dependencyCount; |
189 | | uint32_t memberCount; |
190 | | // Sizes of above tables. |
191 | | |
192 | | const uint16_t* membersByDiscriminant; |
193 | | // List of all member indexes ordered by discriminant value. Those which don't have a |
194 | | // discriminant value are listed at the end, in order by ordinal. |
195 | | |
196 | | const RawSchema* canCastTo; |
197 | | // Points to the RawSchema of a compiled-in type to which it is safe to cast any DynamicValue |
198 | | // with this schema. This is null for all compiled-in types; it is only set by SchemaLoader on |
199 | | // dynamically-loaded types. |
200 | | |
201 | | class Initializer { |
202 | | public: |
203 | | virtual void init(const RawSchema* schema) const = 0; |
204 | | }; |
205 | | |
206 | | const Initializer* lazyInitializer; |
207 | | // Lazy initializer, invoked by ensureInitialized(). |
208 | | |
209 | 0 | inline void ensureInitialized() const { |
210 | | // Lazy initialization support. Invoke to ensure that initialization has taken place. This |
211 | | // is required in particular when traversing the dependency list. RawSchemas for compiled-in |
212 | | // types are always initialized; only dynamically-loaded schemas may be lazy. |
213 | |
|
214 | 0 | #if __GNUC__ || defined(__clang__) |
215 | 0 | const Initializer* i = __atomic_load_n(&lazyInitializer, __ATOMIC_ACQUIRE); |
216 | | #elif _MSC_VER |
217 | | const Initializer* i = *static_cast<Initializer const* const volatile*>(&lazyInitializer); |
218 | | std::atomic_thread_fence(std::memory_order_acquire); |
219 | | #else |
220 | | #error "Platform not supported" |
221 | | #endif |
222 | 0 | if (i != nullptr) i->init(this); |
223 | 0 | } |
224 | | |
225 | | RawBrandedSchema defaultBrand; |
226 | | // Specifies the brand to use for this schema if no generic parameters have been bound to |
227 | | // anything. Generally, in the default brand, all generic parameters are treated as if they were |
228 | | // bound to `AnyPointer`. |
229 | | |
230 | | bool mayContainCapabilities = true; |
231 | | // See StructSchema::mayContainCapabilities. |
232 | | }; |
233 | | |
234 | 0 | inline bool RawBrandedSchema::isUnbound() const { |
235 | | // The unbound schema is the only one that has no scopes but is not the default schema. |
236 | 0 | return scopeCount == 0 && this != &generic->defaultBrand; |
237 | 0 | } |
238 | | |
239 | | } // namespace _ (private) |
240 | | } // namespace capnp |
241 | | |
242 | | CAPNP_END_HEADER |