diff -urpN geant4.9.5.p01/source/processes/hadronic/cross_sections/GNUmakefile geant4.9.5.p01-new/source/processes/hadronic/cross_sections/GNUmakefile
--- geant4.9.5.p01/source/processes/hadronic/cross_sections/GNUmakefile	2012-03-27 10:44:51.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/cross_sections/GNUmakefile	2012-09-07 21:07:15.867842792 +0300
@@ -11,7 +11,7 @@ endif
 
 include $(G4INSTALL)/config/architecture.gmk
 
-CPPFLAGS += -DG4HADRONIC_ALLOC_EXPORT
+CPPFLAGS += -DG4HADRONIC_ALLOC_EXPORT -std=c++0x
 CPPFLAGS += -I$(G4BASE)/global/management/include \
             -I$(G4BASE)/global/HEPRandom/include \
             -I$(G4BASE)/global/HEPGeometry/include \
diff -urpN geant4.9.5.p01/source/processes/hadronic/cross_sections/include/G4CrossSectionDataStore.hh geant4.9.5.p01-new/source/processes/hadronic/cross_sections/include/G4CrossSectionDataStore.hh
--- geant4.9.5.p01/source/processes/hadronic/cross_sections/include/G4CrossSectionDataStore.hh	2012-03-27 10:44:50.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/cross_sections/include/G4CrossSectionDataStore.hh	2012-09-07 21:07:15.868870562 +0300
@@ -37,7 +37,7 @@
 //              by G. Folger, V. Ivantchenko, T. Koi and D.H. Wright
 
 // Class Description
-// This is the class to which cross section data sets may be registered. 
+// This is the class to which cross section data sets may be registered.
 // An instance of it is contained in each hadronic process, allowing
 // the use of the AddDataSet() method to tailor the cross sections to
 // your application.
@@ -48,34 +48,80 @@
 
 #include "globals.hh"
 #include "G4VCrossSectionDataSet.hh"
+
+#include "G4DynamicParticle.hh"
+#include "G4Material.hh"
+
 #include <vector>
+#include <unordered_map>
+#include <tuple>
+#include <cstdint>
 
 class G4Nucleus;
-class G4DynamicParticle;
+//class G4DynamicParticle;
 class G4ParticleDefinition;
 class G4Isotope;
 class G4Element;
-class G4Material;
+//class G4Material;
 class G4NistManager;
 
