Repository: google/benchmark
File: include/benchmark/benchmark.h (C/C++)

Code before:
  bool scaling_enabled;
  std::vector<double> load_avg;

  static const CPUInfo& Get();

 private:
  CPUInfo();
  BENCHMARK_DISALLOW_COPY_AND_ASSIGN(CPUInfo);
};

//Adding Struct for System Information
struct SystemInfo {
  std::string name;
  static const SystemInfo& Get();
 private:
  SystemInfo();
  BENCHMARK_DISALLOW_COPY_AND_ASSIGN(SystemInfo);
};

// BenchmarkName wraps a std::string containing different fields
// of a benchmark's name (e.g. the 'root' name, the benchmark's
// 'args' etc.).
class BenchmarkName {
 public:
  // Different fields of the benchmark's name.
  enum Field {
    // The name of the function being invoked in the benchmark.
    kRoot = 1U,
    // The arguments supplied to the benchmark, e.g. via Range().
    kArgs = 1U << 1U,
    // The minimum time specified for a benchmark.
    kMinTime = 1U << 2U,
    // The number of iterations specified for a benchmark.
    kIterations = 1U << 3U,
    // The number of repetitions specified for a benchmark.
    kRepetitions = 1U << 4U,
    // The type of time to measure for a benchmark.
    kTimeType = 1U << 5U,
    // The number of concurrent threads for a benchmark.
    kThreads = 1U << 6U,
    // All fields.
    kAll =
        kRoot | kArgs | kMinTime | kIterations | kRepetitions | kTimeType | kThreads
  };

  // Construct BenchmarkName with an 'empty' name.
  BenchmarkName();

  // Construct BenchmarkName with a given 'root'.
  BenchmarkName(std::string root);


Review comment (performance):
thinking more, and looking at the access pattern, i think this is overkill. The sections of the benchmark name are always appended in the same order. Similarly, you only care about dropping 'args' from the complexity bit (as far as i can see).

So why not just have a struct with all the strings stored as individual fields with an accessor `name` and another `NameWithoutArgs`.

Ie:

```c++
struct BenchmarkName {
  std::string name;
  std::string args;
  std::string min_time;
  std::string iterations;
  ...

  std::string name() { return absl::StrJoin({name, args, min_time, iterations...}, "/"); }  // or equivalent non-absl version
  std::string nameNoArgs() { return absl::StrJoin({name, min_time, iterations...}, "/"); }  // also non-absl.
};
```

then the benchmark name is stored (as you have) as a BenchmarkName and we have two simple accessors for getting the formatted version.

Code after:
  std::vector<double> load_avg;

  static const CPUInfo& Get();

 private:
  CPUInfo();
  BENCHMARK_DISALLOW_COPY_AND_ASSIGN(CPUInfo);
};

//Adding Struct for System Information
struct SystemInfo {
  std::string name;
  static const SystemInfo& Get();
 private:
  SystemInfo();
  BENCHMARK_DISALLOW_COPY_AND_ASSIGN(SystemInfo);
};

// BenchmarkName contains the components of the Benchmark's name
// which allows individual fields to be modified or cleared before
// building the final name using 'str()'.
struct BenchmarkName {
  std::string function_name;
  std::string args;
  std::string min_time;
  std::string iterations;
  std::string repetitions;
  std::string time_type;
  std::string threads;

  // Return the full name of the benchmark with each non-empty
  // field separated by a '/'
  std::string str() const;
};

// 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 {
    CPUInfo const& cpu_info;
    SystemInfo const& sys_info;
    // The number of chars in the longest benchmark name.
    size_t name_field_width;
    static const char* executable_name;
    Context();
  };