/**************************************************
* unit:    sets           release 0.12            *
* purpose: test of functionality of unit sets     *
* Licency: GPL                                    *
* Copyright: (c) 1998-2024 Jaroslav Fojtik        *
***************************************************/
#ifdef _MSC_VER
    #include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#ifdef __BORLANDC__
 #include <alloc.h>
#else
 #define heapcheck() 1
#endif

#define CurrentDir

#ifdef Streams
 //#include <iostream.h>
 #include<iostream>
 #ifndef IOSTREAM_H_ONLY
  using namespace std;
 #endif
#endif

#include "sets.h"


#ifdef ERROR_HANDLER
 void RaiseError(int ErrNo, const void *Instance)
     {
     fprintf(stderr,"Sets::Error %d (%p)\n",ErrNo,Instance);
     }
#endif

void Benchmark(void);


static void CheckCompiler(void)
{
if((sizeof(uint8_t)!=1)||(sizeof(uint16_t)!=2)||(sizeof(uint32_t)!=4)||
   (sizeof(int8_t)!=1)||(sizeof(int16_t)!=2)||(sizeof(int32_t)!=4))
	{
	fprintf(stderr,"Error: File was badly compiled. Check typedfs.h !\n");
	}
}


int main(int argc, char *argv[])
{
set s0,s1,s2,s3,s4;
int i,j;
char retezec[200],retezec2[200];
int Ops;

int pole[]={1,3,8 ___ 12,1};
int pole2[]={1,3,16};
int pole3[]={16 ___ 33, 200};

 CheckCompiler();
 puts("");
 puts("<<<sets>>> (c)1998-2024 Jaroslav Fojtik");
 printf("              This program tests the sets unit, release %u.%u\n",
	SETS_VERSION>>8, SETS_VERSION&0xFF);

 if(argc>1)
 {
   Ops = 0;
   for(i=1; i<argc; i++)
   {
     if(!strcmp(argv[i],"-bench")) Ops|=3;
     if(!strcmp(argv[i],"-demo")) Ops|=4;
     if(!strcmp(argv[i],"-test")) Ops|=1;
     if(!strcmp(argv[i],"-help") || !strcmp(argv[i],"/help"))
     {
       printf("Command line parameters:\n-bench -demo -test -help\n");
       return 1;
      }
    }
 }
 else Ops=3;

//////////////////////////////////
if(Ops&1)
{
 puts(" constructors & copy operator =");

 s1=(1);
 if(strcmp(set2str(retezec,s1),"[1]"))
	{
        puts(set2str(retezec,s1));

        i=-10;
	goto Abnormal_End;
        }
 i=check(s1);
 if(i!=0) goto Abnormal_End;

 s2=set(pole,6);
 if(strcmp(set2str(retezec,s2),"[1,3,8..12]"))
	{
        i=-11;
	goto Abnormal_End;
        }
i=check(s2);
if(i!=0) goto Abnormal_End;

s3=set(pole2,3);
if(strcmp(set2str(retezec,s3),"[1,3,16]"))
	{
        i=-12;
	goto Abnormal_End;
        }
i=check(s3);
if(i!=0) goto Abnormal_End;

s4=set(pole3,4);
if(strcmp(set2str(retezec,s4),"[16..33,200]"))
	{
	i=-13;
	goto Abnormal_End;
	}
i=check(s4);
if(i!=0) goto Abnormal_End;

s3=s4;
if(strcmp(set2str(retezec,s3),"[16..33,200]"))
	{
	i=-14;
	goto Abnormal_End;
	}
i=check(s3);
if(i!=0) goto Abnormal_End;

for(i=0;i<10;i++)
  {
  s4=set(8,i);
  if(strcmp(set2str(retezec,s4),"[]"))
	{
	i=-15;
	goto Abnormal_End;
	}
  }

erase(s1);
s1=str2set("[16..33,200]");
if(strcmp(set2str(retezec,s1),"[16..33,200]"))
	{
#ifdef Streams
	cout<<"Function str2set do not work properly s1:"<<s1<<" should be [16..33,200]";
#endif
	i=-16;  goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;

if(Card(s1)!=19)
	{
#ifdef Streams
        cout<<"The number of elements sor set s:"<<s1<<" is calculated badly:"<<Card(s1)<<"!\n";
#endif
        i=-17;  goto Abnormal_End;
        }
        
if(EmptyCheck(s1))
	{
#ifdef Streams
        cout<<"Set s1:"<<s1<<" is reported as empty!\n";
#endif
        i=-18;  goto Abnormal_End;
        }

//////////////////////////////////
puts(" set adding operator + +=");

s1=1;
s4=s3;
s1+=2;
s1=s1+s0;
if(strcmp(set2str(retezec,s1),"[1..2]"))
	{
#ifdef Streams
	cout<<"Set:"<<s1<<" should be [1..2]";i=-20;
#endif
	goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;

s1=s0+s1;
if(strcmp(set2str(retezec,s1),"[1..2]"))
	{
	i=-21;
	goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;

erase(s3);
s3=32;	s3+=17;	s3+=64;
if(strcmp(set2str(retezec,s3),"[17,32,64]"))
	{
#ifdef Streams
	cout<<"Set s3:"<<s3<<" should contain [17,32,64]"<<"\n";i=-22;
#endif
	goto Abnormal_End;
	}
i=check(s3);
if(i!=0) goto Abnormal_End;


erase(s3);
s3=32;	s3=s3+17;	s3=64+s3;
if(strcmp(set2str(retezec,s3),"[17,32,64]"))
	{
#ifdef Streams
	cout<<"Set s3:"<<s3<<" should contain [17,32,64]"<<"\n";i=-23;
#endif
	goto Abnormal_End;
	}
i=check(s3);
if(i!=0) goto Abnormal_End;


s1-=32;
s1=s1+(500);
if(strcmp(set2str(retezec,s1),"[1..2,500]"))
	{
#ifdef Streams
	cout<<"Set s1:"<<s1<<" should contain [1..2,500]"<<"\n";i=-24;
#endif
	goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;


s3=set(pole2,3);
s4+=s3;
if(strcmp(set2str(retezec,s4),"[1,3,16..33,200]"))
	{
	i=-25;
	goto Abnormal_End;
	}
i=check(s3);
if(i!=0) goto Abnormal_End;


s2=set(pole,6);
for(i=12;i<=300;i++)
    {
    s2+=i;
    sprintf(retezec2,"[1,3,8..%d]",i);
    if(strcmp(set2str(retezec,s2),retezec2))
	{
#ifdef Streams
        cout<<"s2:"<<s2<<" should be:"<<retezec2<<"\n";
#endif
	i=-26;	goto Abnormal_End;
	}
   }
i=check(s3);
if(i!=0) goto Abnormal_End;


//////////////////////////////////
puts(" set substracting operator - -=");
s1=s1-(500);
if(strcmp(set2str(retezec,s1),"[1..2]"))
	{
	i=-30;
	goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;


s1=s1-s0;
if(strcmp(set2str(retezec,s1),"[1..2]"))
	{
        i=-31;
	goto Abnormal_End;
        }
i=check(s1);
if(i!=0) goto Abnormal_End;

s1=s0-s1;
if(strcmp(set2str(retezec,s1),"[]"))
	{
	i=-32;
	goto Abnormal_End;
        }
i=check(s1);
if(i!=0) goto Abnormal_End;


for(i=400;i>=10;i--)
    {
    s2-=i;
    sprintf(retezec2,"[1,3,8..%d]",i>300?300:i-1);
    if(strcmp(set2str(retezec,s2),retezec2))
	{
	i=-33;
	goto Abnormal_End;
        }
   }
i=check(s2);
if(i!=0) goto Abnormal_End;


s3=set(pole2,3);
s4=set(pole3,4);
s4-=s3;
if(strcmp(set2str(retezec,s4),"[17..33,200]"))
	{
	i=-34;
	goto Abnormal_End;
	}
i=check(s3);
if(i!=0) goto Abnormal_End;


s4= (0);
for(j=1;j<=300;j++)
    {
    s1+=j;
    s4=(j) + s4;

    s4-=(j-1);
    sprintf(retezec2,"[%d]",j);
    if(strcmp(set2str(retezec,s4),retezec2))
	 {
#ifdef Streams
	 cout<<"Not equal:"<<retezec2<<" "<<s4<<"\n";i=-35;
#endif
	 goto Abnormal_End;
	 }
    i=check(s4);
    if(i!=0) goto Abnormal_End;
    }

erase(s4);
s4=s4-5;
if(!EmptyCheck(s4))
	{
#ifdef Streams
	cout<<"Set s4:"<<s4<<" should be empty!\n";i=-36;
#endif
	goto Abnormal_End;
	}
s4=s4-s1;
if(!EmptyCheck(s4))
	{
#ifdef Streams
	cout<<"Set s4:"<<s4<<" should be empty!\n";i=-36;
#endif
	goto Abnormal_End;
	}

s2=set(pole,6);
for(i=0;i<20;i++)
  {
  if(s2[i])
    {
    s3=i-s2;
    if(strcmp(set2str(retezec,s3),"[]"))
	{
	i=-37;
	goto Abnormal_End;
	}
    }
  s3=s2-i;
  s3=i-s3;
  sprintf(retezec2,"[%d]",i);
  if(strcmp(set2str(retezec,s3),retezec2))
	{
	i=-37;
	goto Abnormal_End;
	}
  }

/////////////////////////////////////////////
puts(" set operators & &= | |=");

s0=set();
s1=s1+(2);
s2=set(pole,6);
s3=set(pole2,3);

if(strcmp(set2str(retezec,s1 & s0),"[]"))
	{
	i=-40;
	goto Abnormal_End;
        }
i=check(s1);
if(i!=0) goto Abnormal_End;

s4=s2 & s3;
if(strcmp(set2str(retezec,s4),"[1,3]"))
	{
        i=-41;
	goto Abnormal_End;
        }
i=check(s4);
if(i!=0) goto Abnormal_End;

s1= s0 | (0);
s4= s0 & (0);
for(j=1;j<=300;j++)
    {
    s1|=j;
    s4=s4 | s1;
    sprintf(retezec2,"[0..%d]",j);
    if(strcmp(set2str(retezec,s1),retezec2))
	{
#ifdef Streams
	cout<<"Not equal:"<<retezec2<<" "<<s1<<"\n";i=-42;
#endif
	goto Abnormal_End;
        }
   i=check(s1);
   if(i!=0) goto Abnormal_End;

   s4&=j;
   sprintf(retezec2,"[%d]",j);
   if(strcmp(set2str(retezec,s4),retezec2))
	{
	i=-43;
	goto Abnormal_End;
        }
   i=check(s4);
   if(i!=0) goto Abnormal_End;
   }

/////////////////////////////////////////////
puts(" set operator ^ ^=");

erase(s1);
s1=s1^(2);
s1^=1;
if(strcmp(set2str(retezec,s1),"[1..2]"))
	{
#ifdef Streams
	cout<<"Set:"<<s1<<" should be [1..2]";
#endif
	i=-50;
	goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;


s0=set();
s1=s0^(2);
s2=set(pole,6);
s3=set(pole2,3);

if(strcmp(set2str(retezec,s1 ^ s0),"[2]"))
	{
	i=-51;
	goto Abnormal_End;
	}
i=check(s1);
if(i!=0) goto Abnormal_End;

s1= s0 | (0);
for(j=2;j<=300;j++)
    {
    s1^=j-1;
    s1 = s1 ^ j;
    if(j==2) sprintf(retezec2,"[0..%d]",j);
	else sprintf(retezec2,"[0..1,%d]",j);
    if(strcmp(set2str(retezec,s1),retezec2))
	{
	i=-52;
	goto Abnormal_End;
	}
   i=check(s1);
   if(i!=0) goto Abnormal_End;
   }


/////////////////////////////////////////////
puts(" set operator []");
s0=set();
erase(s1);

for(i=0;i<100;i++)
  if(s0[i] || s1[i])
	{
	i=-60;
	goto Abnormal_End;
	}

for(i=0;i<100;i++)
  {
  if(s0[i] || s1[i])
	{
	i=-61;
	goto Abnormal_End;
	}
  s0+=i;
  s1|=i;
  if(!s0[i] || !s1[i])
	{
	i=-62;
	goto Abnormal_End;
	}
  s1-=i-1;
  if(s1[i-1])
	{
	i=-63;
	goto Abnormal_End;
	}
  }


/////////////////////////////////////////////
puts(" set operator IN");
erase(s0); s0+=1; s0+=20;
erase(s1);
erase(s2);

for(i=0;i<100;i++)
  {
  if(i==1 || i==20)
    {
    if(!(i IN s0))
	{
	i=-70;
	goto Abnormal_End;
	}
    }
  else
    {
    if(i IN s0)
	{
	i=-71;
	goto Abnormal_End;
	}
    }

  s2=i;
  if(i==1 || i==20)
    {
    if(!(s2 IN s0))
	{
#ifdef Streams
	cout<<s2<<" should be in "<<s0<<"\n";i=-72;
#endif
	goto Abnormal_End;
	}
    }
  else
    {
    if(s2 IN s0)
	{
#ifdef Streams
	cout<<s2<<" should not be in "<<s0<<"\n";i=-73;
#endif
	goto Abnormal_End;
	}
    }
  }

}


/////Now execute benchmarks/////
 if(i==0 && (Ops & 2)) Benchmark();


///////////End of tests/////////
i = 0;
Abnormal_End:
if(heapcheck()<=0)
         {
	 printf("Bad allocation %d",heapcheck());
         return(-1);
         }
if(i!=0) {
	 printf("Unit Error %d",i);
         return(-1);
         }
puts(" .............. Test passed OK ..............");
return(0);
}


#include "../test/bench.h"


void Moving(long i)
{
set s1,s2,s3,s4,s5;
int xi[]={1,2,5,9,20,40};

while(i-->0)
	{
	s1=set(xi,sizeof(xi)/sizeof(int));
	set tmpset(s1);
	s2=s1;
	s5=set(2);

	s3=1;	s3=2;
	s3=16;  s3=100;
	}
}


void Adding(long i)
{
set s1,s2,s3,s4,s5;
int xi[]={1,2,5,9,20,40};

s1=set(xi,sizeof(xi)/sizeof(int));
s2=s1;
while(i-->0)
	{
	s3+=9;
	s4+=s1;
	s4=s1+s2;
	s4=s4+2;
	s5=2+s3;
	}
}


void LogicalMIX(long i)
{
set s1,s2,s3,s4,s5;
while(i-->0)
	{
	s1^=1;
	s2=s1^15;
	s3=s1|2;
	s3|=15;
	s4=s2 & s3;
	s4&=15;
	}
}



void Substracting(long i)
{
set s1,s2,s3,s4,s5;
int xi[]={1,2,5,9,20,40};
int yi[]={0,2,7,10 ___ 40};

s1=set(xi,sizeof(xi)/sizeof(int));
s2=set(yi,sizeof(yi)/sizeof(int));
s3=s2;
while(i-->0)
	{
	s3-=2;
	s4-=s1;
	s4=s1-s2;
	s5=s1-2;
	s4=2-s1;
	}
}


void Indexing(long i)
{
set s1,s2,s3,s4,s5;
int xi[]={1,2,5,9,20,40};
int j=0;

s1=set(xi,sizeof(xi)/sizeof(int));
s2=8;
s3=9;
while(i-->0)
	{
	s1+=41;
	j+=s1[1];
	j+=s1[21];
	j+=s1[40];
	s1-=41;

	if(20 IN s1) j++;
	if(1 IN s1) j++;
	if(s2 IN s1) j++;

	if(EmptyCheck(s1)) j++;
	j+=Card(s1);
	}
}



void Benchmark(void)
{
float f;

puts(" .............. Benchmarks ..............");


f=AutoMeasure(Moving);
printf(" Moving sets: %fus\n",f);

f=AutoMeasure(Adding);
printf(" Addind sets: %fus\n",f);

f=AutoMeasure(Substracting);
printf(" Subtracting sets: %fus\n",f);

f=AutoMeasure(Indexing);
printf(" Indexing sets: %fus\n",f);

f=AutoMeasure(LogicalMIX);
printf(" Logical operations AND OR XOR: %fus\n",f);

}

