Allow custom reporters
diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h
index b2d34ad..de6c7b1 100644
--- a/include/benchmark/benchmark.h
+++ b/include/benchmark/benchmark.h
@@ -145,11 +145,13 @@
 #include "macros.h"
 
 namespace benchmark {
-// If the --benchmarks flag is empty, do nothing.
-//
-// Otherwise, run all benchmarks specified by the --benchmarks flag,
+class BenchmarkReporter;
+
+void Initialize(int* argc, const char** argv);
+
+// Otherwise, run all benchmarks specified by the --benchmark_filter flag,
 // and exit after running the benchmarks.
-extern void RunSpecifiedBenchmarks();
+void RunSpecifiedBenchmarks(const BenchmarkReporter* reporter = nullptr);
 
 // ------------------------------------------------------
 // Routines that can be called from within a benchmark
@@ -290,15 +292,73 @@
   DISALLOW_COPY_AND_ASSIGN(State);
 };
 
+// Interface for custom benchmark result printers.
+// By default, benchmark reports are printed to stdout. However an application
+// can control the destination of the reports by calling
+// RunSpecifiedBenchmarks and passing it a custom reporter object.
+// The reporter object must implement the following interface.
+class BenchmarkReporter {
+ public:
+  struct Context {
+    int num_cpus;
+    double mhz_per_cpu;
+    //std::string cpu_info;
+    bool cpu_scaling_enabled;
+
+    // The number of chars in the longest benchmark name.
+    int name_field_width;
+  };
+
+  struct Run {
+    Run() :
+        thread_index(-1),
+        iterations(1),
+        real_accumulated_time(0),
+        cpu_accumulated_time(0),
+        bytes_per_second(0),
+        items_per_second(0),
+        max_heapbytes_used(0) {}
+
+    std::string benchmark_name;
+    std::string report_label;
+    int thread_index;
+    int64_t iterations;
+    double real_accumulated_time;
+    double cpu_accumulated_time;
+
+    // Zero if not set by benchmark.
+    double bytes_per_second;
+    double items_per_second;
+
+    // This is set to 0.0 if memory tracing is not enabled.
+    double max_heapbytes_used;
+  };
+
+  // Called once for every suite of benchmarks run.
+  // The parameter "context" contains information that the
+  // reporter may wish to use when generating its report, for example the
+  // platform under which the benchmarks are running. The benchmark run is
+  // never started if this function returns false, allowing the reporter
+  // to skip runs based on the context information.
+  virtual bool ReportContext(const Context& context) const = 0;
+
+  // Called once for each group of benchmark runs, gives information about
+  // cpu-time and heap memory usage during the benchmark run.
+  // Note that all the grouped benchmark runs should refer to the same
+  // benchmark, thus have the same name.
+  virtual void ReportRuns(const std::vector<Run>& report) const = 0;
+
+  virtual ~BenchmarkReporter() {}
+};
+
 namespace internal {
-class BenchmarkReporter;
 
 typedef std::function<void(State&)> BenchmarkFunction;
 
 // Run all benchmarks whose name is a partial match for the regular
 // expression in "spec". The results of benchmark runs are fed to "reporter".
 void RunMatchingBenchmarks(const std::string& spec,
-                           BenchmarkReporter* reporter);
+                           const BenchmarkReporter* reporter);
 
 // Extract the list of benchmark names that match the specified regular
 // expression.
@@ -411,101 +471,34 @@
 
   static void AddRange(std::vector<int>* dst, int lo, int hi, int mult);
   static double MeasurePeakHeapMemory(const Instance& b);
-  static void RunInstance(const Instance& b, BenchmarkReporter* br);
+  static void RunInstance(const Instance& b, const BenchmarkReporter* br);
   friend class ::benchmark::State;
   friend struct ::benchmark::internal::Benchmark::Instance;
   friend void ::benchmark::internal::RunMatchingBenchmarks(
-      const std::string&, BenchmarkReporter*);
+      const std::string&, const BenchmarkReporter*);
   DISALLOW_COPY_AND_ASSIGN(Benchmark);
 };
 
 // ------------------------------------------------------
 // Benchmarks reporter interface + data containers.
 
