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