1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sw=4 et tw=99 ft=cpp: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * the Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
25 : * Ms2ger <ms2ger@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /* Implementation of macros to ensure correct use of RAII Auto* objects. */
42 :
43 : #ifndef mozilla_GuardObjects_h
44 : #define mozilla_GuardObjects_h
45 :
46 : #include "mozilla/Assertions.h"
47 : #include "mozilla/Types.h"
48 :
49 : #ifdef __cplusplus
50 :
51 : #ifdef DEBUG
52 :
53 : namespace mozilla {
54 : namespace detail {
55 : /*
56 : * The following classes are designed to cause assertions to detect
57 : * inadvertent use of guard objects as temporaries. In other words,
58 : * when we have a guard object whose only purpose is its constructor and
59 : * destructor (and is never otherwise referenced), the intended use
60 : * might be:
61 : *
62 : * AutoRestore savePainting(mIsPainting);
63 : *
64 : * but is is easy to accidentally write:
65 : *
66 : * AutoRestore(mIsPainting);
67 : *
68 : * which compiles just fine, but runs the destructor well before the
69 : * intended time.
70 : *
71 : * They work by adding (#ifdef DEBUG) an additional parameter to the
72 : * guard object's constructor, with a default value, so that users of
73 : * the guard object's API do not need to do anything. The default value
74 : * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
75 : * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
76 : * guarantee that temporaries are destroyed in the reverse of their
77 : * construction order, but I actually can't find a statement that that
78 : * is true in the general case (beyond the two specific cases mentioned
79 : * there). However, it seems to be true.
80 : *
81 : * These classes are intended to be used only via the macros immediately
82 : * below them:
83 : *
84 : * MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member
85 : * variable, and should be put where a declaration of a private
86 : * member variable would be placed.
87 : * MOZ_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
88 : * parameters to each constructor of the guard object; it declares
89 : * (ifdef DEBUG) an additional parameter. (But use the *_ONLY_PARAM
90 : * variant for constructors that take no other parameters.)
91 : * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL should likewise be used in
92 : * the implementation of such constructors when they are not inline.
93 : * MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT should be used in
94 : * the implementation of such constructors to pass the parameter to
95 : * a base class that also uses these macros
96 : * MOZ_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
97 : * constructor. It uses the parameter declared by
98 : * MOZ_GUARD_OBJECT_NOTIFIER_PARAM.
99 : *
100 : * For more details, and examples of using these macros, see
101 : * https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla
102 : */
103 : class MOZ_EXPORT_API(GuardObjectNotifier)
104 : {
105 : private:
106 : bool* statementDone;
107 :
108 : public:
109 45388316 : GuardObjectNotifier() : statementDone(NULL) {}
110 :
111 45388114 : ~GuardObjectNotifier() {
112 45388114 : *statementDone = true;
113 45388114 : }
114 :
115 45388183 : void setStatementDone(bool* statementIsDone) {
116 45388183 : statementDone = statementIsDone;
117 45388183 : }
118 : };
119 :
120 : class MOZ_EXPORT_API(GuardObjectNotificationReceiver)
121 : {
122 : private:
123 : bool statementDone;
124 :
125 : public:
126 45388296 : GuardObjectNotificationReceiver() : statementDone(false) {}
127 :
128 45388169 : ~GuardObjectNotificationReceiver() {
129 : /*
130 : * Assert that the guard object was not used as a temporary.
131 : * (Note that this assert might also fire if init is not called
132 : * because the guard object's implementation is not using the
133 : * above macros correctly.)
134 : */
135 45388169 : MOZ_ASSERT(statementDone);
136 45388169 : }
137 :
138 45388192 : void init(const GuardObjectNotifier& constNotifier) {
139 : /*
140 : * constNotifier is passed as a const reference so that we can pass a
141 : * temporary, but we really intend it as non-const.
142 : */
143 45388192 : GuardObjectNotifier& notifier = const_cast<GuardObjectNotifier&>(constNotifier);
144 45388192 : notifier.setStatementDone(&statementDone);
145 45388109 : }
146 : };
147 :
148 : } /* namespace detail */
149 : } /* namespace mozilla */
150 :
151 : #endif /* DEBUG */
152 :
153 : #ifdef DEBUG
154 : # define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER \
155 : mozilla::detail::GuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
156 : # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM \
157 : , const mozilla::detail::GuardObjectNotifier& _notifier = \
158 : mozilla::detail::GuardObjectNotifier()
159 : # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM \
160 : const mozilla::detail::GuardObjectNotifier& _notifier = \
161 : mozilla::detail::GuardObjectNotifier()
162 : # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL \
163 : , const mozilla::detail::GuardObjectNotifier& _notifier
164 : # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT \
165 : , _notifier
166 : # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT \
167 : _notifier
168 : # define MOZ_GUARD_OBJECT_NOTIFIER_INIT \
169 : do { _mCheckNotUsedAsTemporary.init(_notifier); } while (0)
170 : #else
171 : # define MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
172 : # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM
173 : # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM
174 : # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL
175 : # define MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT
176 : # define MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT
177 : # define MOZ_GUARD_OBJECT_NOTIFIER_INIT do { } while (0)
178 : #endif
179 :
180 : #endif /* __cplusplus */
181 :
182 : #endif /* mozilla_GuardObjects_h */
|