-struct BenchmarkContextData {
-  int num_cpus;
-  double mhz_per_cpu;
-  //std::string cpu_info;
-  bool cpu_scaling_enabled;
-
-  // The number of chars in the longest benchmark name.
-  int name_field_width;
-};
-
-struct BenchmarkRunData {
-  BenchmarkRunData() :
-      thread_index(-1),
-      iterations(1),
-      real_accumulated_time(0),
-      cpu_accumulated_time(0),
-      bytes_per_second(0),
-      items_per_second(0),
-      max_heapbytes_used(0) {}
-
-  std::string benchmark_name;
-  std::string report_label;
-  int thread_index;
-  int64_t iterations;
-  double real_accumulated_time;
-  double cpu_accumulated_time;
-
-  // Zero if not set by benchmark.
-  double bytes_per_second;
-  double items_per_second;
-
-  // This is set to 0.0 if memory tracing is not enabled.
-  double max_heapbytes_used;
-};
-
-// Interface for custom benchmark result printers.
-// By default, benchmark reports are printed to stdout. However an application
-// can control the destination of the reports by calling
-// RunMatchingBenchmarks and passing it a custom reporter object.
-// The reporter object must implement the following interface.
-class BenchmarkReporter {
- public:
-  // Called once for every suite of benchmarks run.
-  // The parameter "context" contains information that the
-  // reporter may wish to use when generating its report, for example the
-  // platform under which the benchmarks are running. The benchmark run is
-  // never started if this function returns false, allowing the reporter
-  // to skip runs based on the context information.
-  virtual bool ReportContext(const BenchmarkContextData& context) = 0;
-
-  // Called once for each group of benchmark runs, gives information about
-  // cpu-time and heap memory usage during the benchmark run.
-  // Note that all the grouped benchmark runs should refer to the same
-  // benchmark, thus have the same name.
-  virtual void ReportRuns(const std::vector<BenchmarkRunData>& report) = 0;
-
-  virtual ~BenchmarkReporter();
-};
-
-
 // ------------------------------------------------------
 // Internal implementation details follow; please ignore
 
-// Given a collection of reports, computes their mean and stddev.
-// REQUIRES: all runs in "reports" must be from the same benchmark.
-void ComputeStats(const std::vector<BenchmarkRunData>& reports,
-                  BenchmarkRunData* mean_data,
-                  BenchmarkRunData* stddev_data);
-
 // Simple reporter that outputs benchmark data to the console. This is the
 // default reporter used by RunSpecifiedBenchmarks().
 class ConsoleReporter : public BenchmarkReporter {
  public:
-  virtual bool ReportContext(const BenchmarkContextData& context);
-  virtual void ReportRuns(const std::vector<BenchmarkRunData>& reports);
+  virtual bool ReportContext(const Context& context) const;
+  virtual void ReportRuns(const std::vector<Run>& reports) const;
+
  private:
-  std::string PrintMemoryUsage(double bytes);
-  virtual void PrintRunData(const BenchmarkRunData& report);
-  int name_field_width_;
+  std::string PrintMemoryUsage(double bytes) const;
+  virtual void PrintRunData(const Run& report) const;
+  mutable int name_field_width_;
 };
 
 }  // end namespace internal
-
-void Initialize(int* argc, const char** argv);
 }  // end namespace benchmark
 
 // ------------------------------------------------------
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 4344257..0df3b25 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -229,15 +229,11 @@
   return false;
 }
 
