Rcpp Version 1.0.7
unwindProtect.h
Go to the documentation of this file.
1 
2 // unwind.h: Rcpp R/C++ interface class library -- Unwind Protect
3 //
4 // Copyright (C) 2018 - 2020 RStudio
5 // Copyright (C) 2021 RStudio, Dirk Eddelbuettel and IƱaki Ucar
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21 
22 #ifndef RCPP_UNWINDPROTECT_H
23 #define RCPP_UNWINDPROTECT_H
24 
25 #include <csetjmp>
26 
27 #ifdef RCPP_USING_CXX11
28 #include <functional>
29 #endif
30 
31 
32 namespace Rcpp { namespace internal {
33 
34 struct UnwindData {
35  std::jmp_buf jmpbuf;
36 };
37 
38 // First jump back to the protected context with a C longjmp because
39 // `Rcpp_protected_eval()` is called from C and we can't safely throw
40 // exceptions across C frames.
41 inline void maybeJump(void* unwind_data, Rboolean jump) {
42  if (jump) {
43  UnwindData* data = static_cast<UnwindData*>(unwind_data);
44  longjmp(data->jmpbuf, 1);
45  }
46 }
47 
48 #ifdef RCPP_USING_CXX11
49 inline SEXP unwindProtectUnwrap(void* data) {
50  std::function<SEXP(void)>* callback = (std::function<SEXP(void)>*) data;
51  return (*callback)();
52 }
53 #endif
54 
55 }} // namespace Rcpp::internal
56 
57 
58 namespace Rcpp {
59 
60 inline SEXP unwindProtect(SEXP (*callback)(void* data), void* data) {
61  internal::UnwindData unwind_data;
62  Shield<SEXP> token(::R_MakeUnwindCont());
63 
64  if (setjmp(unwind_data.jmpbuf)) {
65  // Keep the token protected while unwinding because R code might run
66  // in C++ destructors. Can't use PROTECT() for this because
67  // UNPROTECT() might be called in a destructor, for instance if a
68  // Shield<SEXP> is on the stack.
69  ::R_PreserveObject(token);
70 
71  throw LongjumpException(token);
72  }
73 
74  return ::R_UnwindProtect(callback, data,
75  internal::maybeJump, &unwind_data,
76  token);
77 }
78 
79 #ifdef RCPP_USING_CXX11
80 inline SEXP unwindProtect(std::function<SEXP(void)> callback) {
81  return unwindProtect(&internal::unwindProtectUnwrap, &callback);
82 }
83 #endif
84 
85 } // namespace Rcpp
86 
87 #endif
Rcpp::internal::UnwindData
Definition: unwindProtect.h:34
Rcpp::LongjumpException
Definition: exceptions.h:164
Rcpp::Shield
Definition: Shield.h:35
Rcpp
Rcpp API.
Definition: algo.h:28
Rcpp::unwindProtect
SEXP unwindProtect(SEXP(*callback)(void *data), void *data)
Definition: unwindProtect.h:60
Rcpp::internal::UnwindData::jmpbuf
std::jmp_buf jmpbuf
Definition: unwindProtect.h:35
Rcpp::internal::maybeJump
void maybeJump(void *unwind_data, Rboolean jump)
Definition: unwindProtect.h:41