1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIB_FIDL_CPP_BUILDER_H_ 6 #define LIB_FIDL_CPP_BUILDER_H_ 7 8 #include <new> // For placement new. 9 #include <stdalign.h> 10 #include <stdint.h> 11 12 #include <lib/fidl/cpp/message_part.h> 13 #include <zircon/compiler.h> 14 #include <zircon/fidl.h> 15 #include <zircon/types.h> 16 17 namespace fidl { 18 19 // Builder helps FIDL clients store decoded objects in a buffer. 20 // 21 // Objects are allocated sequentually in the buffer with appropriate alignment 22 // for in-place encoding. The client is responsible for ordering the objects in 23 // the buffer appropriately. 24 class Builder { 25 public: 26 // Creates a buffer without any storage. 27 Builder(); 28 29 // Creates a buffer that stores objects in the given memory. 30 // 31 // The constructed |Builder| object does not take ownership of the given 32 // storage. 33 Builder(void* buffer, uint32_t capacity); 34 ~Builder(); 35 36 Builder(const Builder& other) = delete; 37 Builder& operator=(const Builder& other) = delete; 38 39 Builder(Builder&& other); 40 Builder& operator=(Builder&& other); 41 42 // Allocates storage in the buffer of sufficient size to store an object of 43 // type |T|. The object must have alignment constraints that are compatible 44 // with FIDL messages. 45 // 46 // If there is insufficient storage in the builder's buffer, this method 47 // returns nullptr. 48 template <typename T> New()49 T* New() { 50 static_assert(alignof(T) <= FIDL_ALIGNMENT, ""); 51 static_assert(sizeof(T) <= ZX_CHANNEL_MAX_MSG_BYTES, ""); 52 if (void* ptr = Allocate(sizeof(T))) 53 return new (ptr) T; 54 return nullptr; 55 } 56 57 // Allocates storage in the buffer of sufficient size to store |count| 58 // objects of type |T|. The object must have alignment constraints that are 59 // compatible with FIDL messages. 60 // 61 // If there is insufficient storage in the builder's buffer, this method 62 // returns nullptr. 63 template <typename T> NewArray(uint32_t count)64 T* NewArray(uint32_t count) { 65 static_assert(alignof(T) <= FIDL_ALIGNMENT, ""); 66 static_assert(sizeof(T) <= ZX_CHANNEL_MAX_MSG_BYTES, ""); 67 if (sizeof(T) * static_cast<uint64_t>(count) > UINT32_MAX) 68 return nullptr; 69 if (void* ptr = Allocate(static_cast<uint32_t>(sizeof(T) * count))) 70 return new (ptr) T[count]; 71 return nullptr; 72 } 73 74 // Completes the building and returns a |MesssagePart| containing the 75 // allocated objects. 76 // 77 // The allocated objects are placed in the returned buffer in the order in 78 // which they were allocated, with appropriate alignment for a FIDL message. 79 // The returned buffer's capacity cooresponds to the capacity originally 80 // provided to this builder in its constructor. 81 BytePart Finalize(); 82 83 // Attaches the given storage to the |Builder|. 84 // 85 // The |Builder| object does not take ownership of the given storage. The 86 // next object will be allocated at the start of the buffer. 87 void Reset(void* buffer, uint32_t capacity); 88 89 protected: buffer()90 uint8_t* buffer() const { return buffer_; } capacity()91 uint32_t capacity() const { return capacity_; } 92 93 private: 94 // Returns |size| bytes of zeroed memory aligned to at least FIDL_ALIGNMENT 95 void* Allocate(uint32_t size); 96 97 uint32_t capacity_; 98 uint32_t at_; 99 uint8_t* buffer_; 100 }; 101 102 } // namespace fidl 103 104 #endif // LIB_FIDL_CPP_BUILDER_H_ 105