Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / common / Tub.h
1 /* Copyright (c) 2010-2015 Stanford University
2  *
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.
6  *
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.
14  */
15
16 #ifndef CEPH_COMMON_TUB_H
17 #define CEPH_COMMON_TUB_H
18
19 /**
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).
27  *
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
33  *   never be used.
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
41  *   in a tub and do:
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).
46  *
47  * Tub is CopyConstructible if and only if ElementType is CopyConstructible,
48  * and Tub is Assignable if and only if ElementType is Assignable.
49  *
50  * \tparam ElementType
51  *      The type of the object to be stored within the Tub.
52  */
53 template<typename ElementType>
54 class Tub {
55  public:
56   /// The type of the object to be stored within the Tub.
57   typedef ElementType element_type;
58
59   /**
60          * Default constructor: the object starts off uninitialized.
61          */
62   Tub(): occupied(false) {}
63
64   /**
65          * Construct an occupied Tub, whose contained object is initialized
66          * with a copy of the given object.
67          * \pre
68          *      ElementType is CopyConstructible.
69          * \param other
70          *      Source of the copy.
71          */
72   Tub(const ElementType& other) // NOLINT
73           : occupied(false) {
74     construct(other);
75   }
76
77   /**
78          * Construct an occupied Tub, whose contained object is initialized
79          * with a move of the given object.
80          * \pre
81          *      ElementType is MoveConstructible.
82          * \param other
83          *      Source of the move.
84          */
85   Tub(ElementType&& other) // NOLINT
86           : occupied(false) {
87     construct(std::move(other));
88   }
89
90   /**
91          * Copy constructor.
92          * The object will be initialized if and only if the source of the copy is
93          * initialized.
94          * \pre
95          *      ElementType is CopyConstructible.
96          * \param other
97          *      Source of the copy.
98          */
99   Tub(const Tub<ElementType>& other) // NOLINT
100           : occupied(false) {
101     if (other.occupied) {
102       construct(*other.object); // use ElementType's copy constructor
103     }
104   }
105
106   /**
107          * Move constructor.
108          * The object will be initialized if and only if the source of the move is
109          * initialized.
110          * \pre
111          *      ElementType is MoveConstructible.
112          * \param other
113          *      Source of the move.
114          */
115   Tub(Tub<ElementType>&& other) // NOLINT
116           : occupied(false) {
117     if (other.occupied)
118       construct(std::move(*other.object)); // use ElementType's copy constructor
119   }
120
121   /**
122          * Destructor: destroy the object if it was initialized.
123          */
124   ~Tub() {
125     destroy();
126   }
127
128   /**
129          * Assignment: destroy current object if initialized, replace with
130          * source.  Result will be uninitialized if source is uninitialized.
131          * \pre
132          *      ElementType is Assignable.
133          */
134   Tub<ElementType>& operator=(const Tub<ElementType>& other) {
135     if (this != &other) {
136       if (other.occupied) {
137         if (occupied) {
138 #if __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
139           #pragma GCC diagnostic push
140 #pragma GCC diagnostic ignored "-Warray-bounds"
141 #endif
142           *object = *other.object; // use ElementType's assignment
143 #if __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
144 #pragma GCC diagnostic pop
145 #endif
146         } else {
147           construct(*other.object);
148         }
149       } else {
150         destroy();
151       }
152     }
153     return *this;
154   }
155
156   /**
157          * Assignment: destroy current object if initialized, replace with
158          * source.  Result will be uninitialized if source is uninitialized.
159          * \pre
160          *      ElementType is Assignable.
161          */
162   Tub<ElementType>& operator=(Tub<ElementType> &&other) {
163     if (this != &other) {
164       if (other.occupied) {
165         if (occupied)
166           *object = std::move(*other.object);
167         else
168           construct(std::move(*other.object));
169         other.destroy();
170       } else {
171         destroy();
172       }
173     }
174     return *this;
175   }
176
177   /**
178          * Assignment: destroy current object if initialized, replace with
179          * source.  Result will be uninitialized if source is uninitialized.
180          * \pre
181          *      ElementType is Assignable.
182          */
183   Tub<ElementType>& operator=(ElementType &&elt) {
184     if (occupied) {
185       *object = std::move(elt);
186     } else {
187       construct(std::forward<ElementType>(elt));
188     }
189     return *this;
190   }
191
192   /**
193          * Initialize the object.
194          * If the object was already initialized, it will be destroyed first.
195          * \param args
196          *      Arguments to ElementType's constructor.
197          * \return
198          *      A pointer to the newly initialized object.
199          * \post
200          *      The object is initialized.
201          */
202   template<typename... Args>
203   ElementType* construct(Args&&... args) {
204     destroy();
205     new(object) ElementType(std::forward<Args>(args)...);
206     occupied = true;
207     return object;
208   }
209
210   /**
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.
214          * \post
215          *      The object is uninitialized.
216          */
217   void destroy() {
218     if (occupied) {
219       object->~ElementType();
220       occupied = false;
221     }
222   }
223
224   /// See #get().
225   const ElementType& operator*() const {
226     return *get();
227   }
228
229   /// See #get().
230   ElementType& operator*() {
231     return *get();
232   }
233
234   /// See #get().
235   const ElementType* operator->() const {
236     return get();
237   }
238
239   /// See #get().
240   ElementType* operator->() {
241     return get();
242   }
243
244   /**
245          * Return a pointer to the object.
246          * \pre
247          *      The object is initialized.
248          */
249   ElementType* get() {
250     if (!occupied)
251       return NULL;
252     return object;
253   }
254
255   /// See #get().
256   const ElementType* get() const {
257     if (!occupied)
258       return NULL;
259     return object;
260   }
261
262   /**
263          * Return whether the object is initialized.
264          */
265   operator bool() const {
266     return occupied;
267   }
268
269  private:
270   /**
271          * A pointer to where the object is, if it is initialized.
272          * This must directly precede #raw in the struct.
273          */
274   ElementType object[0];
275
276   /**
277          * A storage area to back the object while it is initialized.
278          */
279   char raw[sizeof(ElementType)];
280
281   /**
282          * Whether the object is initialized.
283          */
284   bool occupied;
285 };
286
287 #endif  // CEPH_COMMON_TUB_H