E-MailRelay

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