Example #1
0
List rbind__impl( Dots dots, SEXP id = R_NilValue ){
    int ndata = dots.size() ;
    int n = 0 ;
    DataFrameAbleVector chunks ;
    std::vector<int> df_nrows ;

    int k=0 ;
    for( int i=0; i<ndata; i++) {
      SEXP obj = dots[i] ;
      if( Rf_isNull(obj) ) continue ;
      chunks.push_back( obj ) ;
      int nrows = chunks[k].nrows() ;
      df_nrows.push_back(nrows) ;
      n += nrows ;
      k++ ;
    }
    ndata = chunks.size() ;
    pointer_vector<Collecter> columns ;

    std::vector<String> names ;

    k=0 ;
    Function enc2native( "enc2native" ) ;
    for( int i=0; i<ndata; i++){
        Rcpp::checkUserInterrupt() ;

        const DataFrameAble& df = chunks[i] ;
        if( !df.size() ) continue ;

        int nrows = df.nrows() ;

        CharacterVector df_names = enc2native(df.names()) ;
        for( int j=0; j<df.size(); j++){
            SEXP source = df.get(j) ;
            String name = df_names[j] ;

            Collecter* coll = 0;
            size_t index = 0 ;
            for( ; index < names.size(); index++){
                if( name == names[index] ){
                    coll = columns[index] ;
                    break ;
                }
            }
            if( ! coll ){
                coll = collecter( source, n ) ;
                columns.push_back( coll );
                names.push_back(name) ;
            }
            if( coll->compatible(source) ){
                // if the current source is compatible, collect
                coll->collect( SlicingIndex( k, nrows), source ) ;

            } else if( coll->can_promote(source) ) {
                // setup a new Collecter
                Collecter* new_collecter = promote_collecter(source, n, coll ) ;

                // import data from this chunk
                new_collecter->collect( SlicingIndex( k, nrows), source ) ;

                // import data from previous collecter
                new_collecter->collect( SlicingIndex(0, k), coll->get() ) ;

                // dispose the previous collecter and keep the new one.
                delete coll ;
                columns[index] = new_collecter ;

            } else if( all_na(source) ) {
                // do nothing, the collecter already initialized data with the
                // right NA
            } else if( coll->is_logical_all_na()  ) {
                Collecter* new_collecter = collecter( source, n ) ;
                new_collecter->collect( SlicingIndex(k, nrows), source ) ;
                delete coll ;
                columns[index] = new_collecter ;
            } else {
                std::string column_name(name) ;
                stop(
                  "Can not automatically convert from %s to %s in column \"%s\".",
                  coll->describe(), get_single_class(source), column_name
                ) ;
            }

        }

        k += nrows ;
    }

    int nc = columns.size() ;
    int has_id = Rf_isNull(id) ? 0 : 1;

    List out(nc + has_id) ;
    CharacterVector out_names(nc + has_id) ;
    for( int i=0; i<nc; i++){
        out[i + has_id] = columns[i]->get() ;
        out_names[i + has_id] = names[i] ;
    }

    // Add vector of identifiers if .id is supplied
    if (!Rf_isNull(id)) {
      CharacterVector df_names = dots.names() ;
      CharacterVector id_col = no_init(n) ;

      CharacterVector::iterator it = id_col.begin() ;
      for (int i=0; i<ndata; ++i) {
        std::fill( it, it + df_nrows[i], df_names[i] ) ;
        it += df_nrows[i] ;
      }
      out[0] = id_col ;
      out_names[0] = Rcpp::as<std::string>(id) ;
    }
    out.attr( "names" ) = out_names ;
    set_rownames( out, n ) ;

    // infer the classes and extra info (groups, etc ) from the first (#1692)
    if( ndata ){
      const DataFrameAble& first = chunks[0] ;
      if( first.is_dataframe() ){
        DataFrame df = first.get() ;
        out.attr("class") = df.attr("class") ;
        if( df.inherits("grouped_df") ){
          out.attr("vars") = df.attr("vars") ;
          out = GroupedDataFrame(out).data() ;
        }
      } else {
        out.attr( "class" ) = classes_not_grouped() ;
      }
    } else {
      out.attr( "class" ) = classes_not_grouped() ;
    }

    return out ;
}