| 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 | |