E-MailRelay

gcall.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gcall.h
19///
20
21#ifndef G_CALL_H
22#define G_CALL_H
23
24#include "gdef.h"
25
26 namespace G
27{
28 class CallStack ;
29 class CallFrame ;
30}
31
32//| \class G::CallStack
33/// A linked list of CallFrame pointers.
34///
35/// The motivation is the situation where an object, typically
36/// instantiated on the heap, emits some sort of synchronous
37/// signal, event, or callback and the receiving code somehow
38/// ends up deleting the originating object. If the emitting
39/// object might do more work before the stack unwinds then it
40/// can protect itself with a CallFrame check, with almost zero
41/// run-time cost:
42///
43/// \code
44/// class Emitter
45/// {
46/// CallStack m_stack ;
47/// void do_stuff()
48/// {
49/// CallFrame this_( m_stack ) ;
50/// emit( "doing stuff" ) ; // call client code - can do anything
51/// if( this_.deleted() ) return ; // just in case
52/// do_more_stuff() ;
53/// }
54/// } ;
55/// \endcode
56///
57 class G::CallStack
58{
59 public:
60 CallStack() noexcept ;
61 ///< Constructor.
62
63 ~CallStack() noexcept ;
64 ///< Destructor. Calls invalidate() on all the frames in the stack.
65
66 CallFrame * push( CallFrame * ) noexcept ;
67 ///< Pushes a new innermost call frame onto the stack.
68
69 void pop( CallFrame * ) noexcept ;
70 ///< Makes the given frame the innermost.
71
72public:
73 CallStack( const CallStack & ) = delete ;
74 CallStack( CallStack && ) = delete ;
75 void operator=( const CallStack & ) = delete ;
76 void operator=( CallStack && ) = delete ;
77
78private:
79 CallFrame * m_inner{nullptr} ;
80} ;
81
82//| \class G::CallFrame
83/// An object to represent a nested execution context.
84/// \see G::CallStack
85///
86 class G::CallFrame
87{
88 public:
89 explicit CallFrame( CallStack & ) noexcept ;
90 ///< Constructor. The newly constructed call frame becomes
91 ///< the innermost frame in the stack.
92
93 ~CallFrame() noexcept ;
94 ///< Destructor.
95
96 void invalidate() noexcept ;
97 ///< Invalidates the call-frame.
98
99 bool valid() const noexcept ;
100 ///< Returns true if not invalidate()d. This is safe to call
101 ///< even if the call stack has been destructed.
102
103 bool deleted() const noexcept ;
104 ///< Returns !valid().
105
106 CallFrame * outer() noexcept ;
107 ///< Returns the next frame in the stack going from innermost
108 ///< to outermost.
109
110 public:
111 CallFrame( const CallFrame & ) = delete ;
112 CallFrame( CallFrame && ) = delete ;
113 void operator=( const CallFrame & ) = delete ;
114 void operator=( CallFrame && ) = delete ;
115
116 private:
117 CallStack & m_stack ;
118 bool m_valid ;
119 CallFrame * m_outer ;
120} ;
121
122// ==
123
124 inline
125 G::CallStack::CallStack() noexcept
126= default;
127
128inline
129 G::CallStack::~CallStack() noexcept
130{
131 for( CallFrame * p = m_inner ; p ; p = p->outer() )
132 p->invalidate() ;
133}
134
135 inline
136 G::CallFrame * G::CallStack::push( CallFrame * p ) noexcept
137{
138 CallFrame * old = m_inner ;
139 m_inner = p ;
140 return old ;
141}
142
143 inline
144 void G::CallStack::pop( CallFrame * p ) noexcept
145{
146 m_inner = p ;
147}
148
149// ==
150
151 inline
152 G::CallFrame::CallFrame( CallStack & stack ) noexcept :
153 m_stack(stack) ,
154 m_valid(true)
155{
156 m_outer = m_stack.push( this ) ;
157}
158
159 inline
160 G::CallFrame::~CallFrame() noexcept
161{
162 if( m_valid )
163 m_stack.pop( m_outer ) ;
164}
165
166 inline
167 void G::CallFrame::invalidate() noexcept
168{
169 m_valid = false ;
170}
171
172 inline
173 bool G::CallFrame::valid() const noexcept
174{
175 return m_valid ;
176}
177
178 inline
179 bool G::CallFrame::deleted() const noexcept
180{
181 return !m_valid ;
182}
183
184 inline
185 G::CallFrame * G::CallFrame::outer() noexcept
186{
187 return m_outer ;
188}
189
190#endif
G::CallFrame
An object to represent a nested execution context.
Definition: gcall.h:87
G::CallFrame::valid
bool valid() const noexcept
Returns true if not invalidate()d.
Definition: gcall.h:173
G::CallFrame::deleted
bool deleted() const noexcept
Returns !valid().
Definition: gcall.h:179
G::CallFrame::~CallFrame
~CallFrame() noexcept
Destructor.
Definition: gcall.h:160
G::CallFrame::invalidate
void invalidate() noexcept
Invalidates the call-frame.
Definition: gcall.h:167
G::CallFrame::CallFrame
CallFrame(CallStack &) noexcept
Constructor.
Definition: gcall.h:152
G::CallFrame::outer
CallFrame * outer() noexcept
Returns the next frame in the stack going from innermost to outermost.
Definition: gcall.h:185
G::CallStack
A linked list of CallFrame pointers.
Definition: gcall.h:58
G::CallStack::CallStack
CallStack() noexcept
Constructor.
G::CallStack::push
CallFrame * push(CallFrame *) noexcept
Pushes a new innermost call frame onto the stack.
Definition: gcall.h:136
G::CallStack::pop
void pop(CallFrame *) noexcept
Makes the given frame the innermost.
Definition: gcall.h:144
G
Low-level classes.
Definition: galign.h:28