#include "pgkeywords.h"
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <chrono>
using namespace std;
using namespace std::chrono;

int main(int argc, char **argv)
{
  const int nkeywords = SCANKEYWORDS_NUM_KEYWORDS;

  int kw_lengths[nkeywords] = {0};
  const int maxlen = 64;

  for (int kw = 0; kw < nkeywords; kw++)
  {
    int len = strlen(ScanKeywords_kw_string + ScanKeywords_kw_offsets[kw]);
    kw_lengths[kw] = len;
  }

  const uint64_t iters = 1000000;
  printf("%-20s %-6s %-16s %-16s %-16s\n", "keyword", "length", "char-a-time (ns)", "word-a-time (ns)", "diff (%)");
  int lengths_seen[64] = {0};
  for (int len = 1; len < maxlen; len++)
  {
    for (int kw = 0; kw < nkeywords; kw++)
    {
      if (kw_lengths[kw] != len)
      {
        continue;
      }
      if (++lengths_seen[kw_lengths[kw]] > 3)
      {
        break;
      }
      high_resolution_clock::time_point t1 = high_resolution_clock::now();
      int chksum1 = 0;
      for (uint64_t i = 0; i < iters; i++)
      {
        chksum1 += ScanKeywords_hash_func(ScanKeywords_kw_string + ScanKeywords_kw_offsets[kw], kw_lengths[kw]);
      }
      high_resolution_clock::time_point t2 = high_resolution_clock::now();
      auto duration1 = duration_cast<nanoseconds>(t2 - t1).count();
      high_resolution_clock::time_point t3 = high_resolution_clock::now();
      int chksum2 = 0;
      for (uint64_t i = 0; i < iters; i++)
      {
        chksum2 += ScanKeywords_hash_func2(ScanKeywords_kw_string + ScanKeywords_kw_offsets[kw], kw_lengths[kw]);
      }
      high_resolution_clock::time_point t4 = high_resolution_clock::now();
      auto duration2 = duration_cast<nanoseconds>(t4 - t3).count();
      if (chksum1 != chksum2)
      {
        printf("Hash functions returned different values for %s!\n", ScanKeywords_kw_string + ScanKeywords_kw_offsets[kw]);
        exit(0);
      }
      printf("%-20s %-6d %-16.2f %-16.2f %-16.2f\n", ScanKeywords_kw_string + ScanKeywords_kw_offsets[kw], len, (double)duration1 / iters, (double)duration2 / iters, (double)duration2 / (double)duration1 - 1.0);
    }
  }
  return 0;
}
