Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision 6a5f0e7dfb84bde161ef99c4d0e14d90d0266007)
+++ src/CodeTools/DeclStats.cc	(revision 424931dd6af68222c4b2549fae5ee43f3791bd72)
@@ -31,4 +31,67 @@
 	
 	class DeclStats : public Visitor {
+		template<typename T>
+		static void sum(T& a, const T& b) { a += b; }
+
+		static void sum(VectorMap<unsigned>& a, const VectorMap<unsigned>& b) {
+			a.reserve( b.size() );
+			for ( unsigned i = 0; i < b.size(); ++i ) {
+				a[i] += b[i];
+			}
+		}
+
+		template<typename K>
+		static void sum(std::map<K, unsigned>& a, const std::map<K, unsigned>& b) {
+			for ( const auto& entry : b ) {
+				a[ entry.first ] += entry.second;
+			}
+		}
+
+		template<typename K>
+		static void sum(std::unordered_map<K, unsigned>& a, const std::unordered_map<K, unsigned>& b) {
+			for ( const auto& entry : b ) {
+				a[ entry.first ] += entry.second;
+			}
+		}
+
+		struct ArgPackStats {
+			VectorMap<unsigned> n;                 ///< Count of decls with each number of elements
+			VectorMap<unsigned> n_basic;           ///< Count of decls with each number of basic type elements
+			VectorMap<unsigned> n_poly;            ///< Count of decls with each number of polymorphic elements
+			std::map<unsigned, unsigned> p_basic;  ///< Count of decls with each percentage of basic type elements
+			std::map<unsigned, unsigned> p_poly;   ///< Count of decls with each percentage of polymorphic elements
+
+			ArgPackStats& operator+= (const ArgPackStats& o) {
+				sum(n, o.n);
+				sum(n_basic, o.n_basic);
+				sum(n_poly, o.n_poly);
+				sum(p_basic, o.p_basic);
+				sum(p_poly, o.p_poly);
+				
+				return *this;
+			}
+
+			/// Update based on a declaration list
+			ArgPackStats& operator+= ( std::list<DeclarationWithType*>& decls ) {
+				unsigned nn = 0;
+				unsigned nn_basic = 0;
+				unsigned nn_poly = 0;
+				for ( auto decl : decls ) {
+					nn += decl->get_type()->size();
+					if ( dynamic_cast<BasicType*>( decl->get_type() ) ) ++nn_basic;
+					else if ( GenPoly::hasPolyBase( decl->get_type() ) ) ++nn_poly;
+				}
+				++n.at( nn );
+				++n_basic.at( nn_basic );
+				++n_poly.at( nn_poly );
+				if ( nn > 0 ) {
+					++p_basic[ nn_basic*100/nn ];
+					++p_poly[ nn_poly*100/nn ];
+				}
+				
+				return *this;
+			}
+		};
+		
 		struct Stats {
 			unsigned n_decls;     ///< Total number of declarations
@@ -37,62 +100,17 @@
 			/// Count of declarations with each name
 			std::unordered_map<std::string, unsigned> by_name;
-
-			/// Count of declarations with each number of parameters
-			VectorMap<unsigned> n_params;
-			/// Count of declarations with each number of return types
-			VectorMap<unsigned> n_returns;
-			/// Count of declarations with each number of polymorphic parameters
-			VectorMap<unsigned> n_poly_params;
-			/// Count of declarations with each number of polymorphic return types
-			VectorMap<unsigned> n_poly_returns;
-			/// Count of declarations with each percentage of polymorphic parameters
-			std::map<unsigned, unsigned> p_poly_params;
-			/// Count of declarations with each percentage of polymorphic returns
-			std::map<unsigned, unsigned> p_poly_returns;
-
+			/// Stats for the parameter list
+			ArgPackStats params;
+			/// Stats for the return list
+			ArgPackStats returns;
+			
 			/// Count of declarations with each number of assertions
-			std::map<unsigned, unsigned> n_assertions;
-			/// Count of assertions with each number of parameters
-			VectorMap<unsigned> n_assn_params;
-			/// Count of assertions with each number of return types
-			VectorMap<unsigned> n_assn_returns;
-			/// Count of assertions with each number of polymorphic parameters
-			VectorMap<unsigned> n_assn_poly_params;
-			/// Count of assertions with each number of polymorphic return types
-			VectorMap<unsigned> n_assn_poly_returns;
-			/// Count of assertions with each percentage of polymorphic parameters
-			std::map<unsigned, unsigned> p_assn_poly_params;
-			/// Count of assertions with each percentage of polymorphic returns
-			std::map<unsigned, unsigned> p_assn_poly_returns;
-
-			Stats()
-				: n_decls(0), n_type_params(), by_name(),
-				  n_params(), n_returns(), n_poly_params(), n_poly_returns(), p_poly_params(), p_poly_returns(),
-				  n_assertions(), n_assn_params(), n_assn_returns(), n_assn_poly_params(), n_assn_poly_returns(), p_assn_poly_params(), p_assn_poly_returns() {}
-
-		private:
-			template<typename T>
-			static void sum(T& a, const T& b) { a += b; }
-
-			static void sum(VectorMap<unsigned>& a, const VectorMap<unsigned>& b) {
-				a.reserve( b.size() );
-				for ( unsigned i = 0; i < b.size(); ++i ) {
-					a[i] += b[i];
-				}
-			}
-
-			template<typename K>
-			static void sum(std::map<K, unsigned>& a, const std::map<K, unsigned>& b) {
-				for ( const auto& entry : b ) {
-					a[ entry.first ] += entry.second;
-				}
-			}
-
-			template<typename K>
-			static void sum(std::unordered_map<K, unsigned>& a, const std::unordered_map<K, unsigned>& b) {
-				for ( const auto& entry : b ) {
-					a[ entry.first ] += entry.second;
-				}
-			}
+			std::map<unsigned, unsigned> n_assns;
+			/// Stats for the assertions' parameters
+			ArgPackStats assn_params;
+			/// Stats for the assertions' return types
+			ArgPackStats assn_returns;
+			
+			Stats() : n_decls(0), n_type_params(), by_name(), params(), returns(), n_assns(), assn_params(), assn_returns() {}
 
 		public:
@@ -101,20 +119,10 @@
 				sum( n_type_params, o.n_type_params );
 				sum( by_name, o.by_name );
+				sum( params, o.params );
+				sum( returns, o.returns );
+				sum( n_assns, o.n_assns );
+				sum( assn_params, o.assn_params );
+				sum( assn_returns, o.assn_returns );
 				
-				sum( n_params, o.n_params );
-				sum( n_returns, o.n_returns );
-				sum( n_poly_params, o.n_poly_params );
-				sum( n_poly_returns, o.n_poly_returns );
-				sum( p_poly_params, o.p_poly_params );
-				sum( p_poly_returns, o.p_poly_returns );
-
-				sum( n_assertions, o.n_assertions );
-				sum( n_assn_params, o.n_assn_params );
-				sum( n_assn_returns, o.n_assn_returns );
-				sum( n_assn_poly_params, o.n_assn_poly_params );
-				sum( n_assn_poly_returns, o.n_assn_poly_returns );
-				sum( p_assn_poly_params, o.p_assn_poly_params );
-				sum( p_assn_poly_returns, o.p_assn_poly_returns );
-
 				return *this;
 			}
@@ -125,26 +133,7 @@
 		Stats total;
 
-		void analyzeFunc( FunctionType* fnTy, VectorMap<unsigned>& by_params, VectorMap<unsigned>& by_poly_params,
-		                  VectorMap<unsigned>& by_returns, VectorMap<unsigned>& by_poly_returns,
-		                  std::map<unsigned, unsigned>& p_poly_params, std::map<unsigned, unsigned>& p_poly_returns ) {
-			unsigned n_params = 0;
-			unsigned n_poly_params = 0;
-			for ( auto pdecl : fnTy->get_parameters() ) {
-				n_params += pdecl->get_type()->size();
-				if ( GenPoly::hasPolyBase( pdecl->get_type() ) ) ++n_poly_params;
-			}
-			++by_params.at( n_params );
-			++by_poly_params.at( n_poly_params );
-			if ( n_params > 0 ) ++p_poly_params[ n_poly_params*100/n_params ];
-
-			unsigned n_returns = 0;
-			unsigned n_poly_returns = 0;
-			for ( auto rdecl : fnTy->get_returnVals() ) {
-				n_returns += rdecl->get_type()->size();
-				if ( GenPoly::hasPolyBase( rdecl->get_type() ) ) ++n_poly_returns;
-			}
-			++by_returns.at( n_returns );
-			++by_poly_returns.at( n_poly_returns );
-			if ( n_returns > 0 ) ++p_poly_returns[ n_poly_returns*100/n_returns ];
+		void analyzeFunc( FunctionType* fnTy, ArgPackStats& params, ArgPackStats& returns ) {
+			params += fnTy->get_parameters();
+			returns += fnTy->get_returnVals();
 		}
 
@@ -163,7 +152,7 @@
 			const Type::ForallList& forall = fnTy->get_forall();
 			++stats.n_type_params.at( forall.size() );
-			unsigned n_assertions = 0;
+			unsigned n_assns = 0;
 			for ( TypeDecl* fdecl : forall ) {
-				n_assertions += fdecl->get_assertions().size();
+				n_assns += fdecl->get_assertions().size();
 				for ( DeclarationWithType* assn : fdecl->get_assertions() ) {
 					FunctionType *assnTy = 0;
@@ -175,19 +164,17 @@
 						assnTy = assnDecl->get_functionType();
 					}
-					if ( assnTy ) analyzeFunc( assnTy, stats.n_assn_params, stats.n_assn_poly_params, stats.n_assn_returns,
-					                           stats.n_assn_poly_returns, stats.p_assn_poly_params, stats.p_assn_poly_returns );
-				}
-			}
-			++stats.n_assertions[ n_assertions ];
+					if ( assnTy ) analyzeFunc( assnTy, stats.assn_params, stats.assn_returns );
+				}
+			}
+			++stats.n_assns[ n_assns ];
 
 			++stats.by_name[ decl->get_name() ];
 
