Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@
* inst/tinytest/cpp/Module.cpp (Module_scope_is_cleared): New
* inst/tinytest/test_module.R: Test loading the failing module

* inst/include/Rcpp/module/class.h (class_::AddMethod): Count special
'[' methods once per name rather than once per overload, as complete()
expects; overloading '[[' dropped methods from completion or ran past
the end of the method map (#1529)
* inst/tinytest/cpp/Module.cpp: Add classes overloading '[['
* inst/tinytest/test_module.R: Test their completions

* inst/include/Rcpp/Module.h (internal::module_class_pointer): New
per-library record of the class_<Class> registered for a C++ type
* inst/include/Rcpp/Module.h (internal::make_new_object): Pass it to
Expand Down
3 changes: 2 additions & 1 deletion inst/include/Rcpp/module/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,10 @@
typename map_vec_signed_method::iterator it = ptr->vec_methods.find( name_ ) ;
if( it == ptr->vec_methods.end() ){
it = ptr->vec_methods.insert( vec_signed_method_pair( name_, new vec_signed_method() ) ).first ;
// complete() relies on this counting names, not overloads
if( *name_ == '[' ) ptr->specials++ ;
}
(it->second)->push_back( new signed_method_class(m, valid, docstring ) ) ;
if( *name_ == '[' ) ptr->specials++ ;
return *this ;
}

Expand Down
37 changes: 37 additions & 0 deletions inst/tinytest/cpp/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,27 @@ double ModuleBase_value(const ModuleBase& x) {
return x.value;
}

class ModuleBrackets {
public:
ModuleBrackets() : value(1.0) {}

double at(int i) { return value * i; }
double at2(int i, int j) { return value * i * j; }
double total() { return value; }

double value;
};

class ModuleBracketsOnly {
public:
ModuleBracketsOnly() : value(1.0) {}

double at(int i) { return value * i; }
double at2(int i, int j) { return value * i * j; }

double value;
};

class ModuleGadget {
public:
ModuleGadget() {}
Expand Down Expand Up @@ -283,6 +304,22 @@ RCPP_MODULE(demoModule) {

function("ModuleBase_value", &ModuleBase_value);

// overloaded [[, with and without an ordinary method
class_<ModuleBrackets>("ModuleBrackets")
.constructor()
.method("[[", &ModuleBrackets::at)
.method("[[", &ModuleBrackets::at2)
.method("total", &ModuleBrackets::total)
.field("value", &ModuleBrackets::value)
;

class_<ModuleBracketsOnly>("ModuleBracketsOnly")
.constructor()
.method("[[", &ModuleBracketsOnly::at)
.method("[[", &ModuleBracketsOnly::at2)
.field("value", &ModuleBracketsOnly::value)
;

class_<ModuleGadget>("ModuleGadget")
.constructor()
.method("value", static_cast<void (ModuleGadget::*)(int)>(&ModuleGadget::value))
Expand Down
8 changes: 8 additions & 0 deletions inst/tinytest/test_module.R
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ expect_error( r$get(10L), "not initialized" )
expect_error( Rcpp::sourceCpp("cpp/ModuleInitError.cpp"), "no such class" )
expect_true( Module_scope_is_cleared() )

## completion lists the ordinary methods and the fields; an overloaded [[
## used to be counted once per overload, which dropped the last ordinary
## method, or ran past the end of the method map when there was none (#1529)
brackets <- new( ModuleBrackets )
expect_equal( Rcpp:::complete( brackets ), c("total( ", "value") )
expect_equal( brackets[[2L]], 2.0 )
expect_equal( Rcpp:::complete( new( ModuleBracketsOnly ) ), "value" )

## a body that throws after registering some of its classes and functions
## leaves nothing behind, so loading the module again does not end up with
## two copies of what the failed run registered
Expand Down
Loading