]>
git.proxmox.com Git - ceph.git/blob - ceph/src/common/Tub.h
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