Skip to content

Commit cdb656e

Browse files
committed
Validate all options/flags
Fixes #107
1 parent 24ba558 commit cdb656e

6 files changed

Lines changed: 91 additions & 71 deletions

File tree

RcppTskit/R/Class-TableCollection.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ TableCollection <- R6Class(
1818
#' @param xptr an external pointer (\code{externalptr}) to a table collection.
1919
#' @details See the corresponding Python function at
2020
#' \url{https://github.com/tskit-dev/tskit/blob/dc394d72d121c99c6dcad88f7a4873880924dd72/python/tskit/tables.py#L3463}.
21+
#' TODO: Update URL to TableCollection.load() method #104
22+
#' https://github.com/HighlanderLab/RcppTskit/issues/104
2123
#' @return A \code{\link{TableCollection}} object.
2224
#' @examples
2325
#' ts_file <- system.file("examples/test.trees", package = "RcppTskit")

RcppTskit/R/RcppTskit.R

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ ts_read <- ts_load
179179
#' @return A \code{\link{TableCollection}} object.
180180
#' @details See the corresponding Python function at
181181
#' \url{https://github.com/tskit-dev/tskit/blob/dc394d72d121c99c6dcad88f7a4873880924dd72/python/tskit/tables.py#L3463}.
182+
#' TODO: Update URL to TableCollection.load() method #104
183+
#' https://github.com/HighlanderLab/RcppTskit/issues/104
182184
#' @seealso \code{\link[=TableCollection]{TableCollection$new}}
183185
#' @examples
184186
#' ts_file <- system.file("examples/test.trees", package = "RcppTskit")

RcppTskit/inst/include/RcppTskit_public.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ Rcpp::IntegerVector kastore_version();
1111
Rcpp::IntegerVector tskit_version();
1212

1313
// sync default options with .cpp!
14-
SEXP rtsk_treeseq_load(std::string filename, int options = 0);
15-
SEXP rtsk_table_collection_load(std::string filename, int options = 0);
16-
void rtsk_treeseq_dump(SEXP ts, std::string filename, int options = 0);
17-
void rtsk_table_collection_dump(SEXP tc, std::string filename, int options = 0);
14+
SEXP rtsk_treeseq_load(std::string &filename, int options = 0);
15+
SEXP rtsk_table_collection_load(std::string &filename, int options = 0);
16+
void rtsk_treeseq_dump(SEXP ts, std::string &filename, int options = 0);
17+
void rtsk_table_collection_dump(SEXP tc, std::string &filename,
18+
int options = 0);
1819
SEXP rtsk_treeseq_copy_tables(SEXP ts, int options = 0);
1920
SEXP rtsk_treeseq_init(SEXP tc, int options = 0);
2021

RcppTskit/src/RcppExports.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,48 +31,48 @@ BEGIN_RCPP
3131
END_RCPP
3232
}
3333
// rtsk_treeseq_load
34-
SEXP rtsk_treeseq_load(const std::string filename, const int options);
34+
SEXP rtsk_treeseq_load(const std::string& filename, const int options);
3535
RcppExport SEXP _RcppTskit_rtsk_treeseq_load(SEXP filenameSEXP, SEXP optionsSEXP) {
3636
BEGIN_RCPP
3737
Rcpp::RObject rcpp_result_gen;
3838
Rcpp::RNGScope rcpp_rngScope_gen;
39-
Rcpp::traits::input_parameter< const std::string >::type filename(filenameSEXP);
39+
Rcpp::traits::input_parameter< const std::string& >::type filename(filenameSEXP);
4040
Rcpp::traits::input_parameter< const int >::type options(optionsSEXP);
4141
rcpp_result_gen = Rcpp::wrap(rtsk_treeseq_load(filename, options));
4242
return rcpp_result_gen;
4343
END_RCPP
4444
}
4545
// rtsk_table_collection_load
46-
SEXP rtsk_table_collection_load(const std::string filename, const int options);
46+
SEXP rtsk_table_collection_load(const std::string& filename, const int options);
4747
RcppExport SEXP _RcppTskit_rtsk_table_collection_load(SEXP filenameSEXP, SEXP optionsSEXP) {
4848
BEGIN_RCPP
4949
Rcpp::RObject rcpp_result_gen;
5050
Rcpp::RNGScope rcpp_rngScope_gen;
51-
Rcpp::traits::input_parameter< const std::string >::type filename(filenameSEXP);
51+
Rcpp::traits::input_parameter< const std::string& >::type filename(filenameSEXP);
5252
Rcpp::traits::input_parameter< const int >::type options(optionsSEXP);
5353
rcpp_result_gen = Rcpp::wrap(rtsk_table_collection_load(filename, options));
5454
return rcpp_result_gen;
5555
END_RCPP
5656
}
5757
// rtsk_treeseq_dump
58-
void rtsk_treeseq_dump(const SEXP ts, const std::string filename, const int options);
58+
void rtsk_treeseq_dump(const SEXP ts, const std::string& filename, const int options);
5959
RcppExport SEXP _RcppTskit_rtsk_treeseq_dump(SEXP tsSEXP, SEXP filenameSEXP, SEXP optionsSEXP) {
6060
BEGIN_RCPP
6161
Rcpp::RNGScope rcpp_rngScope_gen;
6262
Rcpp::traits::input_parameter< const SEXP >::type ts(tsSEXP);
63-
Rcpp::traits::input_parameter< const std::string >::type filename(filenameSEXP);
63+
Rcpp::traits::input_parameter< const std::string& >::type filename(filenameSEXP);
6464
Rcpp::traits::input_parameter< const int >::type options(optionsSEXP);
6565
rtsk_treeseq_dump(ts, filename, options);
6666
return R_NilValue;
6767
END_RCPP
6868
}
6969
// rtsk_table_collection_dump
70-
void rtsk_table_collection_dump(const SEXP tc, const std::string filename, const int options);
70+
void rtsk_table_collection_dump(const SEXP tc, const std::string& filename, const int options);
7171
RcppExport SEXP _RcppTskit_rtsk_table_collection_dump(SEXP tcSEXP, SEXP filenameSEXP, SEXP optionsSEXP) {
7272
BEGIN_RCPP
7373
Rcpp::RNGScope rcpp_rngScope_gen;
7474
Rcpp::traits::input_parameter< const SEXP >::type tc(tcSEXP);
75-
Rcpp::traits::input_parameter< const std::string >::type filename(filenameSEXP);
75+
Rcpp::traits::input_parameter< const std::string& >::type filename(filenameSEXP);
7676
Rcpp::traits::input_parameter< const int >::type options(optionsSEXP);
7777
rtsk_table_collection_dump(tc, filename, options);
7878
return R_NilValue;

RcppTskit/src/RcppTskit.cpp

Lines changed: 72 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
namespace {
99
// namespace to keep the contents local to this file
1010

11-
constexpr tsk_flags_t kLoadSupportedOptions =
11+
constexpr tsk_flags_t kLoadSupportedFlags =
1212
TSK_LOAD_SKIP_TABLES | TSK_LOAD_SKIP_REFERENCE_SEQUENCE;
1313

14-
constexpr tsk_flags_t kCopyTablesSupportedOptions = TSK_COPY_FILE_UUID;
14+
constexpr tsk_flags_t kCopyTablesSupportedFlags = TSK_COPY_FILE_UUID;
1515

16-
constexpr tsk_flags_t kTreeseqInitSupportedOptions =
16+
constexpr tsk_flags_t kTreeseqInitSupportedFlags =
1717
TSK_TS_INIT_BUILD_INDEXES | TSK_TS_INIT_COMPUTE_MUTATION_PARENTS;
1818

1919
// INTERNAL
@@ -26,16 +26,19 @@ constexpr tsk_flags_t kTreeseqInitSupportedOptions =
2626
// objects, so we can't work with \code{TSK_NO_INIT}
2727
// \url{https://tskit.dev/tskit/docs/stable/c-api.html#c.TSK_NO_INIT}.
2828
tsk_flags_t validate_load_options(const int options, const char *caller) {
29-
const tsk_flags_t load_options = static_cast<tsk_flags_t>(options);
30-
const tsk_flags_t unsupported = load_options & ~kLoadSupportedOptions;
29+
if (options < 0) {
30+
Rcpp::stop("%s does not support negative options", caller);
31+
}
32+
const tsk_flags_t flags = static_cast<tsk_flags_t>(options);
33+
const tsk_flags_t unsupported = flags & ~kLoadSupportedFlags;
3134
// ~ flips the bits in kLoadSupportedOptions
3235
if (unsupported != 0) {
3336
Rcpp::stop(
3437
"%s only supports load options TSK_LOAD_SKIP_TABLES (1 << 0) and "
3538
"TSK_LOAD_SKIP_REFERENCE_SEQUENCE (1 << 1); unsupported bits: 0x%X",
3639
caller, static_cast<unsigned int>(unsupported));
3740
}
38-
return load_options;
41+
return flags;
3942
}
4043

4144
// INTERNAL
@@ -51,19 +54,20 @@ tsk_flags_t validate_load_options(const int options, const char *caller) {
5154
// \url{https://tskit.dev/tskit/docs/stable/c-api.html#c.TSK_NO_INIT}.
5255
tsk_flags_t validate_copy_tables_options(const int options,
5356
const char *caller) {
54-
const tsk_flags_t copy_options = static_cast<tsk_flags_t>(options);
55-
if (copy_options & TSK_NO_INIT) {
56-
Rcpp::stop("%s does not support TSK_NO_INIT because the destination table "
57-
"collection is newly allocated in this wrapper",
58-
caller);
57+
if (options < 0) {
58+
Rcpp::stop("%s does not support negative options", caller);
59+
}
60+
const tsk_flags_t flags = static_cast<tsk_flags_t>(options);
61+
if (flags & TSK_NO_INIT) {
62+
Rcpp::stop("%s does not support TSK_NO_INIT", caller);
5963
}
60-
const tsk_flags_t unsupported = copy_options & ~kCopyTablesSupportedOptions;
64+
const tsk_flags_t unsupported = flags & ~kCopyTablesSupportedFlags;
6165
if (unsupported != 0) {
6266
Rcpp::stop("%s only supports copy option TSK_COPY_FILE_UUID (1 << 0); "
6367
"unsupported bits: 0x%X",
6468
caller, static_cast<unsigned int>(unsupported));
6569
}
66-
return copy_options;
70+
return flags;
6771
}
6872

6973
// INTERNAL
@@ -81,42 +85,49 @@ tsk_flags_t validate_copy_tables_options(const int options,
8185
// \url{https://tskit.dev/tskit/docs/stable/c-api.html#c.TSK_TAKE_OWNERSHIP}.
8286
tsk_flags_t validate_treeseq_init_options(const int options,
8387
const char *caller) {
84-
const tsk_flags_t init_options = static_cast<tsk_flags_t>(options);
85-
if (init_options & TSK_TAKE_OWNERSHIP) {
86-
Rcpp::stop(
87-
"%s does not support TSK_TAKE_OWNERSHIP because ownership "
88-
"is managed by R external pointers and this wrapper manages table "
89-
"collections with C++ new()/delete",
90-
caller);
88+
if (options < 0) {
89+
Rcpp::stop("%s does not support negative options", caller);
9190
}
92-
const tsk_flags_t unsupported = init_options & ~kTreeseqInitSupportedOptions;
91+
const tsk_flags_t flags = static_cast<tsk_flags_t>(options);
92+
if (flags & TSK_TAKE_OWNERSHIP) {
93+
Rcpp::stop("%s does not support TSK_TAKE_OWNERSHIP", caller);
94+
}
95+
const tsk_flags_t unsupported = flags & ~kTreeseqInitSupportedFlags;
9396
if (unsupported != 0) {
9497
Rcpp::stop(
9598
"%s only supports init options TSK_TS_INIT_BUILD_INDEXES (1 << 0) "
9699
"and TSK_TS_INIT_COMPUTE_MUTATION_PARENTS (1 << 1); unsupported "
97100
"bits: 0x%X",
98101
caller, static_cast<unsigned int>(unsupported));
99102
}
100-
return init_options;
103+
return flags;
101104
}
102105

103106
// INTERNAL
104-
// @title Validate tree sequence/table collection dump options
105-
// @param options passed to dump functions
107+
// @title Validate tskit flags
108+
// @param options passed to tskit functions
106109
// @param caller function name
107-
// @details See
110+
// @details See for example
108111
// \url{https://tskit.dev/tskit/docs/stable/c-api.html#c.tsk_treeseq_dump}
109112
// and
110-
// \url{https://tskit.dev/tskit/docs/stable/c-api.html#c.tsk_table_collection_dump}.
111-
// \code{tskit} currently does not use dump options and expects \code{0}.
112-
tsk_flags_t validate_dump_options(const int options, const char *caller) {
113-
const tsk_flags_t dump_options = static_cast<tsk_flags_t>(options);
114-
if (dump_options != 0) {
115-
Rcpp::stop("%s does not support non-zero options; tsk dump APIs currently "
116-
"require options = 0",
117-
caller);
113+
// \url{https://tskit.dev/tskit/docs/stable/c-api.html#c.tsk_table_collection_dump},
114+
// which currently expects \code{0}.
115+
tsk_flags_t validate_options(const int options, const tsk_flags_t supported,
116+
const char *caller) {
117+
if (options < 0) {
118+
Rcpp::stop("%s does not support negative options", caller);
119+
}
120+
const tsk_flags_t flags = static_cast<tsk_flags_t>(options);
121+
const tsk_flags_t unsupported = flags & ~supported;
122+
if (unsupported != 0) {
123+
Rcpp::stop("%s only supports options 0x%X; unsupported bits: 0x%X", caller,
124+
static_cast<unsigned int>(supported),
125+
static_cast<unsigned int>(unsupported));
126+
}
127+
if (flags != 0) {
128+
Rcpp::stop("%s does not support non-zero options", caller);
118129
}
119-
return dump_options;
130+
return flags;
120131
}
121132

122133
} // namespace
@@ -174,13 +185,12 @@ Rcpp::IntegerVector tskit_version() {
174185
// ts <- TreeSequence$new(xptr = ts_xptr)
175186
// is(ts)
176187
// [[Rcpp::export]]
177-
SEXP rtsk_treeseq_load(const std::string filename, const int options = 0) {
178-
const tsk_flags_t load_options =
179-
validate_load_options(options, "rtsk_treeseq_load");
188+
SEXP rtsk_treeseq_load(const std::string &filename, const int options = 0) {
189+
const tsk_flags_t flags = validate_load_options(options, "rtsk_treeseq_load");
180190
// tsk_treeseq_t ts; // on stack, destroyed end of func, must free resources
181191
tsk_treeseq_t *ts_ptr = new tsk_treeseq_t(); // on heap, persists function
182192
// See also https://tskit.dev/tskit/docs/stable/c-api.html#api-structure
183-
int ret = tsk_treeseq_load(ts_ptr, filename.c_str(), load_options);
193+
int ret = tsk_treeseq_load(ts_ptr, filename.c_str(), flags);
184194
if (ret != 0) {
185195
tsk_treeseq_free(ts_ptr);
186196
delete ts_ptr;
@@ -214,12 +224,12 @@ SEXP rtsk_treeseq_load(const std::string filename, const int options = 0) {
214224
// tc <- TableCollection$new(xptr = tc_xptr)
215225
// is(tc)
216226
// [[Rcpp::export]]
217-
SEXP rtsk_table_collection_load(const std::string filename,
227+
SEXP rtsk_table_collection_load(const std::string &filename,
218228
const int options = 0) {
219-
const tsk_flags_t load_options =
229+
const tsk_flags_t flags =
220230
validate_load_options(options, "rtsk_table_collection_load");
221231
tsk_table_collection_t *tc_ptr = new tsk_table_collection_t();
222-
int ret = tsk_table_collection_load(tc_ptr, filename.c_str(), load_options);
232+
int ret = tsk_table_collection_load(tc_ptr, filename.c_str(), flags);
223233
if (ret != 0) {
224234
tsk_table_collection_free(tc_ptr);
225235
delete tc_ptr;
@@ -248,12 +258,11 @@ SEXP rtsk_table_collection_load(const std::string filename,
248258
// RcppTskit:::rtsk_treeseq_dump(ts_xptr, dump_file)
249259
// file.remove(dump_file)
250260
// [[Rcpp::export]]
251-
void rtsk_treeseq_dump(const SEXP ts, const std::string filename,
261+
void rtsk_treeseq_dump(const SEXP ts, const std::string &filename,
252262
const int options = 0) {
253-
const tsk_flags_t dump_options =
254-
validate_dump_options(options, "rtsk_treeseq_dump");
263+
const tsk_flags_t flags = validate_options(options, 0, "rtsk_treeseq_dump");
255264
rtsk_treeseq_t ts_xptr(ts);
256-
int ret = tsk_treeseq_dump(ts_xptr, filename.c_str(), dump_options);
265+
int ret = tsk_treeseq_dump(ts_xptr, filename.c_str(), flags);
257266
if (ret != 0) {
258267
Rcpp::stop(tsk_strerror(ret));
259268
}
@@ -276,12 +285,12 @@ void rtsk_treeseq_dump(const SEXP ts, const std::string filename,
276285
// RcppTskit:::rtsk_table_collection_dump(tc_xptr, dump_file)
277286
// file.remove(dump_file)
278287
// [[Rcpp::export]]
279-
void rtsk_table_collection_dump(const SEXP tc, const std::string filename,
288+
void rtsk_table_collection_dump(const SEXP tc, const std::string &filename,
280289
const int options = 0) {
281-
const tsk_flags_t dump_options =
282-
validate_dump_options(options, "rtsk_table_collection_dump");
290+
const tsk_flags_t flags =
291+
validate_options(options, 0, "rtsk_table_collection_dump");
283292
rtsk_table_collection_t tc_xptr(tc);
284-
int ret = tsk_table_collection_dump(tc_xptr, filename.c_str(), dump_options);
293+
int ret = tsk_table_collection_dump(tc_xptr, filename.c_str(), flags);
285294
if (ret != 0) {
286295
Rcpp::stop(tsk_strerror(ret));
287296
}
@@ -312,11 +321,11 @@ void rtsk_table_collection_dump(const SEXP tc, const std::string filename,
312321
// RcppTskit:::rtsk_table_collection_print(tc_xptr)
313322
// [[Rcpp::export]]
314323
SEXP rtsk_treeseq_copy_tables(const SEXP ts, const int options = 0) {
315-
const tsk_flags_t copy_options =
324+
const tsk_flags_t flags =
316325
validate_copy_tables_options(options, "rtsk_treeseq_copy_tables");
317326
rtsk_treeseq_t ts_xptr(ts);
318327
tsk_table_collection_t *tc_ptr = new tsk_table_collection_t();
319-
int ret = tsk_treeseq_copy_tables(ts_xptr, tc_ptr, copy_options);
328+
int ret = tsk_treeseq_copy_tables(ts_xptr, tc_ptr, flags);
320329
if (ret != 0) {
321330
tsk_table_collection_free(tc_ptr);
322331
delete tc_ptr;
@@ -360,11 +369,11 @@ SEXP rtsk_treeseq_copy_tables(const SEXP ts, const int options = 0) {
360369
// RcppTskit:::rtsk_treeseq_print(ts_xptr)
361370
// [[Rcpp::export]]
362371
SEXP rtsk_treeseq_init(const SEXP tc, const int options = 0) {
363-
const tsk_flags_t init_options =
372+
const tsk_flags_t flags =
364373
validate_treeseq_init_options(options, "rtsk_treeseq_init");
365374
rtsk_table_collection_t tc_xptr(tc);
366375
tsk_treeseq_t *ts_ptr = new tsk_treeseq_t();
367-
int ret = tsk_treeseq_init(ts_ptr, tc_xptr, init_options);
376+
int ret = tsk_treeseq_init(ts_ptr, tc_xptr, flags);
368377
if (ret != 0) {
369378
tsk_treeseq_free(ts_ptr);
370379
delete ts_ptr;
@@ -814,8 +823,10 @@ Rcpp::String rtsk_table_collection_get_file_uuid(const SEXP tc) {
814823
// @describeIn rtsk_table_collection_summary Is the table collection indexed
815824
// [[Rcpp::export]]
816825
bool rtsk_table_collection_has_index(const SEXP tc, const int options = 0) {
826+
const tsk_flags_t flags =
827+
validate_options(options, 0, "rtsk_table_collection_has_index");
817828
rtsk_table_collection_t tc_xptr(tc);
818-
return tsk_table_collection_has_index(tc_xptr, options);
829+
return tsk_table_collection_has_index(tc_xptr, flags);
819830
}
820831

821832
// PUBLIC, wrapper for tsk_table_collection_build_index
@@ -837,8 +848,10 @@ bool rtsk_table_collection_has_index(const SEXP tc, const int options = 0) {
837848
// RcppTskit:::rtsk_table_collection_has_index(tc_xptr)
838849
// [[Rcpp::export]]
839850
void rtsk_table_collection_build_index(const SEXP tc, const int options = 0) {
851+
const tsk_flags_t flags =
852+
validate_options(options, 0, "rtsk_table_collection_build_index");
840853
rtsk_table_collection_t tc_xptr(tc);
841-
int ret = tsk_table_collection_build_index(tc_xptr, options);
854+
int ret = tsk_table_collection_build_index(tc_xptr, flags);
842855
if (ret != 0) {
843856
Rcpp::stop(tsk_strerror(ret));
844857
}
@@ -861,10 +874,12 @@ void rtsk_table_collection_build_index(const SEXP tc, const int options = 0) {
861874
// RcppTskit:::rtsk_table_collection_has_index(tc_xptr)
862875
// [[Rcpp::export]]
863876
void rtsk_table_collection_drop_index(const SEXP tc, const int options = 0) {
877+
const tsk_flags_t flags =
878+
validate_options(options, 0, "rtsk_table_collection_drop_index");
864879
rtsk_table_collection_t tc_xptr(tc);
865-
int ret = tsk_table_collection_drop_index(tc_xptr, options);
880+
int ret = tsk_table_collection_drop_index(tc_xptr, flags);
866881
// tsk_table_collection_drop_index() currently documents always returning 0;
867-
// so we test for possible future failures, but we cannot unit-tested.
882+
// so we test for possible future failures, but we cannot unit-test this path.
868883
// # nocov start
869884
if (ret != 0) {
870885
Rcpp::stop(tsk_strerror(ret));

RcppTskit/tests/testthat/test_load_summary_and_dump.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ test_that("ts/tc_load(), ts/tc_summary*(), and ts/tc_dump(x) work", {
549549
file = tempfile(fileext = ".trees"),
550550
options = 1L
551551
),
552-
regexp = "does not support non-zero options"
552+
regexp = "rtsk_treeseq_dump only supports options "
553553
)
554554

555555
# Write ts to disk, read it back, and check that nums are still the same
@@ -608,7 +608,7 @@ test_that("ts/tc_load(), ts/tc_summary*(), and ts/tc_dump(x) work", {
608608
file = tempfile(fileext = ".trees"),
609609
options = 1L
610610
),
611-
regexp = "does not support non-zero options"
611+
regexp = "rtsk_table_collection_dump only supports options "
612612
)
613613

614614
# Write ts to disk, read it back, and check that nums are still the same

0 commit comments

Comments
 (0)