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