Skip to content

Commit dae1b6a

Browse files
avoid need for R_NilValue checks in protect code (#285)
* avoid need for R_NilValue checks in protect code * tweak comments + names * typo * fix comments * backwards compatibility? * code comments * satisfy grumpy formatter --------- Co-authored-by: Romain François <romain@rstudio.com>
1 parent 32eef66 commit dae1b6a

File tree

2 files changed

+32
-26
lines changed

2 files changed

+32
-26
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# cpp11 (development version)
22

3+
* Minor performance improvements to the cpp11 protect code. (@kevinushey)
4+
35
* Silenced an unknown attribute warning specific to the Intel compiler
46
(r-lib/systemfonts#98).
57

inst/include/cpp11/protect.hpp

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -315,16 +315,18 @@ static struct {
315315

316316
static SEXP list_ = get_preserve_list();
317317

318-
// Add a new cell that points to the previous end.
319-
SEXP cell = PROTECT(Rf_cons(list_, CDR(list_)));
318+
// Get references to head, tail of the precious list.
319+
SEXP head = list_;
320+
SEXP tail = CDR(list_);
320321

322+
// Add a new cell that points to the current head + tail.
323+
SEXP cell = PROTECT(Rf_cons(head, tail));
321324
SET_TAG(cell, obj);
322325

323-
SETCDR(list_, cell);
324-
325-
if (CDR(cell) != R_NilValue) {
326-
SETCAR(CDR(cell), cell);
327-
}
326+
// Update the head + tail to point at the newly-created cell,
327+
// effectively inserting that cell between the current head + tail.
328+
SETCDR(head, cell);
329+
SETCAR(tail, cell);
328330

329331
UNPROTECT(2);
330332

@@ -352,29 +354,25 @@ static struct {
352354
#endif
353355
}
354356

355-
void release(SEXP token) {
356-
if (token == R_NilValue) {
357+
void release(SEXP cell) {
358+
if (cell == R_NilValue) {
357359
return;
358360
}
359361

360362
#ifdef CPP11_USE_PRESERVE_OBJECT
361-
R_ReleaseObject(token);
363+
R_ReleaseObject(cell);
362364
return;
363365
#endif
364366

365-
SEXP before = CAR(token);
366-
367-
SEXP after = CDR(token);
368-
369-
if (before == R_NilValue && after == R_NilValue) {
370-
Rf_error("should never happen");
371-
}
372-
373-
SETCDR(before, after);
367+
// Get a reference to the cells before and after the token.
368+
SEXP lhs = CAR(cell);
369+
SEXP rhs = CDR(cell);
374370

375-
if (after != R_NilValue) {
376-
SETCAR(after, before);
377-
}
371+
// Remove the cell from the precious list -- effectively, we do this
372+
// by updating the 'lhs' and 'rhs' references to point at each-other,
373+
// effectively removing any references to the cell in the pairlist.
374+
SETCDR(lhs, rhs);
375+
SETCAR(rhs, lhs);
378376
}
379377

380378
private:
@@ -414,18 +412,24 @@ static struct {
414412

415413
static SEXP get_preserve_list() {
416414
static SEXP preserve_list = R_NilValue;
417-
418415
if (TYPEOF(preserve_list) != LISTSXP) {
419416
preserve_list = get_preserve_xptr_addr();
420417
if (TYPEOF(preserve_list) != LISTSXP) {
421-
preserve_list = Rf_cons(R_NilValue, R_NilValue);
418+
preserve_list = Rf_cons(R_NilValue, Rf_cons(R_NilValue, R_NilValue));
422419
R_PreserveObject(preserve_list);
423420
set_preserve_xptr(preserve_list);
424421
}
422+
423+
// NOTE: Because older versions of cpp11 (<= 0.4.2) initialized the
424+
// precious_list with a single cell, we might need to detect and update
425+
// an existing empty precious list so that we have a second cell following.
426+
if (CDR(preserve_list) == R_NilValue)
427+
SETCDR(preserve_list, Rf_cons(R_NilValue, R_NilValue));
425428
}
426429

427430
return preserve_list;
428431
}
429-
} // namespace cpp11
430-
preserved;
432+
433+
} preserved;
434+
431435
} // namespace cpp11

0 commit comments

Comments
 (0)