1 /* Copyright (c) 2010-2015 Stanford University
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #ifndef CEPH_COMMON_TUB_H
17 #define CEPH_COMMON_TUB_H
20 * A Tub holds an object that may be uninitialized; it allows the allocation of
21 * memory for objects to be separated from its construction and destruction.
22 * When you initially create a Tub its object is uninitialized (and should not
23 * be used). You can call #construct and #destroy to invoke the constructor and
24 * destructor of the embedded object, and #get or #operator-> will return the
25 * embedded object. The embedded object is automatically destroyed when the Tub
26 * is destroyed (if it was ever constructed in the first place).
28 * Tubs are useful in situations like the following:
29 * - You want to create an array of objects, but the objects need complex
30 * constructors with multiple arguments.
31 * - You want to create a collection of objects, only some of which will be
32 * used, and you don't want to pay the cost of constructing objects that will
34 * - You want automatic destruction of an object but don't want to
35 * heap-allocate the object (as with std::unique_ptr).
36 * - You want a way to return failure from a method without using pointers,
37 * exceptions, or special values (e.g. -1). The Tub gives you a 'maybe'
38 * object; it may be empty if a failure occurred.
39 * - You want a singleton, but don't want to deal with heap-allocating an
40 * object on first use and freeing it later. Instead, just declare your object
42 * if (!tub) tub.construct();
43 * - You want optional arguments to a function, but don't want to use pointers
44 * (i.e. use the Tub's boolean to determine that an argument was passed,
45 * rather than checking arg != NULL).
47 * Tub is CopyConstructible if and only if ElementType is CopyConstructible,
48 * and Tub is Assignable if and only if ElementType is Assignable.
51 * The type of the object to be stored within the Tub.
53 template<typename ElementType>
56 /// The type of the object to be stored within the Tub.
57 typedef ElementType element_type;
60 * Default constructor: the object starts off uninitialized.
62 Tub(): occupied(false) {}
65 * Construct an occupied Tub, whose contained object is initialized
66 * with a copy of the given object.
68 * ElementType is CopyConstructible.
72 Tub(const ElementType& other) // NOLINT
78 * Construct an occupied Tub, whose contained object is initialized
79 * with a move of the given object.
81 * ElementType is MoveConstructible.
85 Tub(ElementType&& other) // NOLINT
87 construct(std::move(other));
92 * The object will be initialized if and only if the source of the copy is
95 * ElementType is CopyConstructible.
99 Tub(const Tub<ElementType>& other) // NOLINT
101 if (other.occupied) {
102 construct(*other.object); // use ElementType's copy constructor
108 * The object will be initialized if and only if the source of the move is
111 * ElementType is MoveConstructible.
113 * Source of the move.
115 Tub(Tub<ElementType>&& other) // NOLINT
118 construct(std::move(*other.object)); // use ElementType's copy constructor
122 * Destructor: destroy the object if it was initialized.
129 * Assignment: destroy current object if initialized, replace with
130 * source. Result will be uninitialized if source is uninitialized.
132 * ElementType is Assignable.
134 Tub<ElementType>& operator=(const Tub<ElementType>& other) {
135 if (this != &other) {
136 if (other.occupied) {
138 #if __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
139 #pragma GCC diagnostic push
140 #pragma GCC diagnostic ignored "-Warray-bounds"
142 *object = *other.object; // use ElementType's assignment
143 #if __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
144 #pragma GCC diagnostic pop
147 construct(*other.object);
157 * Assignment: destroy current object if initialized, replace with
158 * source. Result will be uninitialized if source is uninitialized.
160 * ElementType is Assignable.
162 Tub<ElementType>& operator=(Tub<ElementType> &&other) {
163 if (this != &other) {
164 if (other.occupied) {
166 *object = std::move(*other.object);
168 construct(std::move(*other.object));
178 * Assignment: destroy current object if initialized, replace with
179 * source. Result will be uninitialized if source is uninitialized.
181 * ElementType is Assignable.
183 Tub<ElementType>& operator=(ElementType &&elt) {
185 *object = std::move(elt);
187 construct(std::forward<ElementType>(elt));
193 * Initialize the object.
194 * If the object was already initialized, it will be destroyed first.
196 * Arguments to ElementType's constructor.
198 * A pointer to the newly initialized object.
200 * The object is initialized.
202 template<typename... Args>
203 ElementType* construct(Args&&... args) {
205 new(object) ElementType(std::forward<Args>(args)...);
211 * Destroy the object, leaving the Tub in the same state
212 * as after the no-argument constructor.
213 * If the object was not initialized, this will have no effect.
215 * The object is uninitialized.
219 object->~ElementType();
225 const ElementType& operator*() const {
230 ElementType& operator*() {
235 const ElementType* operator->() const {
240 ElementType* operator->() {
245 * Return a pointer to the object.
247 * The object is initialized.
256 const ElementType* get() const {
263 * Return whether the object is initialized.
265 operator bool() const {
271 * A pointer to where the object is, if it is initialized.
272 * This must directly precede #raw in the struct.
274 ElementType object[0];
277 * A storage area to back the object while it is initialized.
279 char raw[sizeof(ElementType)];
282 * Whether the object is initialized.
287 #endif // CEPH_COMMON_TUB_H