-}  // namespace
-
-namespace internal {
-
-BenchmarkReporter::~BenchmarkReporter() {}
-
-void ComputeStats(const std::vector<BenchmarkRunData>& reports,
-                  BenchmarkRunData* mean_data,
-                  BenchmarkRunData* stddev_data) {
+// Given a collection of reports, computes their mean and stddev.
+// REQUIRES: all runs in "reports" must be from the same benchmark.
+void ComputeStats(const std::vector<BenchmarkReporter::Run>& reports,
+                  BenchmarkReporter::Run* mean_data,
+                  BenchmarkReporter::Run* stddev_data) {
   // Accumulators.
   Stat1_d real_accumulated_time_stat;
   Stat1_d cpu_accumulated_time_stat;
@@ -247,7 +243,7 @@
   Stat1MinMax_d max_heapbytes_used_stat;
 
   // Populate the accumulators.
-  for (std::vector<BenchmarkRunData>::const_iterator it = reports.begin();
+  for (std::vector<BenchmarkReporter::Run>::const_iterator it = reports.begin();
        it != reports.end(); ++it) {
     CHECK_EQ(reports[0].benchmark_name, it->benchmark_name);
     real_accumulated_time_stat +=
@@ -289,7 +285,11 @@
   stddev_data->max_heapbytes_used = max_heapbytes_used_stat.StdDev();
 }
 
-std::string ConsoleReporter::PrintMemoryUsage(double bytes) {
+}  // namespace
+
+namespace internal {
+
+std::string ConsoleReporter::PrintMemoryUsage(double bytes) const {
   if (!get_memory_usage || bytes < 0.0)
     return "";
 
@@ -298,7 +298,8 @@
   return ss.str();
 }
 
-bool ConsoleReporter::ReportContext(const BenchmarkContextData& context) {
+bool ConsoleReporter::ReportContext(
+    const BenchmarkReporter::Context& context) const {
   name_field_width_ = context.name_field_width;
 
   std::cout << "Benchmarking on " << context.num_cpus << " X "
@@ -326,8 +327,9 @@
   return true;
 }
 
-void ConsoleReporter::ReportRuns(const std::vector<BenchmarkRunData>& reports) {
-  for (std::vector<BenchmarkRunData>::const_iterator it = reports.begin();
+void ConsoleReporter::ReportRuns(
+    const std::vector<BenchmarkReporter::Run>& reports) const {
+  for (std::vector<BenchmarkReporter::Run>::const_iterator it = reports.begin();
        it != reports.end(); ++it) {
     CHECK_EQ(reports[0].benchmark_name, it->benchmark_name);
     PrintRunData(*it);
@@ -337,15 +339,15 @@
   if (reports.size() < 2)
     return;
 
-  BenchmarkRunData mean_data;
-  BenchmarkRunData stddev_data;
-  internal::ComputeStats(reports, &mean_data, &stddev_data);
+  BenchmarkReporter::Run mean_data;
+  BenchmarkReporter::Run stddev_data;
+  ComputeStats(reports, &mean_data, &stddev_data);
 
   PrintRunData(mean_data);
   PrintRunData(stddev_data);
 }
 
-void ConsoleReporter::PrintRunData(const BenchmarkRunData& result) {
+void ConsoleReporter::PrintRunData(const BenchmarkReporter::Run& result) const {
   // Format bytes per second
   std::string rate;
   if (result.bytes_per_second > 0) {
@@ -546,7 +548,7 @@
   int stopping;  // Number of threads that have entered STOPPING state
   int threads;   // Number of total threads that are running concurrently
   ThreadStats stats;
-  std::vector<internal::BenchmarkRunData> runs;  // accumulated runs
+  std::vector<BenchmarkReporter::Run> runs;  // accumulated runs
   std::string label;
 
   explicit SharedState(const internal::Benchmark::Instance* b)
@@ -776,7 +778,7 @@
 #endif
 }
 
-void Benchmark::RunInstance(const Instance& b, BenchmarkReporter* br) {
+void Benchmark::RunInstance(const Instance& b, const BenchmarkReporter* br) {
   use_real_time = false;
   running_benchmark = true;
   // get_memory_usage = FLAGS_gbenchmark_memory_usage;
@@ -821,7 +823,7 @@
 */
   running_benchmark = false;
 
-  for (internal::BenchmarkRunData& report : state.runs) {
+  for (BenchmarkReporter::Run& report : state.runs) {
     double seconds = (use_real_time ? report.real_accumulated_time :
                                       report.cpu_accumulated_time);
     report.benchmark_name = b.name;
@@ -1014,8 +1016,7 @@
     return true;
   }
 
-  internal::BenchmarkRunData data;
-  data.thread_index = thread_index;
+  BenchmarkReporter::Run data;
   data.iterations = iterations_;
   data.thread_index = thread_index;
 
@@ -1106,8 +1107,7 @@
 namespace internal {
 
 void RunMatchingBenchmarks(const std::string& spec,
-                           BenchmarkReporter* reporter) {
-  CHECK(reporter != NULL);
+                           const BenchmarkReporter* reporter) {
   if (spec.empty()) return;
 
   std::vector<internal::Benchmark::Instance> benchmarks;
@@ -1134,7 +1134,7 @@
   }
 
   // Print header here
-  BenchmarkContextData context;
+  BenchmarkReporter::Context context;
   context.num_cpus = NumCPUs();
   context.mhz_per_cpu =  CyclesPerSecond() / 1000000.0f;
 //  context.cpu_info = base::CompactCPUIDInfoString();
@@ -1158,12 +1158,12 @@
 
 }  // end namespace internal
 
-void RunSpecifiedBenchmarks() {
+void RunSpecifiedBenchmarks(const BenchmarkReporter* reporter /*= nullptr*/) {
   std::string spec = FLAGS_benchmark_filter;
   if (spec.empty() || spec == "all")
     spec = ".";         // Regexp that matches all benchmarks
   internal::ConsoleReporter default_reporter;
-  internal::RunMatchingBenchmarks(spec, &default_reporter);
+  internal::RunMatchingBenchmarks(spec, reporter == nullptr ? &default_reporter : reporter);
   pthread_cond_destroy(&starting_cv);
   pthread_mutex_destroy(&starting_mutex);
   pthread_mutex_destroy(&benchmark_mutex);