xref: /netbsd-src/external/gpl3/gdb.old/dist/gdbsupport/forward-scope-exit.h (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1*6881a400Schristos /* Copyright (C) 2019-2023 Free Software Foundation, Inc.
27d62b00eSchristos 
37d62b00eSchristos    This file is part of GDB.
47d62b00eSchristos 
57d62b00eSchristos    This program is free software; you can redistribute it and/or modify
67d62b00eSchristos    it under the terms of the GNU General Public License as published by
77d62b00eSchristos    the Free Software Foundation; either version 3 of the License, or
87d62b00eSchristos    (at your option) any later version.
97d62b00eSchristos 
107d62b00eSchristos    This program is distributed in the hope that it will be useful,
117d62b00eSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
127d62b00eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
137d62b00eSchristos    GNU General Public License for more details.
147d62b00eSchristos 
157d62b00eSchristos    You should have received a copy of the GNU General Public License
167d62b00eSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
177d62b00eSchristos 
187d62b00eSchristos #ifndef COMMON_FORWARD_SCOPE_EXIT_H
197d62b00eSchristos #define COMMON_FORWARD_SCOPE_EXIT_H
207d62b00eSchristos 
217d62b00eSchristos #include "gdbsupport/scope-exit.h"
227d62b00eSchristos #include <functional>
237d62b00eSchristos 
247d62b00eSchristos /* A forward_scope_exit is like scope_exit, but instead of giving it a
257d62b00eSchristos    callable, you instead specialize it for a given cleanup function,
267d62b00eSchristos    and the generated class automatically has a constructor with the
277d62b00eSchristos    same interface as the cleanup function.  forward_scope_exit
287d62b00eSchristos    captures the arguments passed to the ctor, and in turn passes those
297d62b00eSchristos    as arguments to the wrapped cleanup function, when it is called at
307d62b00eSchristos    scope exit time, from within the forward_scope_exit dtor.  The
317d62b00eSchristos    forward_scope_exit class can take any number of arguments, and is
327d62b00eSchristos    cancelable if needed.
337d62b00eSchristos 
347d62b00eSchristos    This allows usage like this:
357d62b00eSchristos 
367d62b00eSchristos       void
377d62b00eSchristos       delete_longjmp_breakpoint (int arg)
387d62b00eSchristos       {
397d62b00eSchristos 	// Blah, blah, blah...
407d62b00eSchristos       }
417d62b00eSchristos 
427d62b00eSchristos       using longjmp_breakpoint_cleanup
437d62b00eSchristos 	= FORWARD_SCOPE_EXIT (delete_longjmp_breakpoint);
447d62b00eSchristos 
457d62b00eSchristos    This above created a new cleanup class `longjmp_breakpoint_cleanup`
467d62b00eSchristos    than can then be used like this:
477d62b00eSchristos 
487d62b00eSchristos       longjmp_breakpoint_cleanup obj (thread);
497d62b00eSchristos 
507d62b00eSchristos       // Blah, blah, blah...
517d62b00eSchristos 
527d62b00eSchristos       obj.release ();  // Optional cancel if needed.
537d62b00eSchristos 
547d62b00eSchristos    forward_scope_exit is also handy when you would need to wrap a
557d62b00eSchristos    scope_exit in a gdb::optional:
567d62b00eSchristos 
577d62b00eSchristos       gdb::optional<longjmp_breakpoint_cleanup> cleanup;
587d62b00eSchristos       if (some condition)
597d62b00eSchristos 	cleanup.emplace (thread);
607d62b00eSchristos       ...
617d62b00eSchristos       if (cleanup)
627d62b00eSchristos 	cleanup->release ();
637d62b00eSchristos 
647d62b00eSchristos    since with scope exit, you would have to know the scope_exit's
657d62b00eSchristos    callable template type when you create the gdb::optional:
667d62b00eSchristos 
677d62b00eSchristos      gdb:optional<scope_exit<what goes here?>>
687d62b00eSchristos 
697d62b00eSchristos    The "forward" naming fits both purposes shown above -- the class
707d62b00eSchristos    "forwards" ctor arguments to the wrapped cleanup function at scope
717d62b00eSchristos    exit time, and can also be used to "forward declare"
727d62b00eSchristos    scope_exit-like objects.  */
737d62b00eSchristos 
747d62b00eSchristos namespace detail
757d62b00eSchristos {
767d62b00eSchristos 
777d62b00eSchristos /* Function and Signature are passed in the same type, in order to
787d62b00eSchristos    extract Function's arguments' types in the specialization below.
797d62b00eSchristos    Those are used to generate the constructor.  */
807d62b00eSchristos 
817d62b00eSchristos template<typename Function, Function *function, typename Signature>
827d62b00eSchristos struct forward_scope_exit;
837d62b00eSchristos 
847d62b00eSchristos template<typename Function, Function *function,
857d62b00eSchristos 	 typename Res, typename... Args>
867d62b00eSchristos class forward_scope_exit<Function, function, Res (Args...)>
877d62b00eSchristos   : public scope_exit_base<forward_scope_exit<Function,
887d62b00eSchristos 					      function,
897d62b00eSchristos 					      Res (Args...)>>
907d62b00eSchristos {
917d62b00eSchristos   /* For access to on_exit().  */
927d62b00eSchristos   friend scope_exit_base<forward_scope_exit<Function,
937d62b00eSchristos 					    function,
947d62b00eSchristos 					    Res (Args...)>>;
957d62b00eSchristos 
967d62b00eSchristos public:
977d62b00eSchristos   explicit forward_scope_exit (Args ...args)
987d62b00eSchristos     : m_bind_function (function, args...)
997d62b00eSchristos   {
1007d62b00eSchristos     /* Nothing.  */
1017d62b00eSchristos   }
1027d62b00eSchristos 
1037d62b00eSchristos private:
1047d62b00eSchristos   void on_exit ()
1057d62b00eSchristos   {
1067d62b00eSchristos     m_bind_function ();
1077d62b00eSchristos   }
1087d62b00eSchristos 
1097d62b00eSchristos   /* The function and the arguments passed to the ctor, all packed in
1107d62b00eSchristos      a std::bind.  */
1117d62b00eSchristos   decltype (std::bind (function, std::declval<Args> ()...))
1127d62b00eSchristos     m_bind_function;
1137d62b00eSchristos };
1147d62b00eSchristos 
1157d62b00eSchristos } /* namespace detail */
1167d62b00eSchristos 
1177d62b00eSchristos /* This is the "public" entry point.  It's a macro to avoid having to
1187d62b00eSchristos    name FUNC more than once.  */
1197d62b00eSchristos 
1207d62b00eSchristos #define FORWARD_SCOPE_EXIT(FUNC) \
1217d62b00eSchristos   detail::forward_scope_exit<decltype (FUNC), FUNC, decltype (FUNC)>
1227d62b00eSchristos 
1237d62b00eSchristos #endif /* COMMON_FORWARD_SCOPE_EXIT_H */
124