VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/VirtualBoxBase.h@ 25624

Last change on this file since 25624 was 25371, checked in by vboxsync, 15 years ago

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.2 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Declarations of the BFE base classes
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#ifndef ____H_VIRTUALBOXBASEIMPL
24#define ____H_VIRTUALBOXBASEIMPL
25
26#ifdef VBOXBFE_WITHOUT_COM
27# include "COMDefs.h" // Our wrapper for COM definitions left in the code
28#else
29# include <VBox/com/defs.h>
30#endif
31
32#include <VBox/com/assert.h> // For the AssertComRC macro
33
34#include <iprt/alloc.h>
35#include <iprt/assert.h>
36#include <iprt/critsect.h>
37#include <iprt/string.h>
38#include <iprt/asm.h> // for ASMReturnAddress
39
40#include <list>
41#include <map>
42
43// macros and inlines
44////////////////////////////////////////////////////////////////////////////////
45
46/**
47 * A lightweight replacement for the COM setError function. I am
48 * assuming that this is only called in circumstances justifying
49 * an assertion.
50 *
51 * @returns error number
52 * @param iNum error number - this is simply returned
53 * @param pszFormat formatted error message
54 */
55static inline int setError(int iNum, const char *pszFormat, ...)
56{
57 va_list args;
58 va_start(args, pszFormat);
59 AssertMsgFailed((pszFormat, args));
60 va_end(args);
61 return iNum;
62}
63
64/**
65 * Translate an error string. We do not do translation.
66 */
67#define tr(a) a
68
69/**
70 * A special version of the Assert macro to be used within VirtualBoxBase
71 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
72 *
73 * In the debug build, this macro is equivalent to Assert.
74 * In the release build, this macro uses |setError (E_FAIL, ...)| to set the
75 * error info from the asserted expression.
76 *
77 * @see VirtualBoxSupportErrorInfoImpl::setError
78 *
79 * @param expr Expression which should be true.
80 */
81#if defined (DEBUG)
82#define ComAssert(expr) Assert (expr)
83#else
84#define ComAssert(expr) \
85 do { } while (0)
86#endif
87
88/**
89 * A special version of the AssertMsg macro to be used within VirtualBoxBase
90 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
91 *
92 * See ComAssert for more info.
93 *
94 * @param expr Expression which should be true.
95 * @param a printf argument list (in parenthesis).
96 */
97#if defined (DEBUG)
98#define ComAssertMsg(expr, a) AssertMsg (expr, a)
99#else
100#define ComAssertMsg(expr, a) \
101 do { } while (0)
102#endif
103
104/**
105 * A special version of the AssertRC macro to be used within VirtualBoxBase
106 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
107 *
108 * See ComAssert for more info.
109 *
110 * @param vrc VBox status code.
111 */
112#if defined (DEBUG)
113#define ComAssertRC(vrc) AssertRC (vrc)
114#else
115#define ComAssertRC(vrc) ComAssertMsgRC (vrc, ("%Rra", vrc))
116#endif
117
118/**
119 * A special version of the AssertMsgRC macro to be used within VirtualBoxBase
120 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
121 *
122 * See ComAssert for more info.
123 *
124 * @param vrc VBox status code.
125 * @param msg printf argument list (in parenthesis).
126 */
127#if defined (DEBUG)
128#define ComAssertMsgRC(vrc, msg) AssertMsgRC (vrc, msg)
129#else
130#define ComAssertMsgRC(vrc, msg) ComAssertMsg (RT_SUCCESS (vrc), msg)
131#endif
132
133
134/**
135 * A special version of the AssertFailed macro to be used within VirtualBoxBase
136 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
137 *
138 * See ComAssert for more info.
139 */
140#if defined (DEBUG)
141#define ComAssertFailed() AssertFailed()
142#else
143#define ComAssertFailed() \
144 do { } while (0)
145#endif
146
147/**
148 * A special version of the AssertMsgFailed macro to be used within VirtualBoxBase
149 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
150 *
151 * See ComAssert for more info.
152 *
153 * @param a printf argument list (in parenthesis).
154 */
155#if defined (DEBUG)
156#define ComAssertMsgFailed(a) AssertMsgFailed(a)
157#else
158#define ComAssertMsgFailed(a) \
159 do { } while (0)
160#endif
161
162/**
163 * A special version of the AssertComRC macro to be used within VirtualBoxBase
164 * subclasses that also inherit the VirtualBoxSupportErrorInfoImpl template.
165 *
166 * See ComAssert for more info.
167 *
168 * @param rc COM result code
169 */
170#if defined (DEBUG)
171#define ComAssertComRC(rc) AssertComRC (rc)
172#else
173#define ComAssertComRC(rc) ComAssertMsg (SUCCEEDED (rc), ("COM RC = 0x%08X\n", rc))
174#endif
175
176
177/** Special version of ComAssert that returns ret if expr fails */
178#define ComAssertRet(expr, ret) \
179 do { ComAssert (expr); if (!(expr)) return (ret); } while (0)
180/** Special version of ComAssertMsg that returns ret if expr fails */
181#define ComAssertMsgRet(expr, a, ret) \
182 do { ComAssertMsg (expr, a); if (!(expr)) return (ret); } while (0)
183/** Special version of ComAssertRC that returns ret if vrc does not succeed */
184#define ComAssertRCRet(vrc, ret) \
185 do { ComAssertRC (vrc); if (!RT_SUCCESS (vrc)) return (ret); } while (0)
186/** Special version of ComAssertMsgRC that returns ret if vrc does not succeed */
187#define ComAssertMsgRCRet(vrc, msg, ret) \
188 do { ComAssertMsgRC (vrc, msg); if (!RT_SUCCESS (vrc)) return (ret); } while (0)
189/** Special version of ComAssertFailed that returns ret */
190#define ComAssertFailedRet(ret) \
191 do { ComAssertFailed(); return (ret); } while (0)
192/** Special version of ComAssertMsgFailed that returns ret */
193#define ComAssertMsgFailedRet(msg, ret) \
194 do { ComAssertMsgFailed (msg); return (ret); } while (0)
195/** Special version of ComAssertComRC that returns ret if rc does not succeed */
196#define ComAssertComRCRet(rc, ret) \
197 do { ComAssertComRC (rc); if (!SUCCEEDED (rc)) return (ret); } while (0)
198
199
200/** Special version of ComAssert that evaulates eval and breaks if expr fails */
201#define ComAssertBreak(expr, eval) \
202 if (1) { ComAssert (expr); if (!(expr)) { eval; break; } } else do {} while (0)
203/** Special version of ComAssertMsg that evaulates eval and breaks if expr fails */
204#define ComAssertMsgBreak(expr, a, eval) \
205 if (1) { ComAssertMsg (expr, a); if (!(expr)) { eval; break; } } else do {} while (0)
206/** Special version of ComAssertRC that evaulates eval and breaks if vrc does not succeed */
207#define ComAssertRCBreak(vrc, eval) \
208 if (1) { ComAssertRC (vrc); if (!RT_SUCCESS (vrc)) { eval; break; } } else do {} while (0)
209/** Special version of ComAssertMsgRC that evaulates eval and breaks if vrc does not succeed */
210#define ComAssertMsgRCBreak(vrc, msg, eval) \
211 if (1) { ComAssertMsgRC (vrc, msg); if (!RT_SUCCESS (vrc)) { eval; break; } } else do {} while (0)
212/** Special version of ComAssertFailed that vaulates eval and breaks */
213#define ComAssertFailedBreak(eval) \
214 if (1) { ComAssertFailed(); { eval; break; } } else do {} while (0)
215/** Special version of ComAssertMsgFailed that vaulates eval and breaks */
216#define ComAssertMsgFailedBreak(msg, eval) \
217 if (1) { ComAssertMsgFailed (msg); { eval; break; } } else do {} while (0)
218/** Special version of ComAssertComRC that vaulates eval and breaks if rc does not succeed */
219#define ComAssertComRCBreak(rc, eval) \
220 if (1) { ComAssertComRC (rc); if (!SUCCEEDED (rc)) { eval; break; } } else do {} while (0)
221
222/**
223 * Checks whether this object is ready or not. Objects are typically ready
224 * after they are successfully created by their parent objects and become
225 * not ready when the respective parent itsef becomes not ready or gets
226 * destroyed while a reference to the child is still held by the caller
227 * (which prevents it from destruction).
228 *
229 * When this object is not ready, the macro sets error info and returns
230 * E_UNEXPECTED (the translatable error message is defined in null context).
231 * Otherwise, the macro does nothing.
232 *
233 * This macro <b>must</b> be used at the beginning of all interface methods
234 * (right after entering the class lock) in classes derived from both
235 * VirtualBoxBase and VirtualBoxSupportErrorInfoImpl.
236 */
237#define CHECK_READY() \
238 do { \
239 if (!isReady()) \
240 return setError (E_UNEXPECTED, tr ("The object is not ready")); \
241 } while (0)
242
243/**
244 * Declares an empty construtor and destructor for the given class.
245 * This is useful to prevent the compiler from generating the default
246 * ctor and dtor, which in turn allows to use forward class statements
247 * (instead of including their header files) when declaring data members of
248 * non-fundamental types with constructors (which are always called implicitly
249 * by constructors and by the destructor of the class).
250 *
251 * This macro is to be palced within (the public section of) the class
252 * declaration. Its counterpart, DEFINE_EMPTY_CTOR_DTOR, must be placed
253 * somewhere in one of the translation units (usually .cpp source files).
254 *
255 * @param cls class to declare a ctor and dtor for
256 */
257#define DECLARE_EMPTY_CTOR_DTOR(cls) cls(); ~cls();
258
259/**
260 * Defines an empty construtor and destructor for the given class.
261 * See DECLARE_EMPTY_CTOR_DTOR for more info.
262 */
263#define DEFINE_EMPTY_CTOR_DTOR(cls) \
264 cls::cls () {}; cls::~cls () {};
265
266////////////////////////////////////////////////////////////////////////////////
267
268namespace stdx
269{
270 /**
271 * A wrapper around the container that owns pointers it stores.
272 *
273 * @note
274 * Ownership is recognized only when destructing the container!
275 * Pointers are not deleted when erased using erase() etc.
276 *
277 * @param container
278 * class that meets Container requirements (for example, an instance of
279 * std::list<>, std::vector<> etc.). The given class must store
280 * pointers (for example, std::list <MyType *>).
281 */
282 template <typename container>
283 class ptr_container : public container
284 {
285 public:
286 ~ptr_container()
287 {
288 for (typename container::iterator it = container::begin();
289 it != container::end();
290 ++ it)
291 delete (*it);
292 }
293 };
294};
295
296////////////////////////////////////////////////////////////////////////////////
297
298class ATL_NO_VTABLE VirtualBoxBase
299{
300
301public:
302 VirtualBoxBase()
303 {
304 mReady = false;
305 RTCritSectInit(&mCritSec);
306 }
307 virtual ~VirtualBoxBase()
308 {
309 RTCritSectDelete(&mCritSec);
310 }
311
312 /**
313 * Virtual unintialization method. Called during parent object's
314 * uninitialization, if the given subclass instance is a dependent child of
315 * a class dervived from VirtualBoxBaseWithChildren (@sa
316 * VirtualBoxBaseWithChildren::addDependentChild). In this case, this
317 * method's impelemtation must call setReady (false),
318 */
319 virtual void uninit() {}
320
321 // lock the object
322 void lock()
323 {
324 RTCritSectEnter(&mCritSec);
325 }
326 // unlock the object
327 void unlock()
328 {
329 RTCritSectLeave(&mCritSec);
330 }
331
332 /** Returns true when the current thread owns this object's lock. */
333 bool isLockedOnCurrentThread()
334 {
335 return RTCritSectIsOwner (&mCritSec);
336 }
337
338 /**
339 * Helper class to make safe locking / unlocking.
340 * The constructor, given the VirtualBoxBase pointer, safely acquires the
341 * lock protecting its data. This lock will be released automatically
342 * when the instance goes out of scope (block, funciton etc.).
343 *
344 * @note
345 * An instance of this class must be declared as a local variable,
346 * otherwise the optimizer will most likely destruct it right after
347 * creation (but not at the end of the block), so the lock will be
348 * released immediately.
349 */
350 class AutoLock
351 {
352 public:
353
354 #if defined(RT_STRICT)
355 # define ___CritSectEnter(cs) RTCritSectEnterDebug((cs), (RTUINTPTR)ASMReturnAddress(), "return address >>>", 0, __PRETTY_FUNCTION__)
356 #else
357 # define ___CritSectEnter(cs) RTCritSectEnter((cs))
358 #endif
359
360 /** Internal lock handle */
361 class Handle
362 {
363 public:
364 Handle (RTCRITSECT &critSect) : lock (critSect) {}
365 private:
366 RTCRITSECT &lock;
367 friend class AutoLock;
368 };
369
370 AutoLock() : mLock (NULL), mLevel (0), mLeftLevel (0) {}
371
372 AutoLock (VirtualBoxBase *that)
373 : mLock (that ? &that->mCritSec : NULL)
374 , mLevel (0), mLeftLevel (0)
375 {
376 if (mLock)
377 {
378 ___CritSectEnter (mLock);
379 ++ mLevel;
380 }
381 }
382
383 AutoLock (RTCRITSECT &critSect)
384 : mLock (&critSect), mLevel (0), mLeftLevel (0)
385 {
386 if (mLock)
387 {
388 ___CritSectEnter (mLock);
389 ++ mLevel;
390 }
391 }
392
393 AutoLock (const Handle &handle)
394 : mLock (&handle.lock), mLevel (0), mLeftLevel (0)
395 {
396 if (mLock)
397 {
398 ___CritSectEnter (mLock);
399 ++ mLevel;
400 }
401 }
402
403 ~AutoLock()
404 {
405 if (mLock)
406 {
407 if (mLeftLevel)
408 {
409 mLeftLevel -= mLevel;
410 mLevel = 0;
411 for (; mLeftLevel; -- mLeftLevel)
412 RTCritSectEnter (mLock);
413 }
414 AssertMsg (mLevel <= 1, ("Lock level > 1: %d\n", mLevel));
415 for (; mLevel; -- mLevel)
416 RTCritSectLeave (mLock);
417 }
418 }
419
420 /**
421 * Tries to acquire the lock or increases the lock level
422 * if the lock is already owned by this thread.
423 */
424 void lock()
425 {
426 if (mLock)
427 {
428 AssertMsgReturn (mLeftLevel == 0, ("lock() after leave()\n"), (void) 0);
429 ___CritSectEnter (mLock);
430 ++ mLevel;
431 }
432 }
433
434 /**
435 * Decreases the lock level. If the level goes to zero, the lock
436 * is released by the current thread.
437 */
438 void unlock()
439 {
440 if (mLock)
441 {
442 AssertMsgReturn (mLevel > 0, ("Lock level is zero\n"), (void) 0);
443 AssertMsgReturn (mLeftLevel == 0, ("lock() after leave()\n"), (void) 0);
444 -- mLevel;
445 RTCritSectLeave (mLock);
446 }
447 }
448
449 /**
450 * Causes the current thread to completely release the lock
451 * (including locks acquired by all other instances of this class
452 * referring to the same object or handle). #enter() must be called
453 * to acquire the lock back and restore all lock levels.
454 */
455 void leave()
456 {
457 if (mLock)
458 {
459 AssertMsg (mLevel > 0, ("Lock level is zero\n"));
460 AssertMsgReturn (mLeftLevel == 0, ("leave() w/o enter()\n"), (void) 0);
461 mLeftLevel = RTCritSectGetRecursion (mLock);
462 for (uint32_t left = mLeftLevel; left; -- left)
463 RTCritSectLeave (mLock);
464 Assert (mLeftLevel >= mLevel);
465 }
466 }
467
468 /**
469 * Causes the current thread to acquire the lock again and restore
470 * all lock levels after calling #leave().
471 */
472 void enter()
473 {
474 if (mLock)
475 {
476 AssertMsg (mLevel > 0, ("Lock level is zero\n"));
477 AssertMsgReturn (mLeftLevel > 0, ("enter() w/o leave()\n"), (void) 0);
478 for (; mLeftLevel; -- mLeftLevel)
479 ___CritSectEnter (mLock);
480 }
481 }
482
483 uint32_t level() const { return mLevel; }
484
485 bool isNull() const { return mLock == NULL; }
486 bool operator !() const { return isNull(); }
487
488 bool belongsTo (VirtualBoxBase *that) const
489 {
490 return that && &that->mCritSec == mLock;
491 }
492
493 private:
494
495 AutoLock (const AutoLock &that); // disabled
496 AutoLock &operator = (const AutoLock &that); // disabled
497
498 RTCRITSECT *mLock;
499 uint32_t mLevel;
500 uint32_t mLeftLevel;
501
502 #undef ___CritSectEnter
503 };
504
505 // sets the ready state of the object
506 void setReady(bool isReady)
507 {
508 mReady = isReady;
509 }
510 // get the ready state of the object
511 bool isReady()
512 {
513 return mReady;
514 }
515
516 /**
517 * Translates the given text string according to the currently installed
518 * translation table and current context. The current context is determined
519 * by the context parameter. Additionally, a comment to the source text
520 * string text can be given. This comment (which is NULL by default)
521 * is helpful in sutuations where it is necessary to distinguish between
522 * two or more semantically different roles of the same source text in the
523 * same context.
524 *
525 * @param context the context of the the translation
526 * @param sourceText the string to translate
527 * @param comment the comment to the string (NULL means no comment)
528 *
529 * @return
530 * the translated version of the source string in UTF-8 encoding,
531 * or the source string itself if the translation is not found
532 * in the given context.
533 */
534 static const char *translate (const char *context, const char *sourceText,
535 const char *comment = 0);
536
537private:
538
539 // flag determining whether an object is ready
540 // for usage, i.e. methods may be called
541 bool mReady;
542 // mutex semaphore to lock the object
543 RTCRITSECT mCritSec;
544};
545
546////////////////////////////////////////////////////////////////////////////////
547
548/**
549 * Simple template that manages data structure allocation/deallocation
550 * and supports data pointer sharing (the instance that shares the pointer is
551 * not responsible for memory deallocation as opposed to the instance that
552 * owns it).
553 */
554template <class D>
555class Shareable
556{
557public:
558
559 Shareable() : mData (NULL), mIsShared (FALSE) {}
560 ~Shareable() { free(); }
561
562 void allocate() { attach (new D); }
563
564 virtual void free() {
565 if (mData) {
566 if (!mIsShared)
567 delete mData;
568 mData = NULL;
569 mIsShared = false;
570 }
571 }
572
573 void attach (D *data) {
574 AssertMsg (data, ("new data must not be NULL"));
575 if (data && mData != data) {
576 if (mData && !mIsShared)
577 delete mData;
578 mData = data;
579 mIsShared = false;
580 }
581 }
582
583 void attach (Shareable &data) {
584 AssertMsg (
585 data.mData == mData || !data.mIsShared,
586 ("new data must not be shared")
587 );
588 if (this != &data && !data.mIsShared) {
589 attach (data.mData);
590 data.mIsShared = true;
591 }
592 }
593
594 void share (D *data) {
595 AssertMsg (data, ("new data must not be NULL"));
596 if (mData != data) {
597 if (mData && !mIsShared)
598 delete mData;
599 mData = data;
600 mIsShared = true;
601 }
602 }
603
604 void share (const Shareable &data) { share (data.mData); }
605
606 void attachCopy (const D *data) {
607 AssertMsg (data, ("data to copy must not be NULL"));
608 if (data)
609 attach (new D (*data));
610 }
611
612 void attachCopy (const Shareable &data) {
613 attachCopy (data.mData);
614 }
615
616 virtual D *detach() {
617 D *d = mData;
618 mData = NULL;
619 mIsShared = false;
620 return d;
621 }
622
623 D *data() const {
624 return mData;
625 }
626
627 D *operator->() const {
628 AssertMsg (mData, ("data must not be NULL"));
629 return mData;
630 }
631
632 bool isNull() const { return mData == NULL; }
633 bool operator!() const { return isNull(); }
634
635 bool isShared() const { return mIsShared; }
636
637protected:
638
639 D *mData;
640 bool mIsShared;
641};
642
643/**
644 * Simple template that enhances Shareable<> and supports data
645 * backup/rollback/commit (using the copy constructor of the managed data
646 * structure).
647 */
648template <class D>
649class Backupable : public Shareable <D>
650{
651public:
652
653 Backupable() : Shareable <D> (), mBackupData (NULL) {}
654
655 void free()
656 {
657 AssertMsg (this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
658 rollback();
659 Shareable <D>::free();
660 }
661
662 D *detach()
663 {
664 AssertMsg (this->mData || !mBackupData, ("backup must be NULL if data is NULL"));
665 rollback();
666 return Shareable <D>::detach();
667 }
668
669 void share (const Backupable &data)
670 {
671 AssertMsg (!data.isBackedUp(), ("data to share must not be backed up"));
672 if (!data.isBackedUp())
673 Shareable <D>::share (data.mData);
674 }
675
676 /**
677 * Stores the current data pointer in the backup area, allocates new data
678 * using the copy constructor on current data and makes new data active.
679 */
680 void backup()
681 {
682 AssertMsg (this->mData, ("data must not be NULL"));
683 if (this->mData && !mBackupData)
684 {
685 mBackupData = this->mData;
686 this->mData = new D (*mBackupData);
687 }
688 }
689
690 /**
691 * Deletes new data created by #backup() and restores previous data pointer
692 * stored in the backup area, making it active again.
693 */
694 void rollback()
695 {
696 if (this->mData && mBackupData)
697 {
698 delete this->mData;
699 this->mData = mBackupData;
700 mBackupData = NULL;
701 }
702 }
703
704 /**
705 * Commits current changes by deleting backed up data and clearing up the
706 * backup area. The new data pointer created by #backup() remains active
707 * and becomes the only managed pointer.
708 *
709 * This method is much faster than #commitCopy() (just a single pointer
710 * assignment operation), but makes the previous data pointer invalid
711 * (because it is freed). For this reason, this method must not be
712 * used if it's possible that data managed by this instance is shared with
713 * some other Shareable instance. See #commitCopy().
714 */
715 void commit()
716 {
717 if (this->mData && mBackupData)
718 {
719 if (!this->mIsShared)
720 delete mBackupData;
721 mBackupData = NULL;
722 this->mIsShared = false;
723 }
724 }
725
726 /**
727 * Commits current changes by assigning new data to the previous data
728 * pointer stored in the backup area using the assignment operator.
729 * New data is deleted, the backup area is cleared and the previous data
730 * pointer becomes active and the only managed pointer.
731 *
732 * This method is slower than #commit(), but it keeps the previous data
733 * pointer valid (i.e. new data is copied to the same memory location).
734 * For that reason it's safe to use this method on instances that share
735 * managed data with other Shareable instances.
736 */
737 void commitCopy()
738 {
739 if (this->mData && mBackupData)
740 {
741 *mBackupData = *(this->mData);
742 delete this->mData;
743 this->mData = mBackupData;
744 mBackupData = NULL;
745 }
746 }
747
748 void assignCopy (const D *data)
749 {
750 AssertMsg (this->mData, ("data must not be NULL"));
751 AssertMsg (data, ("data to copy must not be NULL"));
752 if (this->mData && data)
753 {
754 if (!mBackupData)
755 {
756 mBackupData = this->mData;
757 this->mData = new D (*data);
758 }
759 else
760 *this->mData = *data;
761 }
762 }
763
764 void assignCopy (const Backupable &data)
765 {
766 assignCopy (data.mData);
767 }
768
769 bool isBackedUp() const
770 {
771 return mBackupData != NULL;
772 }
773
774 bool hasActualChanges() const
775 {
776 AssertMsg (this->mData, ("data must not be NULL"));
777 return this->mData != NULL && mBackupData != NULL &&
778 !(*this->mData == *mBackupData);
779 }
780
781 D *backedUpData() const
782 {
783 return mBackupData;
784 }
785
786protected:
787
788 D *mBackupData;
789};
790
791#endif // ____H_VIRTUALBOXBASEIMPL
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