// [[Rcpp::export]]
List make_index_parallel( DataFrame data, CharacterVector by ){
    
    int n = data.nrows() ;
    
    Visitors visitors(data, by) ;
    IndexMaker indexer(visitors) ;
    
    parallelReduce(0, n, indexer) ;
    
    return indexer.get() ;
}
// [[Rcpp::export]]
List detail_make_index_parallel( DataFrame data, CharacterVector by ){
    int n = data.nrows() ;
    Timers timers(n);
    
    Visitors visitors(data, by) ;  
    
    IndexMaker indexer(visitors) ;
    TimedReducer<IndexMaker, Timer, tbb::mutex, tbb::mutex::scoped_lock> timed_indexer(indexer, timers) ;
    
    parallelReduce(0, n, timed_indexer, 100) ;
    return timed_indexer.get() ;
    
}
// [[Rcpp::export]]
List make_index_concurrent_hash_map( DataFrame data, CharacterVector by ){
    
    int n = data.nrows() ;
    
    Visitors visitors(data, by) ;
    VisitorSetHasher<Visitors> hasher(visitors) ; 
    VisitorSetEqualPredicate<Visitors> equal(visitors) ;
    ConcurrentMap map(1024, hasher, equal) ;
    
    IndexMaker2 indexer(map) ;
    
    parallelFor(0, n, indexer) ;
    
    return indexer.get() ;
}
// [[Rcpp::export]]
List detail_make_index_concurrent_hash_map( DataFrame data, CharacterVector by ){
    Timer timer ;
    timer.step( "start" ) ;
    int n = data.nrows() ;
    
    Visitors visitors(data, by) ;
    VisitorSetHasher<Visitors> hasher(visitors) ; 
    VisitorSetEqualPredicate<Visitors> equal(visitors) ;
    ConcurrentMap map(1024, hasher, equal) ;
    
    IndexMaker2 indexer(map) ;
    
    parallelFor(0, n, indexer) ;
    timer.step( "train and join" ) ;
    
    List res = indexer.get() ;
    
    timer.step( "structure" ) ;
    
    return List::create( (SEXP)timer, res ) ;
}