+typedef std::tuple<const G4DynamicParticle *, const G4Material *, uint64_t> TPartMat;
+typedef std::pair<double, int> THitCount;
+
+namespace std {
+	template <>
+	class hash<TPartMat> {
+	public:
+		size_t operator()(const TPartMat &x) const {
+			// Taken by pere@
+			size_t res = 0;
+			size_t len = sizeof(x);
+			const int *p = reinterpret_cast<const int *>(&x);
+			while(len) {
+				res = (res << 1) ^ *p; ++p; len -=sizeof(int);
+			}
+			return res;
+		}
+	};
+}
+
+struct pairEquals : public std::binary_function<const TPartMat&,
+						const TPartMat&,
+						bool>
+{
+	result_type operator()(first_argument_type  lhs,
+			       second_argument_type rhs) const
+	{
+		return ((std::get<0>(lhs) == std::get<0>(rhs)) &&
+			(std::get<1>(lhs) == std::get<1>(rhs)) &&
+			(std::get<2>(lhs) == std::get<2>(rhs)));
+	}
+};
+
 class G4CrossSectionDataStore
 {
 public:
-
   G4CrossSectionDataStore();
 
   ~G4CrossSectionDataStore();
 
+  void printArray(void) const;
+  void printStats(void) const;
+
+  G4String ownerName;
+  void SetOwnerName(const G4String &name) { this->ownerName = name; }
+
   // Cross section per unit volume is computed (inverse mean free path)
+  G4double MyGetCrossSection(const G4DynamicParticle*, const G4Material*);
   G4double GetCrossSection(const G4DynamicParticle*, const G4Material*);
 
   // Cross section per element is computed
-  G4double GetCrossSection(const G4DynamicParticle*, 
+  G4double MyGetCrossSection(const G4DynamicParticle*,
 			   const G4Element*, const G4Material*);
 
   // Cross section per isotope is computed
-  G4double GetCrossSection(const G4DynamicParticle*, G4int Z, G4int A,
-                           const G4Isotope*,
+  G4double MyGetCrossSection(const G4DynamicParticle*, G4int Z, G4int A,
+			   const G4Isotope*,
 			   const G4Element*, const G4Material*);
 
   // Sample Z and A of a target nucleus and upload into G4Nucleus
@@ -112,6 +158,11 @@ private:
   std::vector<G4double> xseciso;
   G4int nDataSetList;
   G4int verboseLevel;
+
+  std::unordered_map<TPartMat, THitCount, std::hash<TPartMat>, pairEquals> mymap;
+  size_t hits;
+  size_t misses;
+  size_t mismatch;
 };
 
 inline void G4CrossSectionDataStore::AddDataSet(G4VCrossSectionDataSet* p)
diff -urpN geant4.9.5.p01/source/processes/hadronic/cross_sections/src/G4CrossSectionDataStore.cc geant4.9.5.p01-new/source/processes/hadronic/cross_sections/src/G4CrossSectionDataStore.cc
--- geant4.9.5.p01/source/processes/hadronic/cross_sections/src/G4CrossSectionDataStore.cc	2012-03-27 10:44:51.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/cross_sections/src/G4CrossSectionDataStore.cc	2012-09-07 21:58:12.597420277 +0300
@@ -52,37 +52,202 @@
 #include "G4Material.hh"
 #include "G4NistManager.hh"
 #include <iostream>
+#include <limits>
 
 
+#define likely(x)       __builtin_expect((x), 1)
+#define unlikely(x)     __builtin_expect((x), 0)
+#define abs(x) ((x) > 0 ? (x) : -(x))
+
 G4CrossSectionDataStore::G4CrossSectionDataStore() :
-  nDataSetList(0), verboseLevel(0)
+	nDataSetList(0), verboseLevel(0)
 {
-  nist = G4NistManager::Instance();
+	nist = G4NistManager::Instance();
+
+	xsecelm.reserve(20);
+	xseciso.reserve(20);
+	
+	hits     = 0;
+	misses   = 0;
+	mismatch = 0;
+
+	mymap.reserve(2 * 1024 * 1024);
 }
 
 G4CrossSectionDataStore::~G4CrossSectionDataStore()
-{}
+{
+	mymap.clear();
+}
+
+void
+G4CrossSectionDataStore::printArray(void) const
+{
+	std::unordered_map<TPartMat, THitCount>::const_iterator it;
+
+	for (it  = mymap.begin();
+	     it != mymap.end();
+	     it++) {
+		G4cout  
+		       << it->second.first  << " "
+		       << it->second.second << G4endl;
+	}
+	G4cout << G4endl;
+
+#if 0
+	// Enable code block to detect unusually high number of collisions
+	// inside the hash map
+	double sum = 0.0;
+	for (int i = 0; i < mymap.size(); i++) {
+		if (mymap.bucket_size(i) > 2)
+			G4cout << "i=" << i
+			       << " size=" << mymap.bucket_size(i)
+			       << G4endl;
+	}
+#endif
+}
+
+void
+G4CrossSectionDataStore::printStats(void) const
+{
+	G4cout << "parent="	      << this->ownerName << "(" << this << ")"
+	       << " Mismatch="	      << mismatch
+	       << " Hits="	      << hits
+	       << " Misses="	      << misses
+	       << " load_factor="     << mymap.load_factor()
+	       << " max_load_factor=" << mymap.max_load_factor()
+	       << " size()=" << mymap.size()
+	       << G4endl;
+}
 
 G4double
 G4CrossSectionDataStore::GetCrossSection(const G4DynamicParticle* part,
+					 const G4Material* mat)
+{
+	union {
+		double d;
+		uint64_t i;
+	} uDoubleInt;
+
+	uDoubleInt.d  = part->GetKineticEnergy();
+	uDoubleInt.i &= 0xFFFFFF0000000000;	// Keep only 12 bits of decimal part
+
+	std::tuple<const G4DynamicParticle *,
+		   const G4Material *, uint64_t>
+	    partmat(part, mat, uDoubleInt.d);
+
+#if 0
+	// Dumps some statistics once every while
+	static unsigned long cnt = 0;
+	if (unlikely(++cnt % 0xFFFFF == 0)) {
+		printArray();
+		printStats();
+	}
+#endif
+
+	if (mymap.count(partmat) > 0) {
+		double rv =  mymap[partmat].first;
+		mymap[partmat].second++;
+#if 0
+		// Enable code block to check whether a result returned by
+		// the cache is correct (equals the result that we would have
+		// come up with, if we had done the calculation)
+		// HINT: change the epsilon value, depending on how many decimal
+		// digits we keep, when doing the bin'ing of energy
+		double rv2 = MyGetCrossSection(part, mat);
+		if (abs(rv - rv2) > 0.0001) {
+			++mismatch;
+			G4cout << "[FET] parent=" << this
+			       << " part="	  << part
+			       << " mat="	  << mat
+			       << " rv(wro)="	  << rv		// wrong value
+			       << G4endl;
+
+                        G4cout << "[FET] parent=" << this
+			       << " part="	  << part
+			       << " mat="	  << mat
+			       << " rv(cor)="	  << rv2	// correct value
+			       << G4endl;
+
+			return rv2;
+		}
+#endif
+		++hits;
+		return rv;
+	} else {
+		++misses;
+		double rv = MyGetCrossSection(part, mat);
+
+		// If the map has been overwhelmed by data, discard all of them
+		// except for those that have been hit a lot of times
+		// The higher the threshold T, more aggressive the purge (here T=10)
+		if (unlikely(mymap.load_factor() > 0.95)) {
+			std::unordered_map<TPartMat, THitCount>::const_iterator it;
+			G4cout << "EMERGENCY CLEARING" << G4endl;
+
+			for (it  = mymap.begin();
+			     it != mymap.end();
+			     it++) {
+				if (it->second.second < 10) {
+					mymap.erase(it);
+				}
+			}
+
+		}
+
+		// As it came up by the analysis of the cross-section values,
+		// most of the values returned are zero. Therefore, cache only
+		// those keys, for which a cross section calculation would end
+		// up in a zero value
+		if (rv == 0.0) {
+			std::pair<double, int> rvpair(rv, 1);
+			mymap[partmat] = rvpair;
+		}
+#if 0
+		G4cout << "[INS] parent=" << this
+		       << " part="	  << part
+		       << " mat="	  << mat
+		       << " rv="	  << mymap[partmat]
+		       << G4endl;
+#endif
+		return rv;
+	}
+}
+
+G4double
+G4CrossSectionDataStore::MyGetCrossSection(const G4DynamicParticle* part,
                                          const G4Material* mat)
 {
-  G4double sigma(0);
-  G4int nElements = mat->GetNumberOfElements();
-  const G4double* nAtomsPerVolume = mat->GetVecNbOfAtomsPerVolume();
+	G4double sigma(0);
+	G4int nElements			= mat->GetNumberOfElements();
+	const G4double* nAtomsPerVolume = mat->GetVecNbOfAtomsPerVolume();
 
-  if(G4int(xsecelm.size()) < nElements) { xsecelm.resize(nElements); }
+	if (unlikely(G4int(xsecelm.capacity()) < nElements)) {
+		xsecelm.resize(nElements);
+	}
 
-  for(G4int i=0; i<nElements; ++i) {
-    sigma += nAtomsPerVolume[i] * 
-      GetCrossSection(part, (*mat->GetElementVector())[i], mat);
-    xsecelm[i] = sigma;
-  }
-  return sigma;
+	for (G4int i = 0; i < nElements; ++i) {
+		sigma += nAtomsPerVolume[i] * 
+		    MyGetCrossSection(part, (*mat->GetElementVector())[i], mat);
+		xsecelm[i] = sigma;
+	}
+
+	// Uncomment the following line, so the the result (read: sigma),
+	// is copied into the EAX, EDX registers. It helps to be able to
+	// aggregate the results with DTrace, by doing something like:
+	//
+	// dtrace 'pid$target::*MyGetCrossSection*:return
+	// {
+	//	@[uregs[R_EAX], uregs[R_EDX]] = count();
+	// } -c '/path/to/simulation/binary ./bachfile' -o uregs.cross
+	//
+
+	//	__asm__ __volatile__ ("" : : "A" (*(&sigma)));
+
+	return sigma;
 }
 
 G4double
-G4CrossSectionDataStore::GetCrossSection(const G4DynamicParticle* part,
+G4CrossSectionDataStore::MyGetCrossSection(const G4DynamicParticle* part,
                                          const G4Element* elm,
 					 const G4Material* mat)
 {
@@ -168,7 +333,7 @@ G4CrossSectionDataStore::GetIsoCrossSect
 }
 
 G4double
-G4CrossSectionDataStore::GetCrossSection(const G4DynamicParticle* part,
+G4CrossSectionDataStore::MyGetCrossSection(const G4DynamicParticle* part,
                                          G4int Z, G4int A,
 					 const G4Isotope* iso,
                                          const G4Element* elm,
@@ -203,7 +368,7 @@ G4CrossSectionDataStore::SampleZandA(con
 
   // select element from a compound 
   if(1 < nElements) {
-    G4double cross = G4UniformRand()*GetCrossSection(part, mat);
+    G4double cross = G4UniformRand()*MyGetCrossSection(part, mat);
     for(G4int i=0; i<nElements; ++i) {
       if(cross <= xsecelm[i]) {
 	anElement = (*theElementVector)[i];
@@ -280,7 +445,7 @@ G4CrossSectionDataStore::SampleZandA(con
       // more than 1 isotope
       if(1 < nIso) {
 	G4double* abundVector = anElement->GetRelativeAbundanceVector();
-	if(G4int(xseciso.size()) < nIso) { xseciso.resize(nIso); }
+	if(unlikely(G4int(xseciso.capacity()) < nIso)) { xseciso.resize(nIso); }
 
 	for (G4int j = 0; j<nIso; ++j) {
 	  xsec = 0.0;
@@ -309,7 +474,7 @@ G4CrossSectionDataStore::SampleZandA(con
 
       // more than 1 isotope
       if(1 < nn) {
-	if(G4int(xseciso.size()) < nn) { xseciso.resize(nn); }
+	if(unlikely(G4int(xseciso.capacity()) < nn)) { xseciso.resize(nn); }
 	for (G4int j = 0; j < nn; ++j) {
 	  xsec = 0.0;
 	  A = n0 + j;
diff -urpN geant4.9.5.p01/source/processes/hadronic/management/include/G4HadronicProcess.hh geant4.9.5.p01-new/source/processes/hadronic/management/include/G4HadronicProcess.hh
--- geant4.9.5.p01/source/processes/hadronic/management/include/G4HadronicProcess.hh	2012-03-27 10:46:08.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/management/include/G4HadronicProcess.hh	2012-09-07 21:07:15.872406610 +0300
@@ -84,7 +84,7 @@ public:
 				  const G4Element * elm, 
 				  const G4Material* mat = 0)
   {
-    G4double x = theCrossSectionDataStore->GetCrossSection(part, elm, mat);
+    G4double x = theCrossSectionDataStore->MyGetCrossSection(part, elm, mat);
     if(x < 0.0) { x = 0.0; }
     return x;
   }
diff -urpN geant4.9.5.p01/source/processes/hadronic/management/src/G4HadronicProcess.cc geant4.9.5.p01-new/source/processes/hadronic/management/src/G4HadronicProcess.cc
--- geant4.9.5.p01/source/processes/hadronic/management/src/G4HadronicProcess.cc	2012-03-27 10:46:09.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/management/src/G4HadronicProcess.cc	2012-09-07 21:07:15.873367552 +0300
@@ -160,6 +160,9 @@ void G4HadronicProcess::PreparePhysicsTa
 void G4HadronicProcess::BuildPhysicsTable(const G4ParticleDefinition& p)
 {
   theCrossSectionDataStore->BuildPhysicsTable(p);
+  // Needed by G4CrossSectionDatasStore to map cache maps and hadronic processes
+  theCrossSectionDataStore->SetOwnerName(
+	  GetProcessName() + "~" + p.GetParticleName());
   G4HadronicProcessStore::Instance()->PrintInfo(&p);
 }
 
diff -urpN geant4.9.5.p01/source/processes/hadronic/models/chiral_inv_phase_space/body/src/G4QEnvironment.cc geant4.9.5.p01-new/source/processes/hadronic/models/chiral_inv_phase_space/body/src/G4QEnvironment.cc
--- geant4.9.5.p01/source/processes/hadronic/models/chiral_inv_phase_space/body/src/G4QEnvironment.cc	2012-03-27 10:45:52.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/models/chiral_inv_phase_space/body/src/G4QEnvironment.cc	2012-09-07 21:55:02.758765161 +0300
@@ -61,6 +61,7 @@
 #include "G4QEnvironment.hh" 
 #include <cmath>
 #include <cstdlib>
+
 using namespace std;
 
 G4QEnvironment::G4QEnvironment(const G4QNucleus& theEnv)
diff -urpN geant4.9.5.p01/source/processes/hadronic/models/coherent_elastic/src/G4ChargeExchangeProcess.cc geant4.9.5.p01-new/source/processes/hadronic/models/coherent_elastic/src/G4ChargeExchangeProcess.cc
--- geant4.9.5.p01/source/processes/hadronic/models/coherent_elastic/src/G4ChargeExchangeProcess.cc	2012-03-27 10:46:01.000000000 +0300
+++ geant4.9.5.p01-new/source/processes/hadronic/models/coherent_elastic/src/G4ChargeExchangeProcess.cc	2012-09-07 21:07:16.097155090 +0300
@@ -147,7 +147,7 @@ G4double G4ChargeExchangeProcess::GetEle
     G4cout << "G4ChargeExchangeProcess compute GHAD CS for element "
 	   << elm->GetName()
 	   << G4endl;
-  x = store->GetCrossSection(dp, elm, mat);
+  x = store->MyGetCrossSection(dp, elm, mat);
 
   if(verboseLevel>1)
     G4cout << "G4ChargeExchangeProcess cross(mb)= " << x/millibarn