-			analyzeFunc( fnTy, stats.n_params, stats.n_poly_params, stats.n_returns,
-			             stats.n_poly_returns, stats.p_poly_params, stats.p_poly_returns );
+			analyzeFunc( fnTy, stats.params, stats.returns );
 		}
 
 	private:
 		template<typename F>
-		void printAll( const char* name, F extract ) {
+		void printAll( const std::string& name, F extract ) {
 			std::cout << "\"" << name << "\",";
 			for ( const auto& stats : for_linkage ) {
@@ -198,5 +185,5 @@
 
 		template<typename F>
-		void printAllMap( const char* name, F extract ) {
+		void printAllMap( const std::string& name, F extract ) {
 			for ( const auto& entry : extract(total) ) {
 				const auto& key = entry.first;
@@ -213,5 +200,5 @@
 
 		template<typename F>
-		void printAllHisto( const char* name, F extract ) {
+		void printAllHisto( const std::string& name, F extract ) {
 			VectorMap<unsigned> histos[LinkageSpec::NoOfSpecs];
 			VectorMap<unsigned> thisto;
@@ -236,5 +223,5 @@
 
 		template<typename F>
-		void printAllSparseHisto( const char* name, F extract ) {
+		void printAllSparseHisto( const std::string& name, F extract ) {
 			std::map<unsigned, unsigned> histos[LinkageSpec::NoOfSpecs];
 			std::map<unsigned, unsigned> thisto;
@@ -257,4 +244,13 @@
 			}
 		}
+
+		template<typename F>
+		void printAllPack( const std::string& name, F extract ) {
+			printAllMap("n_basic_" + name, [&extract](const Stats& stats) { return extract(stats).n_basic; });
+			printAllMap("n_poly_" + name, [&extract](const Stats& stats) { return extract(stats).n_poly; });
+			printAllMap("n_" + name, [&extract](const Stats& stats) { return extract(stats).n; });
+			printAllMap("%_basic_" + name, [&extract](const Stats& stats) { return extract(stats).p_basic; });
+			printAllMap("%_poly_" + name, [&extract](const Stats& stats) { return extract(stats).p_poly; });
+		}
 		
 	public:
@@ -270,19 +266,9 @@
 			printAll("unique_names", [](const Stats& stats) { return stats.by_name.size(); });
 			printAllSparseHisto("overloads", [](const Stats& stats) { return stats.by_name; });
-			
-			printAllMap("n_poly_params", [](const Stats& stats) { return stats.n_poly_params; });
-			printAllMap("n_params", [](const Stats& stats) { return stats.n_params; });
-			printAllMap("%_poly_params", [](const Stats& stats) { return stats.p_poly_params; });
-			printAllMap("n_poly_returns", [](const Stats& stats) { return stats.n_poly_returns; });
-			printAllMap("n_returns", [](const Stats& stats) { return stats.n_returns; });
-			printAllMap("%_poly_returns", [](const Stats& stats) { return stats.p_poly_returns; });
-
-			printAllMap("n_assertions", [](const Stats& stats) { return stats.n_assertions; });
-			printAllMap("n_assn_poly_params", [](const Stats& stats) { return stats.n_assn_poly_params; });
-			printAllMap("n_assn_params", [](const Stats& stats) { return stats.n_assn_params; });
-			printAllMap("%_assn_poly_params", [](const Stats& stats) { return stats.p_assn_poly_params; });
-			printAllMap("n_assn_poly_returns", [](const Stats& stats) { return stats.n_assn_poly_returns; });
-			printAllMap("n_assn_returns", [](const Stats& stats) { return stats.n_assn_returns; });
-			printAllMap("%_assn_poly_returns", [](const Stats& stats) { return stats.p_assn_poly_returns; });
+			printAllPack("params", [](const Stats& stats) { return stats.params; });
+			printAllPack("returns", [](const Stats& stats) { return stats.returns; });
+			printAllMap("n_assns", [](const Stats& stats) { return stats.n_assns; });
+			printAllPack("assn_params", [](const Stats& stats) { return stats.assn_params; });
+			printAllPack("assn_returns", [](const Stats& stats) { return stats.assn_returns; });
 		}
 	};
