E-MailRelay
gcall.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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
26namespace 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/// do_some_stuff() ;
51/// emit( "doing stuff" ) ; // call client code - can do anything
52/// if( this_.deleted() ) return ; // just in case
53/// do_more_stuff() ;
54/// }
55/// } ;
56/// \endcode
57///
59{
60public:
61 CallStack() noexcept ;
62 ///< Constructor.
63
64 ~CallStack() noexcept ;
65 ///< Destructor. Calls invalidate() on all the frames in the stack.
66
67 CallFrame * push( CallFrame * ) noexcept ;
68 ///< Pushes a new innermost call frame onto the stack.
69
70 void pop( CallFrame * ) noexcept ;
71 ///< Makes the given frame the innermost.
72
73public:
74 CallStack( const CallStack & ) = delete ;
75 CallStack( CallStack && ) = delete ;
76 CallStack & operator=( const CallStack & ) = delete ;
77 CallStack & operator=( CallStack && ) = delete ;
78
79private:
80 CallFrame * m_inner{nullptr} ;
81} ;
82
83//| \class G::CallFrame
84/// An object to represent a nested execution context.
85/// \see G::CallStack
86///
88{
89public:
90 explicit CallFrame( CallStack & ) noexcept ;
91 ///< Constructor. The newly constructed call frame becomes
92 ///< the innermost frame in the stack.
93
94 ~CallFrame() noexcept ;
95 ///< Destructor.
96
97 void invalidate() noexcept ;
98 ///< Invalidates the call-frame.
99
100 bool valid() const noexcept ;
101 ///< Returns true if not invalidate()d. This is safe to call
102 ///< even if the call stack has been destructed.
103
104 bool deleted() const noexcept ;
105 ///< Returns !valid().
106
107 CallFrame * outer() noexcept ;
108 ///< Returns the next frame in the stack going from innermost
109 ///< to outermost.
110
111public:
112 CallFrame( const CallFrame & ) = delete ;
113 CallFrame( CallFrame && ) = delete ;
114 CallFrame & operator=( const CallFrame & ) = delete ;
115 CallFrame & operator=( CallFrame && ) = delete ;
116
117private:
118 CallStack & m_stack ;
119 bool m_valid ;
120 CallFrame * m_outer ;
121} ;
122
123// ==
124
125inline
127= default;
128
129inline
130G::CallStack::~CallStack() noexcept
131{
132 for( CallFrame * p = m_inner ; p ; p = p->outer() )
133 p->invalidate() ;
134}
135
136inline
138{
139 CallFrame * old = m_inner ;
140 m_inner = p ;
141 return old ;
142}
143
144inline
145void G::CallStack::pop( CallFrame * p ) noexcept
146{
147 m_inner = p ;
148}
149
150// ==
151
152inline
154 m_stack(stack) ,
155 m_valid(true)
156{
157 m_outer = m_stack.push( this ) ;
158}
159
160inline
162{
163 if( m_valid )
164 m_stack.pop( m_outer ) ;
165}
166
167inline
169{
170 m_valid = false ;
171}
172
173inline
174bool G::CallFrame::valid() const noexcept
175{
176 return m_valid ;
177}
178
179inline
180bool G::CallFrame::deleted() const noexcept
181{
182 return !m_valid ;
183}
184
185inline
187{
188 return m_outer ;
189}
190
191#endif
An object to represent a nested execution context.
Definition: gcall.h:88
bool valid() const noexcept
Returns true if not invalidate()d.
Definition: gcall.h:174
bool deleted() const noexcept
Returns !valid().
Definition: gcall.h:180
~CallFrame() noexcept
Destructor.
Definition: gcall.h:161
void invalidate() noexcept
Invalidates the call-frame.
Definition: gcall.h:168
CallFrame(CallStack &) noexcept
Constructor.
Definition: gcall.h:153
CallFrame * outer() noexcept
Returns the next frame in the stack going from innermost to outermost.
Definition: gcall.h:186
A linked list of CallFrame pointers.
Definition: gcall.h:59
CallStack() noexcept
Constructor.
CallFrame * push(CallFrame *) noexcept
Pushes a new innermost call frame onto the stack.
Definition: gcall.h:137
void pop(CallFrame *) noexcept
Makes the given frame the innermost.
Definition: gcall.h:145
Low-level classes.
Definition: garg.h:30