VirtualBox

source: vbox/trunk/include/iprt/cpputils.h@ 6175

Last change on this file since 6175 was 6170, checked in by vboxsync, 17 years ago

IPRT/cpputils: Wording.

  • Property svn:eol-style set to native
File size: 12.0 KB
Line 
1/** @file
2 * innotek Portable Runtime - C++ Utilities (useful templates, defines and such).
3 */
4
5/*
6 * Copyright (C) 2006-2007 innotek GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef ___iprt_cpputils_h
27#define ___iprt_cpputils_h
28
29#include <iprt/assert.h>
30
31#include <memory>
32
33/** @defgroup grp_rt_cpputils C++ Utilities
34 * @ingroup grp_rt
35 * @{
36 */
37
38/**
39 * Shortcut to |const_cast<C &>()| that automatically derives the correct
40 * type (class) for the const_cast template's argument from its own argument.
41 * Can be used to temporarily cancel the |const| modifier on the left-hand side
42 * of assignment expressions, like this:
43 * @code
44 * const Class that;
45 * ...
46 * unconst (that) = some_value;
47 * @endcode
48 */
49template <class C>
50inline C &unconst (const C &that) { return const_cast <C &> (that); }
51
52
53/**
54 * Shortcut to |const_cast<C *>()| that automatically derives the correct
55 * type (class) for the const_cast template's argument from its own argument.
56 * Can be used to temporarily cancel the |const| modifier on the left-hand side
57 * of assignment expressions, like this:
58 * @code
59 * const Class *that;
60 * ...
61 * unconst (that) = some_value;
62 * @endcode
63 */
64template <class C>
65inline C *unconst (const C *that) { return const_cast <C *> (that); }
66
67
68/**
69 * Extensions to the std namespace.
70 */
71namespace stdx
72{
73
74/* forward */
75template <class> class auto_ref_ptr;
76
77/**
78 * Base class for objects willing to support smart reference counting using
79 * the auto_ref_ptr template.
80 *
81 * When a class that wants to be used with the auto_ref_ptr template it simply
82 * declares the auto_ref class among its public base classes -- there is no
83 * need to implement any additional methods.
84 */
85class auto_ref
86{
87protected:
88
89 auto_ref() : mRefs (0) {}
90
91 /** Increases the reference counter and returns it */
92 size_t ref() { return ++ mRefs; }
93
94 /** Decreases the reference counter and returns it */
95 size_t unref() { Assert (mRefs > 0); return -- mRefs; }
96
97private:
98
99 size_t mRefs;
100
101 template <class> friend class auto_ref_ptr;
102};
103
104/**
105 * The auto_ref_ptr template manages pointers to objects that support
106 * reference counting by implementing auto_ref or a similar interface.
107 *
108 * Pointer management includes the following key points:
109 *
110 * 1) Automatic increment of the object's reference counter when the given
111 * auto_ref_ptr instance starts managing a pointer to this object.
112 *
113 * 2) Automatic decrement of the reference counter when the given
114 * auto_ref_ptr instance is destroyed, or before it is assigned a pointer
115 * to a new object.
116 *
117 * 3) Automatic deletion of the managed object whenever its reference
118 * counter reaches zero after a decrement.
119 *
120 * 4) Providing the dereference operator-> that gives direct access to the
121 * managed pointer.
122 *
123 * The object class to manage must provide ref() and unref() methods that have
124 * the same syntax and symantics as defined in the auto_ref class.
125 *
126 * @param C Class to manage.
127 */
128template <class C>
129class auto_ref_ptr
130{
131public:
132
133 /**
134 * Creates a null instance that does not manage anything.
135 */
136 auto_ref_ptr() : m (NULL) {}
137
138 /**
139 * Creates an instance that starts managing the given pointer. The
140 * reference counter of the object pointed to by @a a is incremented by
141 * one.
142 *
143 * @param a Pointer to manage.
144 */
145 auto_ref_ptr (C* a) : m (a) { if (m) m->ref(); }
146
147 /**
148 * Creates an instance that starts managing a pointer managed by the given
149 * instance. The reference counter of the object managed by @a that is
150 * incremented by one.
151 *
152 * @param that Instance to take a pointer to manage from.
153 */
154 auto_ref_ptr (const auto_ref_ptr &that) : m (that.m) { if (m) m->ref(); }
155
156 ~auto_ref_ptr() { do_unref(); }
157
158 /**
159 * Assigns the given pointer to this instance and starts managing it. The
160 * reference counter of the object pointed to by @a a is incremented by
161 * one. The reference counter of the object previously managed by this
162 * instance is decremented by one.
163 *
164 * @param a Pointer to assign.
165 */
166 auto_ref_ptr &operator= (C *a) { do_reref (a); return *this; }
167
168 /**
169 * Assigns a pointer managed by the given instance to this instance and
170 * starts managing it. The reference counter of the object managed by @a
171 * that is incremented by one. The reference counter of the object
172 * previously managed by this instance is decremented by one.
173 *
174 * @param a Pointer to assign.
175 */
176 auto_ref_ptr &operator= (const auto_ref_ptr &that) { do_reref (that.m); return *this; }
177
178 /**
179 * Returns @c true if this instance is @c null and false otherwise.
180 */
181 bool is_null() const { return m == NULL; }
182
183 /**
184 * Dereferences the instance by returning the managed pointer.
185 * Asserts that the managed pointer is not @c NULL.
186 */
187 C *operator-> () const { AssertMsg (m, ("Managed pointer is NULL!\n")); return m; }
188
189 /**
190 * Returns the managed pointer or @c NULL if this instance is @c null.
191 */
192 C *raw() const { return m; }
193
194 /**
195 * Compares this auto_ref_ptr instance with another instance and returns
196 * @c true if both instances manage the same or @c NULL pointer.
197 *
198 * Note that this method compares pointer values only, it doesn't try to
199 * compare objects themselves. Doing otherwise would a) break the common
200 * 'pointer to something' comparison semantics auto_ref_ptr tries to
201 * follow and b) require to define the comparison operator in the managed
202 * class which is not always possible. You may analyze pointed objects
203 * yourself if you need more precise comparison.
204 *
205 * @param that Instance to compare this instance with.
206 */
207 bool operator== (const auto_ref_ptr &that) const
208 {
209 return m == that.m;
210 }
211
212protected:
213
214 void do_reref (C *a)
215 {
216 /* be aware of self assignment */
217 if (a)
218 a->ref();
219 if (m)
220 {
221 size_t refs = m->unref();
222 if (refs == 0)
223 {
224 refs = 1; /* stabilize */
225 delete m;
226 }
227 }
228 m = a;
229 }
230
231 void do_unref() { do_reref (NULL); }
232
233 C *m;
234};
235
236/**
237 * The exception_trap_base class is an abstract base class for all
238 * exception_trap template instantiations.
239 *
240 * Pointer variables of this class are used to store a pointer any object of
241 * any class instantiated from the exception_trap template, or in other words
242 * to store a full copy of any exception wrapped into the exception_trap instance
243 * allocated on the heap.
244 *
245 * See the exception_trap template for more info.
246 */
247class exception_trap_base
248{
249public:
250
251 virtual void rethrow() = 0;
252};
253
254/**
255 * The exception_trap template acts like a wrapper for the given exception
256 * class that stores a full copy of the exception and therefore allows to
257 * rethrow it preserving the actual type information about the exception
258 * class.
259 *
260 * This functionality is useful in situations where it is necessary to catch a
261 * (known) number of exception classes and pass the caught exception instance
262 * to an upper level using a regular variable (rather than the exception
263 * unwinding mechanism itself) *and* preserve all information about the type
264 * (class) of the caight exception so that it may be rethrown on the upper
265 * level unchanged.
266 *
267 * Usage pattern:
268 * @code
269 using namespace std;
270 using namespace stdx;
271
272 auto_ptr <exception_trap_base> trapped;
273
274 int callback();
275
276 int safe_callback()
277 {
278 try
279 {
280 // callback may throw a set of exceptions but we don't want it to start
281 // unwinding the stack right now
282
283 return callback();
284 }
285 catch (const MyException &err) { trapped = new_exception_trap (err); }
286 catch (const MyException2 &err) { trapped = new_exception_trap (err); }
287 catch (...) { trapped = new_exception_trap (logic_error()); }
288
289 return -1;
290 }
291
292 void bar()
293 {
294 // call a funciton from some C library that supports callbacks but knows
295 // nothing about exceptions so throwing one from a callback will leave
296 // the library in an undetermined state
297
298 do_something_with_callback (safe_callback());
299
300 // check if we have got an exeption from callback() and rethrow it now
301 // when we are not in the C library any more
302 if (trapped.get() != NULL)
303 trapped->rethrow();
304 }
305 * @endcode
306 *
307 * @param T Exception class to wrap.
308 */
309template <typename T>
310class exception_trap : public exception_trap_base
311{
312public:
313
314 exception_trap (const T &aTrapped) : trapped (aTrapped) {}
315 void rethrow() { throw trapped; }
316
317 T trapped;
318};
319
320/**
321 * Convenience function that allocates a new exception_trap instance on the
322 * heap by automatically deducing the exception_trap template argument from
323 * the type of the exception passed in @a aTrapped.
324 *
325 * The following two lines of code inside the catch block are equivalent:
326 *
327 * @code
328 using namespace std;
329 using namespace stdx;
330 catch (const MyException &err)
331 {
332 auto_ptr <exception_trap_base> t1 = new exception_trap <MyException> (err);
333 auto_ptr <exception_trap_base> t2 = new_exception_trap (err);
334 }
335 * @endcode
336 *
337 * @param aTrapped Exception to put to the allocated trap.
338 *
339 * @return Allocated exception_trap object.
340 */
341template <typename T>
342static exception_trap <T> *
343new_exception_trap (const T &aTrapped)
344{
345 return new exception_trap <T> (aTrapped);
346}
347
348/**
349 * Enhancement of std::auto_ptr <char> intended to take pointers to char
350 * buffers allocated using new[].
351 *
352 * This differs from std::auto_ptr <char> so that it overloads some methods to
353 * uses delete[] instead of delete to delete the owned data in order to
354 * conform to the C++ standard (and avoid valgrind complaints).
355 *
356 * Note that you should not use instances of this class where pointers or
357 * references to objects of std::auto_ptr <char> are expeced. Despite the fact
358 * the classes are related, the base is not polymorphic (in particular,
359 * neither the destructor nor the reset() method are virtual). It means that when
360 * acessing instances of this class through the base pointer, overloaded
361 * methods won't be called.
362 */
363class char_auto_ptr : public std::auto_ptr <char>
364{
365public:
366
367 explicit char_auto_ptr (char *a = 0) throw()
368 : std::auto_ptr <char> (a) {}
369
370 /* Note: we use unconst brute force below because the non-const version
371 * of the copy constructor won't accept temporary const objects
372 * (e.g. function return values) in GCC. std::auto_ptr has the same
373 * "problem" but it seems overcome it using #pragma GCC system_header
374 * which doesn't work here. */
375 char_auto_ptr (const char_auto_ptr &that) throw()
376 : std::auto_ptr <char> (unconst (that).release()) {}
377
378 ~char_auto_ptr() { delete[] (release()); }
379
380 char_auto_ptr &operator= (char_auto_ptr &that) throw()
381 {
382 std::auto_ptr <char>::operator= (that);
383 return *this;
384 }
385
386 void reset (char *a) throw()
387 {
388 if (a != get())
389 {
390 delete[] (release());
391 std::auto_ptr <char>::reset (a);
392 }
393 }
394};
395
396} /* namespace stdx */
397
398/** @} */
399
400#endif
401
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette