#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>


#ifndef max
	#define max( a, b ) ( ((a) > (b)) ? (a) : (b) )
#endif

uint8_t seed[8];

inline uint32_t zend_inline_hash_func(const char *arKey, uint32_t nKeyLength)
{
        register uint32_t hash = 5381;

        /* variant with the hash unrolled eight times */
        for (; nKeyLength >= 8; nKeyLength -= 8) {
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[0]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[1]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[2]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[3]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[4]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[5]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[6]);
                hash = ((hash << 5) + hash) + (*arKey++ ^ seed[7]);
        }
        switch (nKeyLength) {
                case 7: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[0]); /* fallthrough... */
                case 6: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[1]); /* fallthrough... */
                case 5: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[2]); /* fallthrough... */
                case 4: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[3]); /* fallthrough... */
                case 3: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[4]); /* fallthrough... */
                case 2: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[5]); /* fallthrough... */
                case 1: hash = ((hash << 5) + hash) + (*arKey++ ^ seed[6]); break;
                case 0: break;
        }
        return hash;
}

struct ll {
	char str[16];
	struct ll *next;
};

#define BSZ 65536
#define STOP 62000

struct ll *bckt[BSZ];
uint32_t bcktsz[BSZ];

char alphabet[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTUVWXYZ01234567890";



int main()
{
	int ln,i,strl;
	uint32_t cmax=0,tmax=0;
	uint32_t mask,hash;
	uint64_t iter=0;
	int cstr[16];
	char stro[16];
	struct ll *tmp;
	FILE *inp;
	char buff[1024];
	int rnd;
	time_t beg;

	beg=time(NULL);

	memset(&buff, 0, sizeof(buff));

	mask=0xffff;

	while (42) {
		inp=fopen("CHKF","r");
		rnd=open("/dev/urandom", O_RDONLY);
		read(rnd, &seed, 8);
		close(rnd);

		iter++;
		memset(&bcktsz, 0, sizeof(bcktsz));
		while (!feof(inp)) {
			if (fgets(buff,sizeof(buff),inp)==NULL) break;
			buff[strlen(buff)-1]='\0';
			hash = zend_inline_hash_func(buff, strlen(buff)) & mask;
	//		printf("%s\n", buff);
			bcktsz[hash]++;
	///		printf("%s %X %d %d\n",stro, hash, bcktsz[hash], cmax);
			cmax=max(cmax, bcktsz[hash]);

		}
		if (cmax>tmax) {
			tmax=cmax;
			printf("time %ld bsize %d iter %ld\n", time(NULL)-beg, cmax, iter);
		};
		fclose(inp);
	}
	return 0;
	ln=strlen(alphabet);

	for(strl=1;strl<17;strl++) {
		memset(&cstr, 0, sizeof(cstr));
//		printf("%d %d\n", strl, cmax);
		while(cstr[strl]==0) {
		//increase
			for (i=0;i<strl;i++) stro[i]=alphabet[cstr[i]];
			hash = zend_inline_hash_func(stro, strl) & mask;
		// do insert

			bcktsz[hash]++;
///			printf("%s %X %d %d\n",stro, hash, bcktsz[hash], cmax);
			cmax=max(cmax, bcktsz[hash]);
			if (bckt[hash]==NULL) {
				bckt[hash]=(struct ll *)malloc(sizeof(struct ll));
				bckt[hash]->next=NULL;
				memcpy(bckt[hash]->str, stro, strl+1);
			} else {
				tmp=bckt[hash];		
				bckt[hash]=(struct ll *)malloc(sizeof(struct ll));
				bckt[hash]->next=tmp;
				memcpy(bckt[hash]->str, stro, strl+1);
			}
			if (cmax>STOP) {
				for (i=0;i<BSZ;i++)
					if (bcktsz[i]==cmax) break;
		//		printf("FOUND %d %d\n", i, cmax);
				tmp=bckt[i];
				for (;tmp!=NULL; tmp=tmp->next) {
					printf("%s\n", tmp->str);
				};
				return 0;
			}
			
			i=0;
			cstr[0]++;
		//	printf("DBG %d %d\n", i, cstr[i]);
			while(cstr[i]>=ln) {
		//		printf("DBG2 %d %c\n", i, stro[cstr[i]]);
				cstr[i]=0;
				i++;
				cstr[i]++;
			}
		}
	}

	return 0;
}
