#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <iso646.h>
#include <clang-c/Index.h>
#undef NDEBUG
#include <assert.h>

typedef enum {false=0,true=1} bool;
#define INCF(x) (++(x))
#define DECF(x) (--(x))





void* memory_alloc(const char* fname,size_t size){
    void* memory=malloc(size);
    if(0==memory){
        fprintf(stderr,"%s: out of memory\n",fname);
        exit(1);}
    return(memory);}


int* compute_primes_to(int n){
    if(n<2){
        int* primes=memory_alloc(__FUNCTION__,1);
        primes[0]=0;
        return(primes);
    }else if(2==n){
        int* primes=memory_alloc(__FUNCTION__,2);
        primes[0]=1;
        primes[1]=2;
        return(primes);
    }else if(3==n){
        int* primes=memory_alloc(__FUNCTION__,3);
        primes[0]=1;
        primes[1]=2;
        primes[2]=3;
        return(primes);
    }else{
        int bits_max;
        int words_max;
        int word_size=8*sizeof(int);
        int* bits;
        int bit;
        int prime_count=2;
        int cur_prime=3;
        int* primes;

        n-=(n%1)?3:2;
        bits_max=n/2;
        words_max=bits_max/word_size;
        bits=memory_alloc(__FUNCTION__,words_max);
        for(int i=0;i<words_max;i++){
            bits[i]=(~0);}
        while(cur_prime<n){
           bit=cur_prime+(cur_prime-3)/2;
           while(bit<bits_max){
               bits[bit/word_size]&=(~(1<<bit%word_size));
               bit+=cur_prime;}
           bit=1+((cur_prime-3)/2);
           int pos=bit;
           while((pos<=bits_max) and (0==(bits[pos/word_size]&(1<<pos%word_size)))){
                pos++; }
           bit=pos;
           if(bit<bits_max){
              cur_prime=bit+bit+3;
              prime_count++;
           }else{
               cur_prime=n;
           }}
        primes=memory_alloc(__FUNCTION__,prime_count*sizeof(int));
        primes[0]=prime_count;
        int curnum=1;
        primes[curnum++]=2;
        primes[curnum++]=3;
        cur_prime=3;
        bit=1;
           while((bit<=bits_max) and (0==(bits[bit/word_size]&(1<<bit%word_size)))){
                bit++; }
        while(bit<bits_max){
           cur_prime=bit+bit+3;
           primes[curnum++]=cur_prime;
           bit++;
           while((bit<=bits_max) and (0==(bits[bit/word_size]&(1<<bit%word_size)))){
                bit++; }}
        return(primes);}}



int* primes=0;

int ceiling_to_nearest_prime(int n){
    if((0==primes) or (primes[primes[0]-1]<n)){
        primes=compute_primes_to(n*2);
    }
    int min=1;
    int max=primes[0];
    int ind=(min+max)/2;
    int ord=(n==primes[ind])?0:(n<primes[ind])?-1:1;
    while((0!=ord) and (min!=ind)){
       if(ord<0){
                    max=ind;
        }else{
        min=ind;
        }
        ind=(min+max)/2;
        ord=(n==primes[ind])?0:(n<primes[ind])?-1:1;}
    if((1<ind)and(ord<0)){
        ord=1;
        ind--;}
    if(ord<0){
       return(primes[1]);
    }else{
       return(primes[ind+1]);
    }}


int argv_count(const char* const* argv){
    int cnt=0;
    while(argv[cnt]){
        cnt++;
    }
    return(cnt);}


const char* const* argv_concat(const char* const* argv1,const char* const* argv2){
    int cnt1=argv_count(argv1);
    int cnt2=argv_count(argv2);
    const char** result=memory_alloc(__FUNCTION__,(1+cnt1+cnt2)*sizeof(char*));
    int s=0;
    int d=0;
    for(s=0;s<cnt1;s++){
        result[d++]=argv1[s];}
    for(s=0;s<cnt2;s++){
        result[d++]=argv2[s];}
    result[d]=0;
    return(result);}



typedef enum {
    ot_nil=0,
    ot_CXCursor,  // CXCursor*
    ot_int,       // int
    ot_cons,      // cons*
    ot_hashtable, // hashtable*
} object_type;

