Skip to content

Commit 205ddd1

Browse files
committed
Adds an API for checking the callback queue length for a loop.
This introduces loop_queue_length(), which is similar to loop_empty() but provides a more granular measure of what remains to be executed. Unlike list_queue(), it is an exported function meant to be used externally. Includes documentation and tests.
1 parent 1f7de58 commit 205ddd1

File tree

10 files changed

+84
-0
lines changed

10 files changed

+84
-0
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export(exists_loop)
99
export(global_loop)
1010
export(later)
1111
export(loop_empty)
12+
export(loop_queue_length)
1213
export(next_op_secs)
1314
export(run_now)
1415
export(with_loop)

R/RcppExports.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ ensureInitialized <- function() {
4949
invisible(.Call('_later_ensureInitialized', PACKAGE = 'later'))
5050
}
5151

52+
queueLength <- function(loop_id) {
53+
.Call('_later_queueLength', PACKAGE = 'later', loop_id)
54+
}
55+
5256
execLater <- function(callback, delaySecs, loop_id) {
5357
.Call('_later_execLater', PACKAGE = 'later', callback, delaySecs, loop_id)
5458
}

R/later.R

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,17 @@ loop_empty <- function(loop = current_loop()) {
314314
idle(loop$id)
315315
}
316316

317+
#' Check how many callbacks are queued in a later loop
318+
#'
319+
#' Returns the number of callbacks that are scheduled to execute in the present
320+
#' or future.
321+
#'
322+
#' @inheritParams create_loop
323+
#' @export
324+
loop_queue_length <- function(loop = current_loop()) {
325+
queueLength(loop$id)
326+
}
327+
317328
#' Relative time to next scheduled operation
318329
#'
319330
#' Returns the duration between now and the earliest operation that is currently

man/loop_queue_length.Rd

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/RcppExports.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ BEGIN_RCPP
134134
return R_NilValue;
135135
END_RCPP
136136
}
137+
// queueLength
138+
size_t queueLength(int loop_id);
139+
RcppExport SEXP _later_queueLength(SEXP loop_idSEXP) {
140+
BEGIN_RCPP
141+
Rcpp::RObject rcpp_result_gen;
142+
Rcpp::RNGScope rcpp_rngScope_gen;
143+
Rcpp::traits::input_parameter< int >::type loop_id(loop_idSEXP);
144+
rcpp_result_gen = Rcpp::wrap(queueLength(loop_id));
145+
return rcpp_result_gen;
146+
END_RCPP
147+
}
137148
// execLater
138149
std::string execLater(Rcpp::Function callback, double delaySecs, int loop_id);
139150
RcppExport SEXP _later_execLater(SEXP callbackSEXP, SEXP delaySecsSEXP, SEXP loop_idSEXP) {

src/callback_registry.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ bool CallbackRegistry::empty() const {
343343
return this->queue.empty();
344344
}
345345

346+
size_t CallbackRegistry::queueLength() const {
347+
Guard guard(mutex);
348+
return this->queue.size();
349+
}
350+
346351
// Returns true if the smallest timestamp exists and is not in the future.
347352
bool CallbackRegistry::due(const Timestamp& time, bool recursive) const {
348353
ASSERT_MAIN_THREAD()

src/callback_registry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ class CallbackRegistry {
138138
// Is the registry completely empty?
139139
bool empty() const;
140140

141+
// How many callbacks are currently queued?
142+
size_t queueLength() const;
143+
141144
// Is anything ready to execute?
142145
bool due(const Timestamp& time = Timestamp(), bool recursive = true) const;
143146

src/init.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Check these declarations against the C/Fortran source code.
1212
extern SEXP _later_ensureInitialized();
1313
extern SEXP _later_execCallbacks(SEXP, SEXP, SEXP);
1414
extern SEXP _later_idle(SEXP);
15+
extern SEXP _later_queueLength(SEXP);
1516
extern SEXP _later_execLater(SEXP, SEXP, SEXP);
1617
extern SEXP _later_cancel(SEXP, SEXP);
1718
extern SEXP _later_nextOpSecs(SEXP);
@@ -29,6 +30,7 @@ static const R_CallMethodDef CallEntries[] = {
2930
{"_later_ensureInitialized", (DL_FUNC) &_later_ensureInitialized, 0},
3031
{"_later_execCallbacks", (DL_FUNC) &_later_execCallbacks, 3},
3132
{"_later_idle", (DL_FUNC) &_later_idle, 1},
33+
{"_later_queueLength", (DL_FUNC) &_later_queueLength, 1},
3234
{"_later_execLater", (DL_FUNC) &_later_execLater, 3},
3335
{"_later_cancel", (DL_FUNC) &_later_cancel, 2},
3436
{"_later_nextOpSecs", (DL_FUNC) &_later_nextOpSecs, 1},

src/later.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,16 @@ void ensureInitialized() {
298298
initialized = true;
299299
}
300300

301+
// [[Rcpp::export]]
302+
size_t queueLength(int loop_id) {
303+
ASSERT_MAIN_THREAD()
304+
shared_ptr<CallbackRegistry> registry = callbackRegistryTable.getRegistry(loop_id);
305+
if (registry == nullptr) {
306+
Rf_error("CallbackRegistry does not exist.");
307+
}
308+
return registry->queueLength();
309+
}
310+
301311
// [[Rcpp::export]]
302312
std::string execLater(Rcpp::Function callback, double delaySecs, int loop_id) {
303313
ASSERT_MAIN_THREAD()

tests/testthat/test-private-loops.R

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,25 @@ test_that("list_queue", {
421421
q <- list_queue(l)
422422
expect_equal(length(q), 0)
423423
})
424+
425+
426+
describe("Queue length with nested loops", {
427+
x <- 0
428+
later(~{x <<- 1}, 0)
429+
expect_equal(loop_queue_length(), 1)
430+
with_temp_loop({
431+
expect_equal(loop_queue_length(), 0)
432+
433+
later(~{x <<- 2})
434+
expect_equal(loop_queue_length(), 1)
435+
436+
run_now()
437+
expect_identical(x, 2)
438+
expect_equal(loop_queue_length(), 0)
439+
expect_equal(loop_queue_length(loop = global_loop()), 1)
440+
441+
run_now(loop = global_loop())
442+
expect_equal(loop_queue_length(loop = global_loop()), 0)
443+
expect_identical(x, 1)
444+
})
445+
})

0 commit comments

Comments
 (0)