Mercurial > hg > sv-dependency-builds
comparison osx/include/capnp/orphan.h @ 49:3ab5a40c4e3b
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
48:9530b331f8c1 | 49:3ab5a40c4e3b |
---|---|
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 #ifndef CAPNP_ORPHAN_H_ | |
23 #define CAPNP_ORPHAN_H_ | |
24 | |
25 #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) | |
26 #pragma GCC system_header | |
27 #endif | |
28 | |
29 #include "layout.h" | |
30 | |
31 namespace capnp { | |
32 | |
33 class StructSchema; | |
34 class ListSchema; | |
35 struct DynamicStruct; | |
36 struct DynamicList; | |
37 namespace _ { struct OrphanageInternal; } | |
38 | |
39 template <typename T> | |
40 class Orphan { | |
41 // Represents an object which is allocated within some message builder but has no pointers | |
42 // pointing at it. An Orphan can later be "adopted" by some other object as one of that object's | |
43 // fields, without having to copy the orphan. For a field `foo` of pointer type, the generated | |
44 // code will define builder methods `void adoptFoo(Orphan<T>)` and `Orphan<T> disownFoo()`. | |
45 // Orphans can also be created independently of any parent using an Orphanage. | |
46 // | |
47 // `Orphan<T>` can be moved but not copied, like `Own<T>`, so that it is impossible for one | |
48 // orphan to be adopted multiple times. If an orphan is destroyed without being adopted, its | |
49 // contents are zero'd out (and possibly reused, if we ever implement the ability to reuse space | |
50 // in a message arena). | |
51 | |
52 public: | |
53 Orphan() = default; | |
54 KJ_DISALLOW_COPY(Orphan); | |
55 Orphan(Orphan&&) = default; | |
56 Orphan& operator=(Orphan&&) = default; | |
57 inline Orphan(_::OrphanBuilder&& builder): builder(kj::mv(builder)) {} | |
58 | |
59 inline BuilderFor<T> get(); | |
60 // Get the underlying builder. If the orphan is null, this will allocate and return a default | |
61 // object rather than crash. This is done for security -- otherwise, you might enable a DoS | |
62 // attack any time you disown a field and fail to check if it is null. In the case of structs, | |
63 // this means that the orphan is no longer null after get() returns. In the case of lists, | |
64 // no actual object is allocated since a simple empty ListBuilder can be returned. | |
65 | |
66 inline ReaderFor<T> getReader() const; | |
67 | |
68 inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } | |
69 inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } | |
70 | |
71 inline void truncate(uint size); | |
72 // Resize an object (which must be a list or a blob) to the given size. | |
73 // | |
74 // If the new size is less than the original, the remaining elements will be discarded. The | |
75 // list is never moved in this case. If the list happens to be located at the end of its segment | |
76 // (which is always true if the list was the last thing allocated), the removed memory will be | |
77 // reclaimed (reducing the messag size), otherwise it is simply zeroed. The reclaiming behavior | |
78 // is particularly useful for allocating buffer space when you aren't sure how much space you | |
79 // actually need: you can pre-allocate, say, a 4k byte array, read() from a file into it, and | |
80 // then truncate it back to the amount of space actually used. | |
81 // | |
82 // If the new size is greater than the original, the list is extended with default values. If | |
83 // the list is the last object in its segment *and* there is enough space left in the segment to | |
84 // extend it to cover the new values, then the list is extended in-place. Otherwise, it must be | |
85 // moved to a new location, leaving a zero'd hole in the previous space that won't be filled. | |
86 // This copy is shallow; sub-objects will simply be reparented, not copied. | |
87 // | |
88 // Any existing readers or builders pointing at the object are invalidated by this call (even if | |
89 // it doesn't move). You must call `get()` or `getReader()` again to get the new, valid pointer. | |
90 | |
91 private: | |
92 _::OrphanBuilder builder; | |
93 | |
94 template <typename, Kind> | |
95 friend struct _::PointerHelpers; | |
96 template <typename, Kind> | |
97 friend struct List; | |
98 template <typename U> | |
99 friend class Orphan; | |
100 friend class Orphanage; | |
101 friend class MessageBuilder; | |
102 }; | |
103 | |
104 class Orphanage: private kj::DisallowConstCopy { | |
105 // Use to directly allocate Orphan objects, without having a parent object allocate and then | |
106 // disown the object. | |
107 | |
108 public: | |
109 inline Orphanage(): arena(nullptr) {} | |
110 | |
111 template <typename BuilderType> | |
112 static Orphanage getForMessageContaining(BuilderType builder); | |
113 // Construct an Orphanage that allocates within the message containing the given Builder. This | |
114 // allows the constructed Orphans to be adopted by objects within said message. | |
115 // | |
116 // This constructor takes the builder rather than having the builder have a getOrphanage() method | |
117 // because this is an advanced feature and we don't want to pollute the builder APIs with it. | |
118 // | |
119 // Note that if you have a direct pointer to the `MessageBuilder`, you can simply call its | |
120 // `getOrphanage()` method. | |
121 | |
122 template <typename RootType> | |
123 Orphan<RootType> newOrphan() const; | |
124 // Allocate a new orphaned struct. | |
125 | |
126 template <typename RootType> | |
127 Orphan<RootType> newOrphan(uint size) const; | |
128 // Allocate a new orphaned list or blob. | |
129 | |
130 Orphan<DynamicStruct> newOrphan(StructSchema schema) const; | |
131 // Dynamically create an orphan struct with the given schema. You must | |
132 // #include <capnp/dynamic.h> to use this. | |
133 | |
134 Orphan<DynamicList> newOrphan(ListSchema schema, uint size) const; | |
135 // Dynamically create an orphan list with the given schema. You must #include <capnp/dynamic.h> | |
136 // to use this. | |
137 | |
138 template <typename Reader> | |
139 Orphan<FromReader<Reader>> newOrphanCopy(Reader copyFrom) const; | |
140 // Allocate a new orphaned object (struct, list, or blob) and initialize it as a copy of the | |
141 // given object. | |
142 | |
143 template <typename T> | |
144 Orphan<List<ListElementType<FromReader<T>>>> newOrphanConcat(kj::ArrayPtr<T> lists) const; | |
145 template <typename T> | |
146 Orphan<List<ListElementType<FromReader<T>>>> newOrphanConcat(kj::ArrayPtr<const T> lists) const; | |
147 // Given an array of List readers, copy and concatenate the lists, creating a new Orphan. | |
148 // | |
149 // Note that compared to allocating the list yourself and using `setWithCaveats()` to set each | |
150 // item, this method avoids the "caveats": the new list will be allocated with the element size | |
151 // being the maximum of that from all the input lists. This is particularly important when | |
152 // concatenating struct lists: if the lists were created using a newer version of the protocol | |
153 // in which some new fields had been added to the struct, using `setWithCaveats()` would | |
154 // truncate off those new fields. | |
155 | |
156 Orphan<Data> referenceExternalData(Data::Reader data) const; | |
157 // Creates an Orphan<Data> that points at an existing region of memory (e.g. from another message) | |
158 // without copying it. There are some SEVERE restrictions on how this can be used: | |
159 // - The memory must remain valid until the `MessageBuilder` is destroyed (even if the orphan is | |
160 // abandoned). | |
161 // - Because the data is const, you will not be allowed to obtain a `Data::Builder` | |
162 // for this blob. Any call which would return such a builder will throw an exception. You | |
163 // can, however, obtain a Reader, e.g. via orphan.getReader() or from a parent Reader (once | |
164 // the orphan is adopted). It is your responsibility to make sure your code can deal with | |
165 // these problems when using this optimization; if you can't, allocate a copy instead. | |
166 // - `data.begin()` must be aligned to a machine word boundary (32-bit or 64-bit depending on | |
167 // the CPU). Any pointer returned by malloc() as well as any data blob obtained from another | |
168 // Cap'n Proto message satisfies this. | |
169 // - If `data.size()` is not a multiple of 8, extra bytes past data.end() up until the next 8-byte | |
170 // boundary will be visible in the raw message when it is written out. Thus, there must be no | |
171 // secrets in these bytes. Data blobs obtained from other Cap'n Proto messages should be safe | |
172 // as these bytes should be zero (unless the sender had the same problem). | |
173 // | |
174 // The array will actually become one of the message's segments. The data can thus be adopted | |
175 // into the message tree without copying it. This is particularly useful when referencing very | |
176 // large blobs, such as whole mmap'd files. | |
177 | |
178 private: | |
179 _::BuilderArena* arena; | |
180 _::CapTableBuilder* capTable; | |
181 | |
182 inline explicit Orphanage(_::BuilderArena* arena, _::CapTableBuilder* capTable) | |
183 : arena(arena), capTable(capTable) {} | |
184 | |
185 template <typename T, Kind = CAPNP_KIND(T)> | |
186 struct GetInnerBuilder; | |
187 template <typename T, Kind = CAPNP_KIND(T)> | |
188 struct GetInnerReader; | |
189 template <typename T> | |
190 struct NewOrphanListImpl; | |
191 | |
192 friend class MessageBuilder; | |
193 friend struct _::OrphanageInternal; | |
194 }; | |
195 | |
196 // ======================================================================================= | |
197 // Inline implementation details. | |
198 | |
199 namespace _ { // private | |
200 | |
201 template <typename T, Kind = CAPNP_KIND(T)> | |
202 struct OrphanGetImpl; | |
203 | |
204 template <typename T> | |
205 struct OrphanGetImpl<T, Kind::PRIMITIVE> { | |
206 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
207 builder.truncate(size, _::elementSizeForType<T>()); | |
208 } | |
209 }; | |
210 | |
211 template <typename T> | |
212 struct OrphanGetImpl<T, Kind::STRUCT> { | |
213 static inline typename T::Builder apply(_::OrphanBuilder& builder) { | |
214 return typename T::Builder(builder.asStruct(_::structSize<T>())); | |
215 } | |
216 static inline typename T::Reader applyReader(const _::OrphanBuilder& builder) { | |
217 return typename T::Reader(builder.asStructReader(_::structSize<T>())); | |
218 } | |
219 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
220 builder.truncate(size, _::structSize<T>()); | |
221 } | |
222 }; | |
223 | |
224 #if !CAPNP_LITE | |
225 template <typename T> | |
226 struct OrphanGetImpl<T, Kind::INTERFACE> { | |
227 static inline typename T::Client apply(_::OrphanBuilder& builder) { | |
228 return typename T::Client(builder.asCapability()); | |
229 } | |
230 static inline typename T::Client applyReader(const _::OrphanBuilder& builder) { | |
231 return typename T::Client(builder.asCapability()); | |
232 } | |
233 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
234 builder.truncate(size, ElementSize::POINTER); | |
235 } | |
236 }; | |
237 #endif // !CAPNP_LITE | |
238 | |
239 template <typename T, Kind k> | |
240 struct OrphanGetImpl<List<T, k>, Kind::LIST> { | |
241 static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) { | |
242 return typename List<T>::Builder(builder.asList(_::ElementSizeForType<T>::value)); | |
243 } | |
244 static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) { | |
245 return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value)); | |
246 } | |
247 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
248 builder.truncate(size, ElementSize::POINTER); | |
249 } | |
250 }; | |
251 | |
252 template <typename T> | |
253 struct OrphanGetImpl<List<T, Kind::STRUCT>, Kind::LIST> { | |
254 static inline typename List<T>::Builder apply(_::OrphanBuilder& builder) { | |
255 return typename List<T>::Builder(builder.asStructList(_::structSize<T>())); | |
256 } | |
257 static inline typename List<T>::Reader applyReader(const _::OrphanBuilder& builder) { | |
258 return typename List<T>::Reader(builder.asListReader(_::ElementSizeForType<T>::value)); | |
259 } | |
260 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
261 builder.truncate(size, ElementSize::POINTER); | |
262 } | |
263 }; | |
264 | |
265 template <> | |
266 struct OrphanGetImpl<Text, Kind::BLOB> { | |
267 static inline Text::Builder apply(_::OrphanBuilder& builder) { | |
268 return Text::Builder(builder.asText()); | |
269 } | |
270 static inline Text::Reader applyReader(const _::OrphanBuilder& builder) { | |
271 return Text::Reader(builder.asTextReader()); | |
272 } | |
273 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
274 builder.truncate(size, ElementSize::POINTER); | |
275 } | |
276 }; | |
277 | |
278 template <> | |
279 struct OrphanGetImpl<Data, Kind::BLOB> { | |
280 static inline Data::Builder apply(_::OrphanBuilder& builder) { | |
281 return Data::Builder(builder.asData()); | |
282 } | |
283 static inline Data::Reader applyReader(const _::OrphanBuilder& builder) { | |
284 return Data::Reader(builder.asDataReader()); | |
285 } | |
286 static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { | |
287 builder.truncate(size, ElementSize::POINTER); | |
288 } | |
289 }; | |
290 | |
291 struct OrphanageInternal { | |
292 static inline _::BuilderArena* getArena(Orphanage orphanage) { return orphanage.arena; } | |
293 static inline _::CapTableBuilder* getCapTable(Orphanage orphanage) { return orphanage.capTable; } | |
294 }; | |
295 | |
296 } // namespace _ (private) | |
297 | |
298 template <typename T> | |
299 inline BuilderFor<T> Orphan<T>::get() { | |
300 return _::OrphanGetImpl<T>::apply(builder); | |
301 } | |
302 | |
303 template <typename T> | |
304 inline ReaderFor<T> Orphan<T>::getReader() const { | |
305 return _::OrphanGetImpl<T>::applyReader(builder); | |
306 } | |
307 | |
308 template <typename T> | |
309 inline void Orphan<T>::truncate(uint size) { | |
310 _::OrphanGetImpl<ListElementType<T>>::truncateListOf(builder, size * ELEMENTS); | |
311 } | |
312 | |
313 template <> | |
314 inline void Orphan<Text>::truncate(uint size) { | |
315 builder.truncateText(size * ELEMENTS); | |
316 } | |
317 | |
318 template <> | |
319 inline void Orphan<Data>::truncate(uint size) { | |
320 builder.truncate(size * ELEMENTS, ElementSize::BYTE); | |
321 } | |
322 | |
323 template <typename T> | |
324 struct Orphanage::GetInnerBuilder<T, Kind::STRUCT> { | |
325 static inline _::StructBuilder apply(typename T::Builder& t) { | |
326 return t._builder; | |
327 } | |
328 }; | |
329 | |
330 template <typename T> | |
331 struct Orphanage::GetInnerBuilder<T, Kind::LIST> { | |
332 static inline _::ListBuilder apply(typename T::Builder& t) { | |
333 return t.builder; | |
334 } | |
335 }; | |
336 | |
337 template <typename BuilderType> | |
338 Orphanage Orphanage::getForMessageContaining(BuilderType builder) { | |
339 auto inner = GetInnerBuilder<FromBuilder<BuilderType>>::apply(builder); | |
340 return Orphanage(inner.getArena(), inner.getCapTable()); | |
341 } | |
342 | |
343 template <typename RootType> | |
344 Orphan<RootType> Orphanage::newOrphan() const { | |
345 return Orphan<RootType>(_::OrphanBuilder::initStruct(arena, capTable, _::structSize<RootType>())); | |
346 } | |
347 | |
348 template <typename T, Kind k> | |
349 struct Orphanage::NewOrphanListImpl<List<T, k>> { | |
350 static inline _::OrphanBuilder apply( | |
351 _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { | |
352 return _::OrphanBuilder::initList( | |
353 arena, capTable, size * ELEMENTS, _::ElementSizeForType<T>::value); | |
354 } | |
355 }; | |
356 | |
357 template <typename T> | |
358 struct Orphanage::NewOrphanListImpl<List<T, Kind::STRUCT>> { | |
359 static inline _::OrphanBuilder apply( | |
360 _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { | |
361 return _::OrphanBuilder::initStructList( | |
362 arena, capTable, size * ELEMENTS, _::structSize<T>()); | |
363 } | |
364 }; | |
365 | |
366 template <> | |
367 struct Orphanage::NewOrphanListImpl<Text> { | |
368 static inline _::OrphanBuilder apply( | |
369 _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { | |
370 return _::OrphanBuilder::initText(arena, capTable, size * BYTES); | |
371 } | |
372 }; | |
373 | |
374 template <> | |
375 struct Orphanage::NewOrphanListImpl<Data> { | |
376 static inline _::OrphanBuilder apply( | |
377 _::BuilderArena* arena, _::CapTableBuilder* capTable, uint size) { | |
378 return _::OrphanBuilder::initData(arena, capTable, size * BYTES); | |
379 } | |
380 }; | |
381 | |
382 template <typename RootType> | |
383 Orphan<RootType> Orphanage::newOrphan(uint size) const { | |
384 return Orphan<RootType>(NewOrphanListImpl<RootType>::apply(arena, capTable, size)); | |
385 } | |
386 | |
387 template <typename T> | |
388 struct Orphanage::GetInnerReader<T, Kind::STRUCT> { | |
389 static inline _::StructReader apply(const typename T::Reader& t) { | |
390 return t._reader; | |
391 } | |
392 }; | |
393 | |
394 template <typename T> | |
395 struct Orphanage::GetInnerReader<T, Kind::LIST> { | |
396 static inline _::ListReader apply(const typename T::Reader& t) { | |
397 return t.reader; | |
398 } | |
399 }; | |
400 | |
401 template <typename T> | |
402 struct Orphanage::GetInnerReader<T, Kind::BLOB> { | |
403 static inline const typename T::Reader& apply(const typename T::Reader& t) { | |
404 return t; | |
405 } | |
406 }; | |
407 | |
408 template <typename Reader> | |
409 inline Orphan<FromReader<Reader>> Orphanage::newOrphanCopy(Reader copyFrom) const { | |
410 return Orphan<FromReader<Reader>>(_::OrphanBuilder::copy( | |
411 arena, capTable, GetInnerReader<FromReader<Reader>>::apply(copyFrom))); | |
412 } | |
413 | |
414 template <typename T> | |
415 inline Orphan<List<ListElementType<FromReader<T>>>> | |
416 Orphanage::newOrphanConcat(kj::ArrayPtr<T> lists) const { | |
417 return newOrphanConcat(kj::implicitCast<kj::ArrayPtr<const T>>(lists)); | |
418 } | |
419 template <typename T> | |
420 inline Orphan<List<ListElementType<FromReader<T>>>> | |
421 Orphanage::newOrphanConcat(kj::ArrayPtr<const T> lists) const { | |
422 // Optimization / simplification: Rely on List<T>::Reader containing nothing except a | |
423 // _::ListReader. | |
424 static_assert(sizeof(T) == sizeof(_::ListReader), "lists are not bare readers?"); | |
425 kj::ArrayPtr<const _::ListReader> raw( | |
426 reinterpret_cast<const _::ListReader*>(lists.begin()), lists.size()); | |
427 typedef ListElementType<FromReader<T>> Element; | |
428 return Orphan<List<Element>>( | |
429 _::OrphanBuilder::concat(arena, capTable, | |
430 _::elementSizeForType<Element>(), | |
431 _::minStructSizeForElement<Element>(), raw)); | |
432 } | |
433 | |
434 inline Orphan<Data> Orphanage::referenceExternalData(Data::Reader data) const { | |
435 return Orphan<Data>(_::OrphanBuilder::referenceExternalData(arena, data)); | |
436 } | |
437 | |
438 } // namespace capnp | |
439 | |
440 #endif // CAPNP_ORPHAN_H_ |