File: cpputils.h

package info (click to toggle)
virtualbox-ose 1.6.6-dfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 91,740 kB
  • ctags: 207,046
  • sloc: ansic: 541,507; cpp: 462,042; asm: 22,594; sh: 8,644; makefile: 6,630; perl: 1,359; objc: 612; xml: 524; sed: 229; cs: 226; python: 34
file content (405 lines) | stat: -rw-r--r-- 12,468 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/** @file
 * IPRT - C++ Utilities (useful templates, defines and such).
 */

/*
 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 * additional information or have any questions.
 */

#ifndef ___iprt_cpputils_h
#define ___iprt_cpputils_h

#include <iprt/assert.h>

#include <memory>

/** @defgroup grp_rt_cpputils   C++ Utilities
 * @ingroup grp_rt
 * @{
 */

/**
 * Shortcut to |const_cast<C &>()| that automatically derives the correct
 * type (class) for the const_cast template's argument from its own argument.
 * Can be used to temporarily cancel the |const| modifier on the left-hand side
 * of assignment expressions, like this:
 * @code
 *      const Class that;
 *      ...
 *      unconst (that) = some_value;
 * @endcode
 */
template <class C>
inline C &unconst (const C &that) { return const_cast <C &> (that); }


/**
 * Shortcut to |const_cast<C *>()| that automatically derives the correct
 * type (class) for the const_cast template's argument from its own argument.
 * Can be used to temporarily cancel the |const| modifier on the left-hand side
 * of assignment expressions, like this:
 * @code
 *      const Class *that;
 *      ...
 *      unconst (that) = some_value;
 * @endcode
 */
template <class C>
inline C *unconst (const C *that) { return const_cast <C *> (that); }


/**
 * Extensions to the std namespace.
 */
namespace stdx
{

/* forward */
template <class> class auto_ref_ptr;

/**
 * Base class for objects willing to support smart reference counting using
 * the auto_ref_ptr template.
 *
 * When a class that wants to be used with the auto_ref_ptr template it simply
 * declares the auto_ref class among its public base classes -- there is no
 * need to implement any additional methods.
 */
class auto_ref
{
protected:

    auto_ref() : mRefs (0) {}

    /** Increases the reference counter and returns it */
    size_t ref() { return ++ mRefs; }

    /** Decreases the reference counter and returns it */
    size_t unref() { Assert (mRefs > 0); return -- mRefs; }

private:

    size_t mRefs;

    template <class> friend class auto_ref_ptr;
};

/**
 * The auto_ref_ptr template manages pointers to objects that support
 * reference counting by implementing auto_ref or a similar interface.
 *
 * Pointer management includes the following key points:
 *
 *   1) Automatic increment of the object's reference counter when the given
 *      auto_ref_ptr instance starts managing a pointer to this object.
 *
 *   2) Automatic decrement of the reference counter when the given
 *      auto_ref_ptr instance is destroyed, or before it is assigned a pointer
 *      to a new object.
 *
 *   3) Automatic deletion of the managed object whenever its reference
 *      counter reaches zero after a decrement.
 *
 *   4) Providing the dereference operator-> that gives direct access to the
 *      managed pointer.
 *
 * The object class to manage must provide ref() and unref() methods that have
 * the same syntax and symantics as defined in the auto_ref class.
 *
 * @param C     Class to manage.
 */
template <class C>
class auto_ref_ptr
{
public:

    /**
     * Creates a null instance that does not manage anything.
     */
    auto_ref_ptr() : m (NULL) {}

    /**
     * Creates an instance that starts managing the given pointer. The
     * reference counter of the object pointed to by @a a is incremented by
     * one.
     *
     * @param a Pointer to manage.
     */
    auto_ref_ptr (C* a) : m (a) { if (m) m->ref(); }

    /**
     * Creates an instance that starts managing a pointer managed by the given
     * instance. The reference counter of the object managed by @a that is
     * incremented by one.
     *
     * @param that Instance to take a pointer to manage from.
     */
    auto_ref_ptr (const auto_ref_ptr &that) : m (that.m) { if (m) m->ref(); }

    ~auto_ref_ptr() { do_unref(); }

    /**
     * Assigns the given pointer to this instance and starts managing it. The
     * reference counter of the object pointed to by @a a is incremented by
     * one. The reference counter of the object previously managed by this
     * instance is decremented by one.
     *
     * @param a Pointer to assign.
     */
    auto_ref_ptr &operator= (C *a) { do_reref (a); return *this; }

    /**
     * Assigns a pointer managed by the given instance to this instance and
     * starts managing it. The reference counter of the object managed by @a
     * that is incremented by one. The reference counter of the object
     * previously managed by this instance is decremented by one.
     *
     * @param that Instance which pointer to reference.
     */
    auto_ref_ptr &operator= (const auto_ref_ptr &that) { do_reref (that.m); return *this; }

    /**
     * Returns @c true if this instance is @c null and false otherwise.
     */
    bool is_null() const { return m == NULL; }

    /**
     * Dereferences the instance by returning the managed pointer.
     * Asserts that the managed pointer is not @c NULL.
     */
    C *operator-> () const { AssertMsg (m, ("Managed pointer is NULL!\n")); return m; }

    /**
     * Returns the managed pointer or @c NULL if this instance is @c null.
     */
    C *raw() const { return m; }

