// ConsoleApplication1.cpp : Этот файл содержит функцию "main". Здесь начинается и заканчивается выполнение программы.
//

#include <iostream>
#include <string.h>
#include <chrono>

typedef void TestTrimRight (char * s);

void TrimRight(char* s) {
	size_t len = strlen(s);
	char* iter = s + len - 1;

   if (*iter != ' ') {
		// Если последний символ не пробел, 
		// то и обрезать нечего
		return;
	}

   while (*iter == ' ' /*&& iter != s*/) {
		// Идти от конца к началу, 
		// пока не кончатся пробелы либо строка
		iter--;
	}

   if (iter == s) {
		// Если строка пройдена
		// и полностью состоит из пробелов
		// то результатом будет пустая строка
		*iter = '\0';
	}
	else {
		// Если пройдены все пробелы 
		// и поиск дошел до первого не пробела,
		// то заменить первый пробел на конец строки.
		*(iter + 1) = '\0';
	}
}

void TrimRight2(char* s)
{
	char* spc = 0, *p = s;

	while (*p)
		if (*p == ' ')
			for (spc = p; *++p == ' '; );
		else
			++p;

	if (spc && p != s && p[-1] == ' ')* spc = 0;

	//return s;
}

void TrimRight3(char* s) {
	char* space = nullptr;
	char* p = s;

	while (*p) {
		if (*p == ' ') {
			if (space == nullptr) {
				space = p;
			}
			p++;
		}
		else {
			space = nullptr;
			p++;
		}
   }

   if (space != nullptr) {
		*space = '\0';
	}
}

void TrimRight4 (char * s) {
   size_t len = strlen (s);
   char * it = s + len - 1;

   while (it >= s && *it == ' ') {
	  *(it--) = '\0';
   }
}

void TrimRight5(char* s) {
	char* space = nullptr;
	bool spaceFlag = false;
	char* p = s;

	while (*p) {
		if (*p == ' ') {
			space = p;
			spaceFlag = true;
		} else {
			spaceFlag = false;
		}
		p++;
	}

	if (spaceFlag) {
		*space = '\0';
	}
}

const int    PROBES = 1000 / 2;
const size_t LENGTH = 1000000;
const int    WINDOW = 75;
char  *      LETTERS;
const int    LETTERS_LENGTH = 22;
char  *      TEST_DATA;
char  *      SOURCE_DATA;

void createLetters () {
   LETTERS = (char *) malloc (sizeof (char) * LETTERS_LENGTH);
   for (size_t j = 0; j < LETTERS_LENGTH; j++) {
      if (j % 7)
         LETTERS[j] = ' ';
      else
         LETTERS[j] = 'A' + j;
   }
}

void createTestData () {
   TEST_DATA = (char *) malloc (sizeof (char) * LENGTH);
}

void createSourceData () {
   SOURCE_DATA = (char *) malloc (sizeof (char) * LENGTH);
}

char * fillSourceData (size_t len_chars, size_t len_string) {
   for (size_t i = 0; i < len_chars; i++) {
      SOURCE_DATA[i] = LETTERS[rand () % LETTERS_LENGTH];
   }

   for (size_t i = len_chars; i < len_string; i++) {
      SOURCE_DATA[i] = ' ';
   }

   SOURCE_DATA[len_string - 1] = '\0';

   return SOURCE_DATA;
}

char * fillTestData (int len) {
   memcpy (TEST_DATA, SOURCE_DATA, sizeof (char) * len);
   return TEST_DATA;
}

double doTest (TestTrimRight * test, char * str) {
   auto start = std::chrono::high_resolution_clock::now();
   test (str);
   auto finish = std::chrono::high_resolution_clock::now();
   return (double)(finish - start).count ();
}

double average (double t0, double t1) {
   return ((99.0 * t0 + t1) / 100.0);
}

int getWindowedLength (int full_length) {
   return
     (full_length -
      full_length / 100 * (rand () % WINDOW) -
      full_length / 100 * (WINDOW >> 2));
}

int main()
{
   int i = 0;
   int c = 0;
   const int c_mod = PROBES / 100 * 10;
   int char_length = 0;
   int full_length = 0;
   double
      e0 = 0.0,
      e1 = 0.0,
      e2 = 0.0,
      e3 = 0.0,
      e4 = 0.0,
      second = 1000000;

   createLetters ();
   createSourceData ();
   createTestData ();

   while (i++ < PROBES) {
      full_length = LENGTH;
      char_length = getWindowedLength (full_length);
      fillSourceData (char_length, full_length);
      e0 = average (e0, doTest (&TrimRight, fillTestData (full_length)));
      e1 = average (e1, doTest (&TrimRight2, fillTestData (full_length)));
      e2 = average (e2, doTest (&TrimRight3, fillTestData (full_length)));
      e3 = average (e3, doTest (&TrimRight4, fillTestData (full_length)));
      e4 = average (e4, doTest (&TrimRight5, fillTestData (full_length)));
      c = (c + 1) % c_mod;
      if (c == 0) {
         printf ("Probe #%-4i: ", i);
         printf
           ("e0 == %5.2f, e1 == %5.2f, e2 == %5.2f, e3 == %5.2f, e4 == %5.2f Ms\n",
            e0/second, e1/second, e2/second, e3/second, e4/second);
      }
   }

   std::cout << "Elapsed time TrimRight:  " << e0/second << " Ms\n";
   std::cout << "Elapsed time TrimRight2: " << e1/second << " Ms\n";
   std::cout << "Elapsed time TrimRight3: " << e2/second << " Ms\n";
   std::cout << "Elapsed time TrimRight4: " << e3/second << " Ms\n";
   std::cout << "Elapsed time TrimRight5: " << e4/second << " Ms\n";
}

