The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Error Handling

Overview

R packages with compiled code have several error mechanisms that do not always work well together: C++ exceptions, C-style errors, and R errors. No single mechanism is safe and idiomatic in every context. The design in charport does not try to put all of these error mechanisms into a single system, but instead tries to be parsimonious, only allowing errors to propagate based on the code and boundaries they interact with.

Operations that call R or construct R objects use R errors, because those operations can already fail through R. Pure C++ operations use standard C++ exceptions, while C access callbacks return C-style integer error codes.

Reader and Builder

Part C++ error handling C error handling
Reader construction Empty construction has no error. Reader(SEXP) uses R errors; with_rcpp() and with_cpp11() adapt construction to the framework’s C++ exception R error
Reader reset reset(SEXP) uses R errors. If resolution fails, the Reader keeps its current borrow. R error
Reader access Standard C++ exception Integer status
Reader destruction None None
Builder construction Standard C++ exception N/A
Builder string append Standard C++ exception N/A
Builder to_sexp() R error; to_sexp_with_rcpp() and to_sexp_with_cpp11() adapt it to the framework’s C++ exception N/A
charvec C constructor N/A R error; crosses the charport package boundary

An empty Reader can be initialized after its C++ lifetime has begun:

charport::Reader input;
input.reset(x);

reset() uses ordinary R error semantics. If resolution fails, the Reader keeps its current borrow. A successful reset releases that borrow and adopts the new one.

Rcpp and cpp11 adapters

Rcpp and cpp11 code can request framework adapters explicitly for Reader construction and Builder conversion:

#include <Rcpp.h>
#include "charport.h"

charport::Reader input = charport::Reader::with_rcpp(x);

charport::charvec::Builder output(input.size());
// Fill output.
SEXP result = output.to_sexp_with_rcpp();
#include <cpp11.hpp>
#include "charport.h"

charport::Reader input = charport::Reader::with_cpp11(x);

charport::charvec::Builder output(input.size());
// Fill output.
SEXP result = output.to_sexp_with_cpp11();

The framework header must come first. The Reader adapter protects the resolution operation, while the Builder adapter protects the terminal conversion to an R object. Each preserves the original R condition in the exception form expected by that framework.

Manual error handling

A C++ package that doesn’t use Rcpp or cpp11 must supply its own error handling around any R call for correctness, not just for charport but in general. R provides R_UnwindProtect() as the low-level mechanism for running cleanup during an R error.

Reader access exceptions

Status conversion is not a bounds check. Callers must supply nonnegative, in-range indices and sizes; an empty range may start at Reader::size(). Reader and the providers shipped with charport do not validate these bounds. A provider that chooses to validate may report CHARPORT_STATUS_OUT_OF_RANGE.

During access calls, e.g., Reader::views(), the Reader may be unable to provide those views. This is a return status code in C and an exception in C++.

C return status Meaning C++ exception
CHARPORT_STATUS_OK The output arrays were filled successfully. None
CHARPORT_STATUS_ERROR or any other nonzero status The access failed for another reason. std::runtime_error
CHARPORT_STATUS_NO_MEMORY Native allocation failed. std::bad_alloc
CHARPORT_STATUS_OUT_OF_RANGE The provider rejected an index or range. std::out_of_range

An access failure does not invalidate the Reader or make the error sticky. The provider state stays available for another access and for release. Whether a later access succeeds depends on the provider. When concurrent_access() is true, multiple worker threads can fail without sharing error state.

Builder conversion

charvec::Builder and its variants allocate and own their own Store during the C++ construction phase. Building the string data is standard C++ and may raise a C++ exception.

Builder::to_sexp() cannot throw a C++ exception, but since it creates the ALTREP object that contains the Store, it may theoretically raise an R allocation error. A caller that wants framework cleanup can use the named adapters:

SEXP rcpp_out = builder.to_sexp_with_rcpp();
SEXP cpp11_out = builder.to_sexp_with_cpp11();

Registration of ALTREP classes

Registering an ALTREP class requires several callbacks and lifecycle guarantees. A producer should meet the following contracts in order to make sure the consumer can always properly recover from errors and clean up resources.

Producer part Failure mechanism Producer obligation
init(SEXP) R error Any C++ exception must be converted to an R error.
Range and indexed access Integer status Should not call R. C++ exceptions should be converted to nonzero status codes. Return CHARPORT_STATUS_OK only after filling the outputs.
release(state) None If supplied, should not be able to produce an R error or C++ exception.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.