    /**
     * Compares this auto_ref_ptr instance with another instance and returns
     * @c true if both instances manage the same or @c NULL pointer.
     *
     * Note that this method compares pointer values only, it doesn't try to
     * compare objects themselves. Doing otherwise would a) break the common
     * 'pointer to something' comparison semantics auto_ref_ptr tries to
     * follow and b) require to define the comparison operator in the managed
     * class which is not always possible. You may analyze pointed objects
     * yourself if you need more precise comparison.
     *
     * @param that Instance to compare this instance with.
     */
    bool operator== (const auto_ref_ptr &that) const
    {
        return m == that.m;
    }

protected:

    void do_reref (C *a)
    {
        /* be aware of self assignment */
        if (a)
            a->ref();
        if (m)
        {
            size_t refs = m->unref();
            if (refs == 0)
            {
                refs = 1; /* stabilize */
                delete m;
            }
        }
        m = a;
    }

    void do_unref() { do_reref (NULL); }

    C *m;
};

/**
 * The exception_trap_base class is an abstract base class for all
 * exception_trap template instantiations.
 *
 * Pointer variables of this class are used to store a pointer any object of
 * any class instantiated from the exception_trap template, or in other words
 * to store a full copy of any exception wrapped into the exception_trap instance
 * allocated on the heap.
 *
 * See the exception_trap template for more info.
 */
class exception_trap_base
{
public:

    virtual void rethrow() = 0;
};

/**
 * The exception_trap template acts like a wrapper for the given exception
 * class that stores a full copy of the exception and therefore allows to
 * rethrow it preserving the actual type information about the exception
 * class.
 *
 * This functionality is useful in situations where it is necessary to catch a
 * (known) number of exception classes and pass the caught exception instance
 * to an upper level using a regular variable (rather than the exception
 * unwinding mechanism itself) *and* preserve all information about the type
 * (class) of the caight exception so that it may be rethrown on the upper
 * level unchanged.
 *
 * Usage pattern:
 * @code
    using namespace std;
    using namespace stdx;

    auto_ptr <exception_trap_base> trapped;

    int callback();

    int safe_callback()
    {
      try
      {
        // callback may throw a set of exceptions but we don't want it to start
        // unwinding the stack right now

        return callback();
      }
      catch (const MyException &err) { trapped = new_exception_trap (err); }
      catch (const MyException2 &err) { trapped = new_exception_trap (err); }
      catch (...) { trapped = new_exception_trap (logic_error()); }

      return -1;
    }

    void bar()
    {
      // call a funciton from some C library that supports callbacks but knows
      // nothing about exceptions so throwing one from a callback will leave
      // the library in an undetermined state

      do_something_with_callback (safe_callback());

      // check if we have got an exeption from callback() and rethrow it now
      // when we are not in the C library any more
      if (trapped.get() != NULL)
        trapped->rethrow();
    }
 * @endcode
 *
 * @param T Exception class to wrap.
 */
template <typename T>
class exception_trap : public exception_trap_base
{
public:

    exception_trap (const T &aTrapped) : trapped (aTrapped) {}
    void rethrow() { throw trapped; }

    T trapped;
};

/**
 * Convenience function that allocates a new exception_trap instance on the
 * heap by automatically deducing the exception_trap template argument from
 * the type of the exception passed in @a aTrapped.
 *
 * The following two lines of code inside the catch block are equivalent:
 *
 * @code
    using namespace std;
    using namespace stdx;
    catch (const MyException &err)
    {
      auto_ptr <exception_trap_base> t1 = new exception_trap <MyException> (err);
      auto_ptr <exception_trap_base> t2 = new_exception_trap (err);
    }
 * @endcode
 *
 * @param aTrapped Exception to put to the allocated trap.
 *
 * @return Allocated exception_trap object.
 */
template <typename T>
static exception_trap <T> *
new_exception_trap (const T &aTrapped)
{
    return new exception_trap <T> (aTrapped);
}

/**
 * Enhancement of std::auto_ptr @<char@> intended to take pointers to char
 * buffers allocated using new[].
 *
 * This differs from std::auto_ptr @<char@> so that it overloads some methods to
 * uses delete[] instead of delete to delete the owned data in order to
 * conform to the C++ standard (and avoid valgrind complaints).
 *
 * Note that you should not use instances of this class where pointers or
 * references to objects of std::auto_ptr @<char@> are expeced. Despite the fact
 * the classes are related, the base is not polymorphic (in particular,
 * neither the destructor nor the reset() method are virtual). It means that when
 * acessing instances of this class through the base pointer, overloaded
 * methods won't be called.
 */
class char_auto_ptr : public std::auto_ptr <char>
{
public:

    explicit char_auto_ptr (char *a = 0) throw()
        : std::auto_ptr <char> (a) {}

    /* Note: we use unconst brute force below because the non-const version
     * of the copy constructor won't accept temporary const objects
     * (e.g. function return values) in GCC. std::auto_ptr has the same
     * "problem" but it seems overcome it using #pragma GCC system_header
     * which doesn't work here. */
    char_auto_ptr (const char_auto_ptr &that) throw()
        : std::auto_ptr <char> (unconst (that).release()) {}

    ~char_auto_ptr() { delete[] (release()); }

    char_auto_ptr &operator= (char_auto_ptr &that) throw()
    {
        std::auto_ptr <char>::operator= (that);
        return *this;
    }

    void reset (char *a) throw()
    {
        if (a != get())
        {
            delete[] (release());
            std::auto_ptr <char>::reset (a);
        }
    }
};

} /* namespace stdx */

/** @} */

#endif