Skip to content

Commit d800e2a

Browse files
committed
Add in warning when DataFrame created will have incorrect rows.
With this commit, if after a push_back the row count of the DataFrame would be invalid, a warning is generated. The type is then not coerced to a DataFrame, but left as a list. In future, this could instead `stop()`.
1 parent fab8b38 commit d800e2a

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

inst/include/Rcpp/DataFrame.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,25 +86,25 @@ namespace Rcpp{
8686
template <typename T>
8787
void push_back( const T& object){
8888
Parent::push_back(object);
89-
set__(Parent::get__());
89+
set_type_after_push();
9090
}
9191

9292
template <typename T>
9393
void push_back( const T& object, const std::string& name ){
9494
Parent::push_back(object, name);
95-
set__(Parent::get__());
95+
set_type_after_push();
9696
}
9797

9898
template <typename T>
9999
void push_front( const T& object){
100100
Parent::push_front(object);
101-
set__(Parent::get__());
101+
set_type_after_push();
102102
}
103103

104104
template <typename T>
105105
void push_front( const T& object, const std::string& name){
106106
Parent::push_front(object, name);
107-
set__(Parent::get__());
107+
set_type_after_push();
108108
}
109109

110110
// Offer multiple variants to accomodate both old interface here and signatures in other classes
@@ -130,6 +130,30 @@ namespace Rcpp{
130130
}
131131
}
132132

133+
void set_type_after_push(){
134+
int max_rows = 0;
135+
bool invalid_column_size = false;
136+
SEXP data = Parent::get__();
137+
List::iterator it;
138+
// Get the maximum number of rows
139+
for (it = Parent::begin(); it != Parent::end(); ++it) {
140+
if (Rf_xlength(*it) > max_rows) {
141+
max_rows = Rf_xlength(*it);
142+
}
143+
}
144+
for (it = Parent::begin(); it != Parent::end(); ++it) {
145+
if (Rf_xlength(*it) > 1 && max_rows % Rf_xlength(*it) != 0) {
146+
// We have a column that is not an integer fraction of the largest
147+
invalid_column_size = true;
148+
}
149+
}
150+
if (invalid_column_size) {
151+
warning("Column sizes are not equal in DataFrame::push_back, object degrading to List\n");
152+
} else {
153+
set__(Parent::get__());
154+
}
155+
}
156+
133157
static DataFrame_Impl from_list( Parent obj ){
134158
bool use_default_strings_as_factors = true ;
135159
bool strings_as_factors = true ;

inst/tinytest/cpp/DataFrame.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,27 @@ DataFrame DataFrame_PushBackDataFrame(){
157157
return df1;
158158
}
159159

160+
// [[Rcpp::export]]
161+
DataFrame DataFrame_PushWrongSize(){
162+
NumericVector u(2);
163+
NumericVector v(3);
164+
165+
DataFrame df1 = DataFrame::create(_["u"] = u);
166+
df1.push_back(v);
167+
return df1;
168+
}
169+
170+
// [[Rcpp::export]]
171+
DataFrame DataFrame_PushReplicateLength(){
172+
NumericVector u(2);
173+
NumericVector v(4);
174+
NumericVector x(1);
175+
176+
u[0] = 1;
177+
x[0] = 2;
178+
179+
DataFrame df1 = DataFrame::create(_["u"] = u);
180+
df1.push_back(v);
181+
df1.push_back(x);
182+
return df1;
183+
}

inst/tinytest/test_dataframe.R

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,12 @@ expect_equal( DataFrame_PushFrontDataFrame(), df )
101101
df <- data.frame( u = c(0, 0), v = c(0, 0), w = c(0, 0), x = c(0, 0) )
102102
expect_true( is.data.frame( DataFrame_PushBackDataFrame() ) )
103103
expect_equal( DataFrame_PushBackDataFrame(), df )
104+
105+
# test.DataFrame.PushWrongSize <- function(){
106+
df <- data.frame( u = c(0, 0), v = c(0, 0), w = c(0, 0), x = c(0, 0) )
107+
expect_warning( DataFrame_PushWrongSize() )
108+
109+
# test.DataFrame.PushReplicateLength <- function(){
110+
df <- data.frame( u = c(1, 0), v = c(0, 0, 0, 0), x = c(2) )
111+
expect_true( is.data.frame( DataFrame_PushReplicateLength() ) )
112+
expect_equal( DataFrame_PushReplicateLength(), df )

0 commit comments

Comments
 (0)