// ==========================================================================
// $Id: stl_hashing.cpp,v 1.1 2014/11/14 22:59:57 jlang Exp $
// CSI2372 example Code for lecture 11
// ==========================================================================
// (C)opyright:
//
//   Jochen Lang
//   SITE, University of Ottawa
//   800 King Edward Ave.
//   Ottawa, On., K1N 6N5
//   Canada. 
//   http://www.site.uottawa.ca
// 
// Creator: jlang (Jochen Lang)
// Email:   jlang@site.uottawa.ca
// ==========================================================================
// $Log: stl_hashing.cpp,v $
// Revision 1.1  2014/11/14 22:59:57  jlang
// Fixed hashing code check-in
//
// ==========================================================================
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <unordered_map>

using std::cout;
using std::endl;
using std::string;
using std::multimap;
using std::unordered_map;
using std::unordered_multimap;

struct Id {
	std::string d_name;
  int d_id;
  // define the equal operator
  bool operator==(const Id& _oId ) const {
		return (	d_id == _oId.d_id && 
			d_name == _oId.d_name);
  }
  // define the hashing function
  size_t operator()( const Id& _id ) const {
  	// based on the std::hash operator; combined with XOR and bitshifting
  	return (std::hash<std::string>()(_id.d_name) ^
  	  std::hash<int>()(_id.d_id)<<1);
	}
};

// Alternative of specializing template
namespace std {
	template <> struct hash<Id> {
  	size_t operator()( const Id& _id ) const {
  		// based on the std::hash operator; combined with XOR and bitshifting
  		return (std::hash<std::string>()(_id.d_name) ^
  	  	std::hash<int>()(_id.d_id)>>1);
		}
	};
} // end of namespace std

int main() {
  // multimap with Id as key and string as value
  unordered_map<Id,string,Id> hMap {{{"Smith, John",31245},"This is a text."},
	{{"Doe, Jane",45672},"This is a short text"},{{"Doe, Jane",245876},"This is a long text"}};
	cout << "Content of hMap: " << endl;
  for ( auto hPair : hMap ) {
    cout << "Key: " << std::setw(8) << hPair.first.d_id << "   " << hPair.first.d_name << endl;
    cout << "Value: " << hPair.second << endl;
  }
  cout << "-------------------------------------------" << endl;
  // Now using the spezialization template
  unordered_map<Id,string> hSpecialMap( hMap.cbegin(), hMap.cend());
  cout << "Content of hSpecialMap: " << endl;
  for ( auto hPair : hSpecialMap ) {
    cout << "Key: " << std::setw(8) << hPair.first.d_id << "   " << hPair.first.d_name << endl;
    cout << "Value: " << hPair.second << endl;
  }
  return 0;  
}
