#include<iostream>
#include <string>
#include <stdexcept>

template<class T>
class GhostMemory{
	T* Memory;
	std::size_t N;
public:

	GhostMemory(T* P = nullptr, std::size_t L = 0): Memory(P), N(L) {}
	std::size_t Size(){ return N; }
	T& operator [](std::size_t Idx){
		if (Idx >= N) throw std::out_of_range("Out Of Range in GhostMemory::Operator[] !!");
		return Memory[Idx];
	}
	bool Reset(T* P=nullptr, std::size_t L=0){
		Memory = P;
		N = L;
		return true;
	}
	T* Pointer(){
		return Memory;
	}
	T* begin(){
		return Memory;
	}
	T* end(){
		return Memory + N;
	}
	T& Back(){
		return Memory[N - 1];
	}
};

template<class T,std::size_t N>
std::size_t CountOf(T(&A)[N]){
	return N;
}
std::string ToString(GhostMemory<char>& G){
	std::string R;

	for (auto& o : G) R += o;


	return R;
}
std::string MakeHoge(char str[], std::size_t Len){
	std::size_t S = 0;
	GhostMemory<char> G;
	std::string R;
	bool F = true;
	for (S= 1; S < Len; S++)
	{
		if (str[S] == str[0])break;
	}
	G.Reset(str, S);
	for (std::size_t i = 0; i < Len - G.Size(); i++){
		if (G[i%G.Size()] != str[i]){
			S = i;
		}
		G.Reset(str, S);
	}

	if (G.Back() != str[Len - 1])S = Len;
	G.Reset(str, S);
	R = ToString(G);
	return R;

}

bool Show(char* str,std::string R){
	std::cout << str << " -> " << R << std::endl;
	return true;
}

int main(){
	char A[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";	
	char B[] = "123412312341231234123123412312341231234123";
	char C[] = "oxoxoxoxoxoxoxoxxoxoxoxoxoxoxoxoxx";
	char D[] = "abac";
	char E[] = "axaxa";
	std::string R;
	R = MakeHoge(A,CountOf(A)-1);
	Show(A, R);
	R = MakeHoge(B,CountOf(B)-1);
	Show(B, R);
	R = MakeHoge(C,CountOf(C)-1);
	Show(C, R);	
	R = MakeHoge(D,CountOf(D)-1);
	Show(D, R);
	R = MakeHoge(E,CountOf(E)-1);
	Show(E, R);
	return 0;
}