const char* type_name(object_type type){
    switch(type){
      case ot_nil: return("null");
      case ot_CXCursor: return("CXCursor");
      case ot_int: return("integer");
      case ot_cons: return("cons");
      case ot_hashtable: return("hashtable");
      default: return("#<UNKNOWN TYPE>");}}

void error_type(const char* fname,object_type expected,object_type got){
    fprintf(stderr,"%s: got an object of type %s, expected type %s\n",
            fname,type_name(got),type_name(expected));
    exit(1);}

void error_signal(const char* fname,const char* message){
    fprintf(stderr,"%s: %s\n",fname,message);
    exit(1);}

typedef struct {
    object_type type;
    union {
        CXCursor cursor;
        struct hashtable* hashtable;
        struct cons* cons;
        int integer;
    } value;
} object;


object* box(object_type type,...){
    object* o=memory_alloc(__FUNCTION__,sizeof(*o));
    o->type=type;
    va_list ap;
    va_start(ap,type);
    switch(type){
      case ot_CXCursor:  o->value.cursor=(*(va_arg(ap,CXCursor*)));         break;
      case ot_int:       o->value.integer=va_arg(ap,int);                   break;
      case ot_cons:      o->value.cons=va_arg(ap,struct cons*);             break;
      case ot_hashtable: o->value.hashtable=va_arg(ap,struct hashtable*);   break;
      default: error_signal(__FUNCTION__,"unexpected object type.");        break;}
    va_end(ap);
    return(o);}


void* nil=0;

bool null(void* object){
    return(0==object);}



typedef struct cons {
    object* car;
    object* cdr;
} kons;

object* cons(object* a,object* d){
    kons* cell=memory_alloc(__FUNCTION__,sizeof(*cell));
    cell->car=a;
    cell->cdr=d;
    return(box(ot_cons,cell));}

