//
// To build with g++ 4.5 or later, use the -std=c++0x option
//
// Enable this macro definition to improve performance when running in Microsoft Debug mode
//
//#define _ITERATOR_DEBUG_LEVEL 0
#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <map>
#include <vector>
#include <ctime>

namespace std {
template<>
struct hash<string const *>
{
inline size_t operator()(string const *p) const
{
    return std::hash<string>()(*p);
}
};

template<>
struct equal_to<string const *>
{
inline bool operator()( std::string const *p1, std::string const *p2 ) const
{
    return *p1 == *p2;
}
};

template<>
struct less<string const *>
{
inline bool operator()( std::string const *p1, std::string const *p2 ) const
{
    return *p1 < *p2;
}
};

}

template<class CONTAINER, class DATA>
void test( const DATA &data, const char *test_name )
{
    std::cout << "Testing container: " << test_name << std::endl;
//
// Microsoft debug mode is so slow that 2 passes is as much
// as I can take.
//
#ifdef _DEBUG
    const int passes = 2;
#else
    const int passes = 10;
#endif
    double fill_times = 0;
    double delete_times = 0;
    size_t entries;
    for ( int i = 0 ; i < passes ; i++ ) {
        CONTAINER *container = new CONTAINER();
        std::cout << "Filling... " << std::flush;
        clock_t t0 = clock();
        for ( auto ii = data.begin() ; ii != data.end() ; ii++ ) 
            (*container)[*ii]++;
        double span = double(clock() - t0)/CLOCKS_PER_SEC;
        fill_times += span;
        entries = container->size();
        std::cout << " " << span << " Deleting... " << std::flush;
        t0 = clock();
        delete container;
        span = double(clock() - t0)/CLOCKS_PER_SEC;
        delete_times += span;
        std::cout << span << " " << std::endl;
    }
    std::cout << "Entries: " << entries 
              << ", Fill time: " << (fill_times/passes) 
              << ", Delete time: " << (delete_times/passes) 
              << std::endl;
}

int main(int argc, char* argv[])
{
    std::vector<std::string> bank;
    std::vector<std::string*> pbank;
    std::string s;
    std::ifstream input("cia.txt");
    bank.reserve(2000000);
    int i = 0;
    while ( input >> s ) {
        bank.push_back( s );
    }
    std::ifstream input2("bible.txt");
    while ( input2 >> s ) 
        bank.push_back( s );
    bank.resize(1000000);
    for ( auto ii = bank.begin() ; ii != bank.end() ; ii++ )
        pbank.push_back( &(*ii) );
    std::cout << "Read in " << bank.size() << " strings" << std::endl;
    test<std::unordered_map<std::string,int> >( bank, "unordered_map<string>" );
    test<std::unordered_map<std::string const *,int> >( pbank, "unordered_map<string *>" );
    test<std::map<std::string,int> >( bank, "map<string>" );
    test<std::map<std::string const *,int> >( pbank, "map<string *>" );
    std::cout << "Hit enter to exit..." << std::flush;
    std::cin.ignore( 1, '\n' );
	return 0;
}