object* car(object* cell){
    if(0==cell){ return(cell); }
    else if(ot_cons==cell->type){ return(cell->value.cons->car); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

object* cdr(object* cell){
    if(0==cell){ return(cell); }
    else if(ot_cons==cell->type){ return(cell->value.cons->cdr); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

object* setcar(object* cell,object* a){
    if(0==cell){ error_type(__FUNCTION__,ot_cons,ot_nil); return(nil); }
    else if(ot_cons==cell->type){ cell->value.cons->car=a; return(a); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}

object* setcdr(object* cell,object* d){
    if(0==cell){ error_type(__FUNCTION__,ot_cons,ot_nil); return(nil); }
    else if(ot_cons==cell->type){ cell->value.cons->cdr=d; return(d); }
    else{ error_type(__FUNCTION__,ot_cons,cell->type); return(nil); }}



bool equal(object* a,object* b){
    if(a->type==b->type){
        switch(a->type){
          case ot_nil:       return(true);
          case ot_CXCursor:  return(clang_equalCursors(a->value.cursor,b->value.cursor));
          case ot_int:       return(a->value.integer==b->value.integer);
          case ot_cons:      return(equal(car(a),car(b)) and equal(cdr(a),cdr(b)));
          case ot_hashtable: return(a->value.hashtable==b->value.hashtable);}
    }else{
        return(false);}}



typedef struct hashtable {
    int count;
    int size;
    float rehash_size;
    float rehash_threshold;
    object** entries;
} hashtable;

unsigned hashtable_hash(hashtable*);

unsigned sxhash(object* o){
    switch(o->type){
      case ot_nil:       return(0);
      case ot_CXCursor:  return(clang_hashCursor(o->value.cursor));
      case ot_int:       return(o->value.integer);
      case ot_cons:      return(sxhash(car(o))+(sxhash(cdr(o))<<1));
      case ot_hashtable: return(hashtable_hash(o->value.hashtable));}}


hashtable* make_hashtable(int size){
    hashtable* h=memory_alloc(__FUNCTION__,sizeof(*h));
    h->count=0;
    h->size=size;
    h->rehash_size=2.0;
    h->rehash_threshold=1.5;
    h->entries=memory_alloc(__FUNCTION__,sizeof(*(h->entries))*size);
    int i=0;
    for(i=0;i<size;i++){
        h->entries[i]=nil;}
    return(h);}

object* hashtable_get(hashtable* table,object* key){
    unsigned h=sxhash(key);
    int i=h%table->size;
    while(not(null(table->entries[i])) and not(equal(key,table->entries[i]->value.cons->car))){
        i=(i+1)%table->size;}
    return(cdr(table->entries[i]));}

unsigned hashtable_hash(hashtable* table){
    return((table->size<<3)+table->count);}

hashtable* hashtable_grow(hashtable* table){
    int newsize=ceiling_to_nearest_prime(table->size*table->rehash_threshold);
    object** newentries=memory_alloc(__FUNCTION__,newsize);
    for(int j=0;j<newsize;j++){
        newentries[j]=nil;}
    for(int i=0;i<table->size;i++){
        object* entry=table->entries[i];
        if(entry){
            unsigned h=sxhash(car(entry));
            int j=h%newsize;
            while(not(null(newentries[j]))){
                j=(j+1)%newsize;}
            newentries[j]=entry;}}
    table->size=newsize;
    table->entries=newentries;
    return(table);}

object* hashtable_set(hashtable* table,object* key,object* value){
    if(table->count*table->rehash_size<table->size){
        unsigned hash=sxhash(key);
        int i=hash%table->size;
        while(not(null(table->entries[i])) and not(equal(key,car(table->entries[i])))){
            i=(i+1)%table->size;}
        if(null(table->entries[i])){
            INCF(table->count);
            table->entries[i]=cons(key,value);
        }else{
            setcdr(table->entries[i],value);
        }
        return(value);
    }else{
        hashtable_grow(table);
        return(hashtable_set(table,key,value));}}



static const char* Includes[]={"-I/opt/llvm/lib/clang/3.3/include",0};

const char* cursorSymbol(int cursorKind){
    switch(cursorKind){
      case CXCursor_UnexposedDecl:                      return ":unexposed-decl";
      case CXCursor_StructDecl:                         return ":struct-decl";
      case CXCursor_UnionDecl:                          return ":union-decl";
      case CXCursor_ClassDecl:                          return ":class-decl";
      case CXCursor_EnumDecl:                           return ":enum-decl";
      case CXCursor_FieldDecl:                          return ":field-decl";
      case CXCursor_EnumConstantDecl:                   return ":enum-constant-decl";
      case CXCursor_FunctionDecl:                       return ":function-decl";
      case CXCursor_VarDecl:                            return ":var-decl";
      case CXCursor_ParmDecl:                           return ":parm-decl";
      case CXCursor_ObjCInterfaceDecl:                  return ":objc-interface-decl";
      case CXCursor_ObjCCategoryDecl:                   return ":objc-category-decl";
      case CXCursor_ObjCProtocolDecl:                   return ":objc-protocol-decl";
      case CXCursor_ObjCPropertyDecl:                   return ":objc-property-decl";
      case CXCursor_ObjCIvarDecl:                       return ":objc-ivar-decl";
      case CXCursor_ObjCInstanceMethodDecl:             return ":objc-instance-method-decl";
      case CXCursor_ObjCClassMethodDecl:                return ":objc-class-method-decl";
      case CXCursor_ObjCImplementationDecl:             return ":objc-implementation-decl";
      case CXCursor_ObjCCategoryImplDecl:               return ":objc-category-impl-decl";
      case CXCursor_TypedefDecl:                        return ":typedef-decl";
      case CXCursor_CXXMethod:                          return ":cxx-method";
      case CXCursor_Namespace:                          return ":namespace";
      case CXCursor_LinkageSpec:                        return ":linkage-spec";
      case CXCursor_Constructor:                        return ":constructor";
      case CXCursor_Destructor:                         return ":destructor";
      case CXCursor_ConversionFunction:                 return ":conversion-function";
      case CXCursor_TemplateTypeParameter:              return ":template-type-parameter";
      case CXCursor_NonTypeTemplateParameter:           return ":non-type-template-parameter";
      case CXCursor_TemplateTemplateParameter:          return ":template-template-parameter";
      case CXCursor_FunctionTemplate:                   return ":function-template";
      case CXCursor_ClassTemplate:                      return ":class-template";
      case CXCursor_ClassTemplatePartialSpecialization: return ":class-template-partial-specialization";
      case CXCursor_NamespaceAlias:                     return ":namespace-alias";
      case CXCursor_UsingDirective:                     return ":using-directive";
      case CXCursor_UsingDeclaration:                   return ":using-declaration";
      case CXCursor_TypeAliasDecl:                      return ":type-alias-decl";
      case CXCursor_ObjCSynthesizeDecl:                 return ":objc-synthesize-decl";
      case CXCursor_ObjCDynamicDecl:                    return ":objc-dynamic-decl";
      case CXCursor_CXXAccessSpecifier:                 return ":cxx-access-specifier";
      case CXCursor_ObjCSuperClassRef:                  return ":objc-super-class-ref";
      case CXCursor_ObjCProtocolRef:                    return ":objc-protocol-ref";
      case CXCursor_ObjCClassRef:                       return ":objc-class-ref";
      case CXCursor_TypeRef:                            return ":type-ref";
      case CXCursor_CXXBaseSpecifier:                   return ":cxx-base-specifier";
      case CXCursor_TemplateRef:                        return ":template-ref";
      case CXCursor_NamespaceRef:                       return ":namespace-ref";
      case CXCursor_MemberRef:                          return ":member-ref";
      case CXCursor_LabelRef:                           return ":label-ref";
      case CXCursor_OverloadedDeclRef:                  return ":overloaded-decl-ref";
      case CXCursor_VariableRef:                        return ":variable-ref";
      case CXCursor_InvalidFile:                        return ":invalid-file";
      case CXCursor_NoDeclFound:                        return ":no-decl-found";
      case CXCursor_NotImplemented:                     return ":not-implemented";
      case CXCursor_InvalidCode:                        return ":invalid-code";
      case CXCursor_UnexposedExpr:                      return ":unexposed-expr";
      case CXCursor_DeclRefExpr:                        return ":decl-ref-expr";
      case CXCursor_MemberRefExpr:                      return ":member-ref-expr";
      case CXCursor_CallExpr:                           return ":call-expr";
      case CXCursor_ObjCMessageExpr:                    return ":objc-message-expr";
      case CXCursor_BlockExpr:                          return ":block-expr";
      case CXCursor_IntegerLiteral:                     return ":integer-literal";
      case CXCursor_FloatingLiteral:                    return ":floating-literal";
      case CXCursor_ImaginaryLiteral:                   return ":imaginary-literal";
      case CXCursor_StringLiteral:                      return ":string-literal";
      case CXCursor_CharacterLiteral:                   return ":character-literal";
      case CXCursor_ParenExpr:                          return ":paren-expr";
      case CXCursor_UnaryOperator:                      return ":unary-operator";
      case CXCursor_ArraySubscriptExpr:                 return ":array-subscript-expr";
      case CXCursor_BinaryOperator:                     return ":binary-operator";
      case CXCursor_CompoundAssignOperator:             return ":compound-assign-operator";
      case CXCursor_ConditionalOperator:                return ":conditional-operator";
      case CXCursor_CStyleCastExpr:                     return ":cstyle-cast-expr";
      case CXCursor_CompoundLiteralExpr:                return ":compound-literal-expr";
      case CXCursor_InitListExpr:                       return ":init-list-expr";
      case CXCursor_AddrLabelExpr:                      return ":addr-label-expr";
      case CXCursor_StmtExpr:                           return ":stmt-expr";
      case CXCursor_GenericSelectionExpr:               return ":generic-selection-expr";
      case CXCursor_GNUNullExpr:                        return ":gnunull-expr";
      case CXCursor_CXXStaticCastExpr:                  return ":cxx-static-cast-expr";
      case CXCursor_CXXDynamicCastExpr:                 return ":cxx-dynamic-cast-expr";
      case CXCursor_CXXReinterpretCastExpr:             return ":cxx-reinterpret-cast-expr";
      case CXCursor_CXXConstCastExpr:                   return ":cxx-const-cast-expr";
      case CXCursor_CXXFunctionalCastExpr:              return ":cxx-functional-cast-expr";
      case CXCursor_CXXTypeidExpr:                      return ":cxx-typeid-expr";
      case CXCursor_CXXBoolLiteralExpr:                 return ":cxx-bool-literal-expr";
      case CXCursor_CXXNullPtrLiteralExpr:              return ":cxx-null-ptr-literal-expr";
      case CXCursor_CXXThisExpr:                        return ":cxx-this-expr";
      case CXCursor_CXXThrowExpr:                       return ":cxx-throw-expr";
      case CXCursor_CXXNewExpr:                         return ":cxx-new-expr";
      case CXCursor_CXXDeleteExpr:                      return ":cxx-delete-expr";
      case CXCursor_UnaryExpr:                          return ":unary-expr";
      case CXCursor_ObjCStringLiteral:                  return ":objc-string-literal";
      case CXCursor_ObjCEncodeExpr:                     return ":objc-encode-expr";
      case CXCursor_ObjCSelectorExpr:                   return ":objc-selector-expr";
      case CXCursor_ObjCProtocolExpr:                   return ":objc-protocol-expr";
      case CXCursor_ObjCBridgedCastExpr:                return ":objc-bridged-cast-expr";
      case CXCursor_PackExpansionExpr:                  return ":pack-expansion-expr";
      case CXCursor_SizeOfPackExpr:                     return ":size-of-pack-expr";
      case CXCursor_LambdaExpr:                         return ":lambda-expr";
      case CXCursor_ObjCBoolLiteralExpr:                return ":objc-bool-literal-expr";
      case CXCursor_UnexposedStmt:                      return ":unexposed-stmt";
      case CXCursor_LabelStmt:                          return ":label-stmt";
      case CXCursor_CompoundStmt:                       return ":compound-stmt";
      case CXCursor_CaseStmt:                           return ":case-stmt";
      case CXCursor_DefaultStmt:                        return ":default-stmt";
      case CXCursor_IfStmt:                             return ":if-stmt";
      case CXCursor_SwitchStmt:                         return ":switch-stmt";
      case CXCursor_WhileStmt:                          return ":while-stmt";
      case CXCursor_DoStmt:                             return ":do-stmt";
      case CXCursor_ForStmt:                            return ":for-stmt";
      case CXCursor_GotoStmt:                           return ":goto-stmt";
      case CXCursor_IndirectGotoStmt:                   return ":indirect-goto-stmt";
      case CXCursor_ContinueStmt:                       return ":continue-stmt";
      case CXCursor_BreakStmt:                          return ":break-stmt";
      case CXCursor_ReturnStmt:                         return ":return-stmt";
      case CXCursor_GCCAsmStmt:                         return ":gccasm-stmt";
      case CXCursor_ObjCAtTryStmt:                      return ":objc-at-try-stmt";
      case CXCursor_ObjCAtCatchStmt:                    return ":objc-at-catch-stmt";
      case CXCursor_ObjCAtFinallyStmt:                  return ":objc-at-finally-stmt";
      case CXCursor_ObjCAtThrowStmt:                    return ":objc-at-throw-stmt";
      case CXCursor_ObjCAtSynchronizedStmt:             return ":objc-at-synchronized-stmt";
      case CXCursor_ObjCAutoreleasePoolStmt:            return ":objc-autorelease-pool-stmt";
      case CXCursor_ObjCForCollectionStmt:              return ":objc-for-collection-stmt";
      case CXCursor_CXXCatchStmt:                       return ":cxx-catch-stmt";
      case CXCursor_CXXTryStmt:                         return ":cxx-try-stmt";
      case CXCursor_CXXForRangeStmt:                    return ":cxx-for-range-stmt";
      case CXCursor_SEHTryStmt:                         return ":seh-try-stmt";
      case CXCursor_SEHExceptStmt:                      return ":seh-except-stmt";
      case CXCursor_SEHFinallyStmt:                     return ":seh-finally-stmt";
      case CXCursor_MSAsmStmt:                          return ":msasm-stmt";
      case CXCursor_NullStmt:                           return ":null-stmt";
      case CXCursor_DeclStmt:                           return ":decl-stmt";
      case CXCursor_TranslationUnit:                    return ":translation-unit";
      case CXCursor_UnexposedAttr:                      return ":unexposed-attr";
      case CXCursor_IBActionAttr:                       return ":ibaction-attr";
      case CXCursor_IBOutletAttr:                       return ":iboutlet-attr";
      case CXCursor_IBOutletCollectionAttr:             return ":iboutlet-collection-attr";
      case CXCursor_CXXFinalAttr:                       return ":cxx-final-attr";
      case CXCursor_CXXOverrideAttr:                    return ":cxx-override-attr";
      case CXCursor_AnnotateAttr:                       return ":annotate-attr";
      case CXCursor_AsmLabelAttr:                       return ":asm-label-attr";
      case CXCursor_PreprocessingDirective:             return ":preprocessing-directive";
      case CXCursor_MacroDefinition:                    return ":macro-definition";
      case CXCursor_MacroExpansion:                     return ":macro-expansion";
      case CXCursor_InclusionDirective:                 return ":inclusion-directive";
      case CXCursor_ModuleImportDecl:                   return ":module-import-decl";
      default:                                          return ":invalid";}}


const char* cursorLinkage(int linkageKind){
    switch(linkageKind){
      case CXLinkage_NoLinkage:      return ":no-linkage";
      case CXLinkage_Internal:       return ":internal";
      case CXLinkage_UniqueExternal: return ":unique-external";
      case CXLinkage_External:       return ":external";
      default:                       return ":invalid";}}


const char* cursorLanguageKind(int languageKind){
    switch(languageKind){
      case CXLanguage_Invalid:   return ":invalid";
      case CXLanguage_C:         return ":c";
      case CXLanguage_ObjC:      return ":objc";
      case CXLanguage_CPlusPlus: return ":cxx";
      default:                   return ":invalid";}}


void test_all(void);
int main(int argc,const char* const* argv){
    test_all();
    const char* pname=argv[0];
    if(argc<2){
        fprintf(stderr,"%s: missing source file argument.\n",pname);
        return(1);}

    const char* sourceFile=argv[1];
    argv+=2;
    argc-=2;
    const char* const* subArgv=argv_concat(Includes,argv);
    int subArgc=argv_count(subArgv);
    CXIndex idx=clang_createIndex(0,1);
    CXTranslationUnit tu=clang_createTranslationUnitFromSourceFile(idx,sourceFile,subArgc,subArgv,0,0);
    if(0==tu){
        fprintf(stderr,"%s: cannot create the translation unit.",pname);
        return(1);}

    CXCursor cursor=clang_getTranslationUnitCursor(tu);
    if(clang_Cursor_isNull(cursor)){
        printf("nil\n");
    }else{
        printf("(%s",cursorSymbol(clang_getCursorKind(cursor)));
        printf("\n :linkage %s",cursorLinkage(clang_getCursorLinkage(cursor)));
        printf("\n :language-kind %s",cursorLanguageKind(clang_getCursorLanguage(cursor)));

        CXSourceLocation location=clang_getCursorLocation(cursor);
        CXFile file;
        unsigned line;
        unsigned column;
        unsigned offset;

        clang_getSpellingLocation(location,&file,&line,&column,&offset);
        CXString fileName=clang_getFileName(file);
        printf("\n :location (location :file \"%s\" :line %u :column %u :offset %u)",clang_getCString(fileName),line,column,offset);
        clang_disposeString(fileName);

        CXSourceRange range=clang_getCursorExtent(cursor);
        CXSourceLocation start=clang_getRangeStart(range);
        CXSourceLocation end=clang_getRangeEnd(range);

        clang_getSpellingLocation(start,&file,&line,&column,&offset);
        fileName=clang_getFileName(file);
        printf("\n :range (range :start (location :file \"%s\" :line %u :column %u :offset %u)",clang_getCString(fileName),line,column,offset);
        clang_disposeString(fileName);

        clang_getSpellingLocation(end,&file,&line,&column,&offset);
        fileName=clang_getFileName(file);
        printf("\n               :end   (location :file \"%s\" :line %u :column %u :offset %u))",clang_getCString(fileName),line,column,offset);
        clang_disposeString(fileName);




        printf(")\n");
    }
    clang_disposeTranslationUnit(tu);
    return(0);}



//// tests

int test_primes[]={
    172,
    2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
    67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
    139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
    223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
    293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
    383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461,
    463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563,
    569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
    647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739,
    743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
    839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
    941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021};

#define testing(BODY)                                                   \
    do{                                                                 \
        printf("%s",__FUNCTION__);                                      \
        { BODY }                                                        \
        printf(" [OK]\n");                                              \
    } while(0)


void test_compute_primes_to(void){
    testing({
                 int* primes=compute_primes_to(1024);
                 for(int i=0;i<=test_primes[0];i++){
                     assert(test_primes[i]==primes[i]);}
             });}

void test_ceiling_to_nearest_prime(void){
    testing({
                 for(int i=1;i<test_primes[0];i++){
                     int n=test_primes[i]-1;
                     int ceiling=ceiling_to_nearest_prime(n);
                     assert(ceiling==test_primes[i]);}
             });}


void test_all(void){
    testing({
                 test_compute_primes_to();
                 test_ceiling_to_nearest_prime();
             });}


//// THE END ////
ViewGit