text:
// vim:sw=4 ts=4 tw=80 et sta fdm=marker:
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <boost/foreach.hpp>

#include "CppRuntimeSystem.h"
#include "rtedsync.h"

using namespace std;

ostream& out = cout;

static const long nondistributed = 0;

static
void beginScope(RuntimeSystem& rs, const char* desc)
{
  rs.getStackManager().beginScope(desc);
}

static
void endScope(RuntimeSystem& rs)
{
  rs.getStackManager().endScope(1);
}

static
void freeMemory(RuntimeSystem& rs, Address addr, MemoryType::AllocKind kind = akCxxNew)
{
  rs.freeMemory(addr, kind);
}

static
void createMemory(RuntimeSystem& rs, Address addr, size_t sz, MemoryType::AllocKind kind = akCxxNew, const RsType* t = NULL)
{
  rs.createMemory(addr, sz, kind, nondistributed, t);
}

static
void createArray(RuntimeSystem& rs, Address addr, const char* a, const char* b, const RsArrayType* arr)
{
  rs.createArray(addr, a, b, arr, akStack, nondistributed);
}

static
SourceInfo srcPosition(const char* file, size_t src, size_t rted)
{
  SourceInfo si = { file, src, rted };;

  return si;
}

static
void registerPointerChange( RuntimeSystem& rs,
                            Address src,
                            Address tgt,
                            const RsPointerType& t,
                            bool checkPointerMove = false
                          )
{
    rs.registerPointerChange(src, tgt, t, checkPointerMove);
}

//~ static
//~ void registerPointerChange( RuntimeSystem& rs,
                            //~ Address src,
                            //~ Address tgt,
                            //~ bool checkPointerMove = false,
                            //~ bool checkMemLeaks = true
                          //~ )
//~ {
    //~ rs.registerPointerChange(src, tgt, checkPointerMove, checkMemLeaks);
//~ }

static
void registerPointerChange( RuntimeSystem& rs,
                            const std::string& mangledName,
                            Address tgt,
                            bool checkPointerMove = false
                          )
{
    const VariablesType* var = rs.getStackManager().getVariableByMangledName(mangledName);
    const RsPointerType& ptr_type = dynamic_cast<const RsPointerType&>(*var->getType());

    registerPointerChange(rs, var->getAddress(), tgt, ptr_type, checkPointerMove);
}

static
void checkMemRead(RuntimeSystem& rs, Address addr, size_t sz)
{
  rs.checkMemRead(addr, sz);
}

static
void registerMemType(MemoryType& mt, size_t ofs, const RsType* t)
{
  Address addr = mt.beginAddress();

  addr.local += ofs;
  mt.registerMemType(addr, ofs, t);
}

static
void checkMemWrite(RuntimeSystem& rs, Address addr, size_t sz, const RsType* t = NULL)
{
  rs.checkMemWrite(addr, sz, t);
}

inline
Address asAddr(size_t sysaddr)
{
  return rted_Addr(reinterpret_cast<char*>(sysaddr));
}

template <class T>
inline
Address memAddr(const T* t)
{
  return rted_Addr(t);
}

template <class T>
inline
const T* point_to(const Address& addr)
{
  return reinterpret_cast<const T*>(addr.local);
}

static
void checkIfSameChunk(MemoryManager& mm, const Address& base, const Address& addr, size_t sz)
{
  mm.checkIfSameChunk(base, addr, sz);
}

/// \note operator+= is only safe in non distributed environments
inline
Address& operator+=(Address& lhs, long offset)
{
  lhs.local += offset;
  return lhs;
}

/// \note operator+ is only safe in non distributed environments
inline
Address operator+(const Address& lhs, long offset)
{
  Address tmp(lhs);

  tmp.local += offset;
  return tmp;
}

/// \note operator- is only safe in non distributed environments
inline
Address operator-(const Address& lhs, long offset)
{
  return lhs + (-offset);
}

#define TEST_INIT( MSG)                               \
    out << "-- " << (MSG) << endl ;         \
    bool errorFound=false;                            \
    RuntimeSystem& rs = RuntimeSystem::instance();   \
    rs.checkpoint((rted_SourceInfo) { MSG, __LINE__, __LINE__ });              \

//#ASR 07/07/10
//Fixed RuntimeViolation object creation for Cxx Standard
#define TEST_CATCH( TYPE)                                          \
    catch (RuntimeViolation & e)  {                                \
        if( e.getType() != ( TYPE) ) {                             \
            out << "Wrong error detected: "                        \
                << e.getShortDesc() << " instead of "              \
                << RuntimeViolation(TYPE).getShortDesc()           \
                << " : " <<  __LINE__                              \
                << endl;                                           \
            exit(1);                                               \
        }                                                          \
        errorFound=true;                                           \
    }                                                              \
    if(!errorFound)                                                \
    {                                                              \
      out   << "Failed to detect error "                           \
            << RuntimeViolation(TYPE).getShortDesc()           \
                << " : " <<  __LINE__                              \
            << endl;                                               \
      exit(1);                                                     \
    }                                                              \
    errorFound=false;                                              \

#define CHECKPOINT rs.checkpoint( srcPosition( "", __LINE__, __LINE__ ));

#define CLEANUP  {  rs.doProgramExitChecks();  rs.clearStatus(); }

// ------------------- cstdlib string test macros ----------------------------

// each test must define TRY_BODY, as a call to the method being tested, e.g.
//      rs.check_strlen(  (const char*) str)
#define TRY_BODY

#define DEST_SOURCE                                                 \
    char *dest = NULL, *source = NULL;
#define STR1_STR2                                                   \
    char *str1 = NULL, *str2 = NULL;
#define TEST_INIT_STRING( ... )                                     \
    size_t N = 9;                                                   \
    size_t SZ = (N + 1) * sizeof(char);                             \
    __VA_ARGS__;

// Tests that try body will complain if var isn't allocated or if it isn't
// initialized.
//
// As a side effect, this will also initialize var.
#define TEST_STRING_READ( var)                                      \
    /* haven't allocated var yet */                                 \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_READ);                    \
                                                                    \
    var = (char*) malloc( SZ);                                      \
    strcpy( var, "         ");                                      \
    var[ N] = ' ';                                                  \
    createMemory(rs,  memAddr(var), SZ);                         \
                                                                    \
    /* haven't initialized var yet */                               \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_READ);                    \
                                                                    \
    checkMemWrite(rs,  memAddr(var), SZ);

// Does TEST_STRING_READ, but also checks that try body complains if var doesn't
// have a null terminator in allocated memory.
#define TEST_STRING_READ_TERMINATED( var)                           \
    TEST_STRING_READ( var )                                         \
                                                                    \
    /* no null-terminator in var */                                 \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_READ);                    \
    var[ N] = '\0';

#define TEST_STRING_WRITE( var, badsz, oksz)                        \
    /* haven't allocated var yet */                                 \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_WRITE);                   \
    var = (char*) malloc( badsz );                                  \
    createMemory(rs,  memAddr(var), badsz );                     \
    /* var isn't large enough */                                    \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_WRITE);                   \
                                                                    \
    freeMemory(rs,  memAddr(var));                               \
    var = (char*) realloc( var, oksz );                             \
    createMemory(rs,  memAddr(var), oksz );

#define TEST_STRING_CAT( var, oksz)                                 \
    /* haven't allocated var yet */                                 \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_READ);                    \
    var = (char*) malloc( oksz );                                   \
    createMemory(rs,  memAddr(var), oksz );                      \
    var[ 0 ] = ' ';                                                 \
    var[ 1 ] = '\0';                                                \
    checkMemWrite(rs,  memAddr(var), 2);                         \
    /* var is large enough to hold source, but not large enough */  \
    /* for source to be appended */                                 \
    try { TRY_BODY }                                                \
    TEST_CATCH( RuntimeViolation::INVALID_WRITE);                   \
    var[ 0 ] = '\0';

// Tests that try body complains if either str1 or str2 lacks a null terminator
// in allocated memory, or if either isn't allocated yet.
//
// Tests that try body does not complain when both of these conditions are
// satisfied.
#define TEST_STR1_STR2                                              \
    TEST_INIT_STRING( STR1_STR2)                                    \
                                                                    \
    TEST_STRING_READ_TERMINATED( str1)                              \
    TEST_STRING_READ_TERMINATED( str2)                              \
    TRY_BODY                                                        \
    TEST_STRING_CLEANUP( str1)                                      \
    TEST_STRING_CLEANUP( str2)                                      \
                                                                    \
    TEST_STRING_READ_TERMINATED( str2)                              \
    TEST_STRING_READ_TERMINATED( str1)                              \
    TRY_BODY                                                        \
    TEST_STRING_CLEANUP( str2)                                      \
    TEST_STRING_CLEANUP( str1)

#define TEST_STRING_CLEANUP( var)                                   \
    free( var );                                                    \
    freeMemory(rs,  memAddr(var) );                              \
    var = NULL;

// -------------------------------------- Memory Checker ------------------------------------------

void testSuccessfulMallocFree()
{
    TEST_INIT("Testing Successful Malloc Free");
    errorFound=false; /*tps unused variable - removing warning */

    createMemory(rs, asAddr(42),10);

    rs.log() << "After creation" << endl;
    rs.printMemStatus();
    freeMemory(rs, asAddr(42));

    rs.log() << "After free" << endl;
    rs.printMemStatus();

    CLEANUP
}

void testFreeInsideBlock()
{
    TEST_INIT("Testing Invalid Free in allocated Block");

    createMemory(rs, asAddr(42),10);

    try  {  freeMemory(rs, asAddr(44)); }
    TEST_CATCH(RuntimeViolation::INVALID_FREE);

    //free the right one
    freeMemory(rs, asAddr(42));

    CLEANUP

}

void testInvalidFree()
{
    TEST_INIT("Testing invalid Free outside allocated Block");

    createMemory(rs, asAddr(42),10);

    try  {  freeMemory(rs, asAddr(500));   }
    TEST_CATCH(RuntimeViolation::INVALID_FREE)

    //free the right one
    freeMemory(rs, asAddr(42));

    CLEANUP
}

void testInvalidStackFree()
{
    TEST_INIT("Testing invalid Free of stack memory");

    // freeing heap memory should be fine
    createMemory(rs, asAddr(42),10);
    freeMemory(rs, asAddr(42));

    // but freeing stack memory is not okay
    rs.createStackMemory(asAddr(42),sizeof(int),"SgTypeInt");
    try  {  freeMemory(rs, asAddr(42));   }
    TEST_CATCH(RuntimeViolation::INVALID_FREE)

    // test cleanup
    freeMemory(rs, asAddr(42), akStack);

    CLEANUP
}

void testDoubleFree()
{
    TEST_INIT("Testing Double Free");

    createMemory(rs, asAddr(42),10);
    freeMemory(rs, asAddr(42));

    try  {  freeMemory(rs, asAddr(42));  }
    TEST_CATCH(RuntimeViolation::INVALID_FREE)

    CLEANUP
}

void testDoubleAllocation()
{
    TEST_INIT("Testing Double Allocation");

    createMemory(rs, asAddr(42),10);

    try{  createMemory(rs, asAddr(45),10);  }
    TEST_CATCH(RuntimeViolation::DOUBLE_ALLOCATION)

    freeMemory(rs, asAddr(42));

    CLEANUP
}

void testMemoryLeaks()
{
    TEST_INIT("Testing detection of memory leaks");

    createMemory(rs, asAddr(42),10);
    createMemory(rs, asAddr(60),10);
    createMemory(rs, asAddr(0),10);

    freeMemory(rs, asAddr(60));

    try{ rs.doProgramExitChecks(); }
    TEST_CATCH(RuntimeViolation::MEMORY_LEAK)

    freeMemory(rs, asAddr(0));
    freeMemory(rs, asAddr(42));

    CLEANUP
}

void testEmptyAllocation()
{
    TEST_INIT("Testing detection of empty allocation");

    try { createMemory(rs, asAddr(12),0); }
    TEST_CATCH(RuntimeViolation::EMPTY_ALLOCATION)

    CLEANUP
}

void testMemAccess()
{
    TEST_INIT("Testing memory access checks");

    createMemory(rs, asAddr(0),10);

    checkMemWrite(rs, asAddr(9),1);
    try { checkMemWrite(rs, asAddr(9),2); }
    TEST_CATCH(RuntimeViolation::INVALID_WRITE)

    try { checkMemRead(rs, asAddr(0), 4); }
    TEST_CATCH(RuntimeViolation::INVALID_READ)

    checkMemWrite(rs, asAddr(0), 5);
    checkMemRead(rs, asAddr(3), 2);

    freeMemory(rs, asAddr(0));

    CLEANUP
}

void testMallocDeleteCombinations()
{
    TEST_INIT("Testing malloc/delete, new/free and similar combinations");

    // memory created via malloc
    createMemory(rs,  asAddr(0x42), sizeof( long ), akCHeap );
    // can't be freed via non-free (e.g. delete)
    try { freeMemory(rs,  asAddr(0x42), akCxxNew ); }
    TEST_CATCH( RuntimeViolation::INVALID_FREE )
    // but can be freed via free
    freeMemory(rs,  asAddr(0x42), akCHeap );

    // memory created via new
    createMemory(rs,  asAddr(0x42), sizeof( long ), akCxxNew );
    // can't be freed via free
    try { freeMemory(rs,  asAddr(0x42), akCHeap ); }
    TEST_CATCH( RuntimeViolation::INVALID_FREE )
    // but can be freed via delete
    freeMemory(rs,  asAddr(0x42), akCxxNew );

    CLEANUP
}

// -------------------------------------- Stack and Variables Tests ------------------------------------------

/*
void testStack()
{
    Address addr=0;

    RuntimeSystem * rs = RuntimeSystem::instance();
    rs.createVariable(addr+=4,"GlobalVar1","MangledGlobal1","SgInt");
    rs.createVariable(addr+=4,"GlobalVar2","MangledGlobal2","SgDouble");

    cout << endl << endl << "After Globals" << endl;

    rs.printStack(cout);
    rs.printMemStatus(cout);

    beginScope(rs, "Function1");
    rs.createVariable(addr+=4,"Function1Var1","Mangled","SgInt");
    rs.createVariable(addr+=4,"Fucntion1Var2","Mangled","SgDouble");

    checkMemWrite(rs, 2348080,4);
    checkMemRead(rs, addr-4,4);

    cout << endl << endl << "After Function1" << endl;
    rs.printStack(cout);
    rs.printMemStatus(cout);

    endScope(rs);
    cout << endl << endl << "After return of function" << endl;
    rs.printStack(cout);
    rs.printMemStatus(cout);
}
*/

// -------------------------------------- File Monitoring Tests ------------------------------------------

void testFileDoubleClose()
{
    TEST_INIT("Testing double file close");

    rs.registerFileOpen((FILE*)42,"MyFileName.txt",READ);
    rs.registerFileClose((FILE*)42);

    try { rs.registerFileClose((FILE*)42); }
    TEST_CATCH(RuntimeViolation::INVALID_FILE_CLOSE)

    CLEANUP
}

void testFileDoubleOpen()
{
    TEST_INIT("Testing double file open");

    rs.registerFileOpen((FILE*)42,"MyFileName.txt",READ);
    try {  rs.registerFileOpen((FILE*)42,"Other.txt",READ); }
    TEST_CATCH(RuntimeViolation::DOUBLE_FILE_OPEN)

    rs.registerFileClose((FILE*)42);

    CLEANUP
}

void testFileInvalidClose()
{
    TEST_INIT("Testing invalid file close");

    rs.registerFileOpen((FILE*)42,"MyFileName.txt",READ);
    try {  rs.registerFileClose((FILE*)43); }
    TEST_CATCH(RuntimeViolation::INVALID_FILE_CLOSE)

    rs.registerFileClose((FILE*)42);

    CLEANUP
}

void testFileUnclosed()
{
    TEST_INIT("Testing detection of unclosed files");

    rs.registerFileOpen((FILE*)42,"MyFileName.txt",READ);
    try {  rs.doProgramExitChecks(); }
    TEST_CATCH(RuntimeViolation::UNCLOSED_FILES)

    rs.registerFileClose((FILE*)42);

    CLEANUP
}

void testFileInvalidAccess()
{
    TEST_INIT("Testing invalid file-access");

    try{ rs.registerFileOpen(NULL,"name",READ ); }
    TEST_CATCH(RuntimeViolation::INVALID_FILE_OPEN)

    FILE * fh = (FILE*)42;
    // some allowed operations
    rs.registerFileOpen(fh,"MyFileName.txt",READ | WRITE);
    rs.checkFileAccess(fh,true);
    rs.checkFileAccess(fh,false);
    rs.registerFileClose(fh);

    // check if illegal write is detected
    rs.registerFileOpen(fh,"MyFileName.txt",READ);
    rs.checkFileAccess(fh,true);
    try {  rs.checkFileAccess(fh,false); } //invalid write
    TEST_CATCH(RuntimeViolation::INVALID_FILE_ACCESS)
    rs.registerFileClose(fh);

    // check if illegal read is detected
    rs.registerFileOpen(fh,"MyFileName.txt",WRITE);
    rs.checkFileAccess(fh,false);
    try {  rs.checkFileAccess(fh,true); } //invalid read
    TEST_CATCH(RuntimeViolation::INVALID_FILE_ACCESS)
    rs.registerFileClose(fh);

    try {  rs.checkFileAccess((FILE*)43,true); }
    TEST_CATCH(RuntimeViolation::INVALID_FILE_ACCESS)

    CLEANUP
}

void testScopeFreesStack()
{
    TEST_INIT("Testing that exiting a scope frees stack variables")
    errorFound=false; /*tps unused variable - removing warning */

    beginScope(rs, "main");
    rs.createVariable(
        asAddr(4),
        "my_var",
        "mangled_my_var",
        "SgTypeInt",
        akStack,
        nondistributed
    );
    endScope(rs);

    CLEANUP
}

// Tests that an implicit scope exists, i.e. main's scope.  Calling
// createVariable without ever calling beginScope or endScope should not result
// in memory errors.Address
void testImplicitScope()
{
    TEST_INIT("Testing that an implicit scope exists for globals/main")
    errorFound=false; /*tps unused variable - removing warning */

    rs.createVariable(
        asAddr(4),
        "my_var",
        "mangled_my_var",
        "SgTypeInt",
        akStack,
        nondistributed
    );

    CLEANUP
}

// -------------------------------------- Pointer Tracking Tests ------------------------------------------

 void testLostMemRegion()
{
    //
    TEST_INIT("Testing detection of lost mem-regions");
    TypeSystem& ts = rs.getTypeSystem();

    createMemory(rs, asAddr(10), 2*sizeof(int));
    createMemory(rs, asAddr(18), 2*sizeof(int));

    Address       addr = asAddr(100);
    int           ptrSize = sizeof(void*);

    beginScope(rs, "Scope1");
        rs.createVariable(addr+=ptrSize,"p1_to_10","mangled_p1_to_10",*ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        registerPointerChange(rs, "mangled_p1_to_10", asAddr(10));

        rs.createVariable(addr+=ptrSize,"p1_to_18","mangled_p1_to_18",*ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        registerPointerChange(rs, "mangled_p1_to_18", asAddr(18));

        beginScope(rs, "Scope2");
            rs.createVariable(addr+=ptrSize,"p2_to_10","mangled_p2_to_10",*ts.getPointerType("SgTypeInt"), akStack, nondistributed);
            registerPointerChange(rs, "mangled_p2_to_10", asAddr(10));
        endScope(rs);

        try{ registerPointerChange(rs, "mangled_p1_to_10", asAddr(0)); }
        TEST_CATCH(RuntimeViolation::MEM_WITHOUT_POINTER)

        try{ registerPointerChange(rs, "mangled_p1_to_18", asAddr(0)); }
        TEST_CATCH(RuntimeViolation::MEM_WITHOUT_POINTER)

    endScope(rs);

    freeMemory(rs, asAddr(10));
    freeMemory(rs, asAddr(18));

    CLEANUP
}

void testLostMemRegionFromDoublePointer()
{
    TEST_INIT(  "Testing detection of lost mem region, which was previously "
                "pointed to by heap ptr")
    TypeSystem&          ts = rs.getTypeSystem();

    AddressDesc          ptr_desc = rted_ptr();
    const RsPointerType* int_ptr = ts.getPointerType( "SgTypeInt", ptr_desc );
    AddressDesc          ptr_ptr_desc = rted_address_of(ptr_desc);
    const RsPointerType* int_ptr_ptr = ts.getPointerType( "SgTypeInt", ptr_ptr_desc );

    Address              var_addr = asAddr(0x7ffb0);
    Address              heap_addr_outer = asAddr(0x42);
    Address              heap_addr_inner = asAddr(0x24601);

    createMemory(rs,  heap_addr_outer, 2 * sizeof( int* ));
    createMemory(rs,  heap_addr_inner, 2 * sizeof( int ));

    // int** ptr;
    rs.createVariable( var_addr, "int**", "mangled_int**", *int_ptr_ptr, akStack, nondistributed );
    // ptr = (int**) malloc( 2 * sizeof( int* ));
    registerPointerChange( rs, var_addr, heap_addr_outer, *int_ptr_ptr, false );

    // ptr[ 0 ] = (int*) malloc( 2 * sizeof( int ));
    checkMemWrite( rs, heap_addr_outer, sizeof( int* ), int_ptr );
    rs.checkpoint( (rted_SourceInfo) {"?", __LINE__, __LINE__} );
    registerPointerChange( rs, heap_addr_outer, heap_addr_inner, *int_ptr, false );

    try{ freeMemory(rs,  heap_addr_outer ); }
    TEST_CATCH( RuntimeViolation::MEM_WITHOUT_POINTER )

    freeMemory(rs,  heap_addr_inner );
    freeMemory(rs,  heap_addr_outer );

    CLEANUP
}

void testPointerChanged()
{
    TEST_INIT("Pointer Tracking test: Pointer changes chunks");

    createMemory(rs, asAddr(10), 2*sizeof(int));
    createMemory(rs, asAddr(18), 2*sizeof(int));

    TypeSystem& ts = rs.getTypeSystem();

    std::cout << "--- Scope 1" << std::endl;

    rs.setViolationPolicy( RuntimeViolation::INVALID_PTR_ASSIGN, ViolationPolicy::Exit );
    // Case1: change of allocation chunk
    Address addr = asAddr(100);
    int ptrSize = sizeof(void*);
    beginScope(rs, "Scope1");

        rs.createVariable(addr+=ptrSize,"p1_to_10","mangled_p1_to_10", *ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        registerPointerChange(rs, "mangled_p1_to_10", asAddr(10));

        rs.createVariable(addr+=ptrSize,"p2_to_10","mangled_p2_to_10", *ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        registerPointerChange(rs, "mangled_p2_to_10", asAddr(10));

        rs.createVariable(addr+=ptrSize,"p1_to_18","mangled_p1_to_18", *ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        registerPointerChange(rs, "mangled_p1_to_18", asAddr(18));

        try{ registerPointerChange(rs, "mangled_p1_to_10", asAddr(18), true); }
        TEST_CATCH(RuntimeViolation::INVALID_PTR_ASSIGN )

        rs.checkpoint((rted_SourceInfo) {"?", __LINE__, __LINE__});
        registerPointerChange(rs, "mangled_p1_to_18", asAddr(18+sizeof(int)));

        freeMemory(rs, asAddr(10));
        freeMemory(rs, asAddr(18));
    endScope(rs);

    std::cout << "--- Scope 2" << std::endl;

    // Case2: change of "type-chunk"
    beginScope(rs, "Scope2");
        struct A { int arr[10]; int behindArr; };
        RsClassType * typeA = &ts.getClassType("A",sizeof(A),false);
        typeA->addMember("arr",ts.getArrayType("SgTypeInt",10 * sizeof(int)), offsetof(A,arr));
        typeA->addMember("behindArr",ts.getTypeInfo("SgTypeInt"),offsetof(A,behindArr));
        assert(typeA->isComplete());

        // Create an instance of A on stack
        rs.createVariable(asAddr(0x42),"instanceOfA","mangled", *typeA, akStack, nondistributed);

        rs.createVariable(asAddr(0x100),"intPtr","mangled_intPtr", *ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        registerPointerChange(rs, "mangled_intPtr",asAddr(0x42));

        try{ registerPointerChange(rs, "mangled_intPtr", asAddr(0x42) + 10*sizeof(int),true); }
        TEST_CATCH(RuntimeViolation::INVALID_PTR_ASSIGN )
    endScope(rs);

    std::cout << "--- Scope 3" << std::endl;

    // use default policy for case 3
    rs.setViolationPolicy( RuntimeViolation::INVALID_PTR_ASSIGN, ViolationPolicy::InvalidatePointer );
    // Case3: into non-allocated memory
    beginScope(rs, "Scope3" );

        CHECKPOINT
        int *ptr = (int*) (&ptr);
        rs.createVariable( memAddr(&ptr),"s3_ptr","mangled_s3_ptr", *ts.getPointerType("SgTypeInt"), akStack, nondistributed);

        CHECKPOINT
        // default policy is to invalidate pointers
        registerPointerChange(rs, memAddr(&ptr), memAddr(ptr), *ts.getPointerType("SgTypeInt"), true);

        CHECKPOINT
        try{ checkMemRead(rs,  memAddr(ptr), sizeof(ptr)); }
        TEST_CATCH(RuntimeViolation::INVALID_READ )

    endScope(rs);

    CLEANUP
}

void testInvalidPointerAssign()
{
    TEST_INIT("Testing Invalid Pointer assign");

    TypeSystem& ts = rs.getTypeSystem();

    beginScope(rs, "Scope2");
        // Create an instance of A on stack
        rs.createVariable(asAddr(0x42), "instanceOfA","mangled","SgTypeDouble", akStack, nondistributed);
        rs.createVariable(asAddr(0x100), "intPtr","mangled_intPtr", *ts.getPointerType("SgTypeInt"), akStack, nondistributed);
        // Try to access double with an int ptr
        try { registerPointerChange(rs, "mangled_intPtr", asAddr(0x42)); }
        TEST_CATCH ( RuntimeViolation::INVALID_TYPE_ACCESS )

    endScope(rs);
    CLEANUP
}

void testPointerTracking()
{
    TEST_INIT("Testing Pointer tracking")
    errorFound=false; /*tps unused variable - removing warning */

    TypeSystem& ts = rs.getTypeSystem();

    // class A { int arr[2]; int intBehindArr; }
    RsClassType * type = &ts.getClassType("A",3*sizeof(int),false);
    type->addMember("arr",ts.getArrayType("SgTypeInt",2 * sizeof(int)));
    type->addMember("intBehindArr",ts.getTypeInfo("SgTypeInt"));

    beginScope(rs, "TestScope");
    rs.createVariable(asAddr(42), "instanceOfA","mangled","A", akStack, nondistributed);

    rs.createVariable(asAddr(100), "pointer","mangledPointer", *ts.getPointerType("A"), akStack, nondistributed);

    //rs.setQtDebuggerEnabled(true);
    //rs.checkpoint(SourcePosition());

    endScope(rs);

    CLEANUP
}

// Note, this doesn't test for non-aligned access of the outer array, which
// doesn't work correctly.  e.g.
//
//  checkIfSameChunk( 0x100, 0x100 + sizeof( int ), 3 * sizeof( int ))
//
// which checks for access of an int[3] at x[ 0 ][ 1 ], which is within the same
// memory chunk, but not really legal.
void testMultidimensionalStackArrayAccess()
{
    TEST_INIT("Testing Multidimensional Array Access")

    TypeSystem& ts = rs.getTypeSystem();
    MemoryManager& mm = rs.getMemManager();

    size_t intsz = sizeof( int );

    // int x[ 2 ][ 3 ]
    //  type array of array of int
    const RsArrayType* type = ts.getArrayType( ts.getArrayType( "SgTypeInt", 3 * intsz), 2 * 3 * sizeof(int) );

    beginScope(rs, "TestScope");

    createArray( rs, asAddr(0x100), "array[2][3]", "mangled_array[2][3]", type );

    // check legal memory read from same memory region, but out of bounds on
    // inner array, i.e check
    //  x[ 0 ][ 3 ]     // actually x[ 1 ][ 0 ]
    try { checkIfSameChunk( mm, asAddr(0x100), asAddr(0x100) + 3 * intsz, intsz); }
    TEST_CATCH ( RuntimeViolation::POINTER_CHANGED_MEMAREA )
    // as above, but out of bounds in the other direction
    try { checkIfSameChunk( mm, asAddr(0x100) + 3 * intsz, asAddr(0x100) + 2 * intsz, intsz); }
    TEST_CATCH ( RuntimeViolation::POINTER_CHANGED_MEMAREA )

    CHECKPOINT
    // as above, but this time legally access the sub array
    checkIfSameChunk( mm, asAddr(0x100) + 3 * intsz, asAddr(0x100) + 3 * intsz, intsz);

    endScope(rs);

    CLEANUP
}

void testArrayAccess()
{
    TEST_INIT("Testing Heap Array")
    TypeSystem&          ts = rs.getTypeSystem();
    Address              heapAddr = asAddr(0x42);

    createMemory(rs, heapAddr,10*sizeof(int));
    createMemory(rs, heapAddr+10*sizeof(int),10); //allocate second chunk directly afterwards

    rs.setViolationPolicy( RuntimeViolation::INVALID_PTR_ASSIGN, ViolationPolicy::Exit );
    beginScope(rs, "Scope");

    Address              pointerAddr = asAddr(0x100);
    const RsPointerType* intptr = ts.getPointerType("SgTypeInt");

    rs.createVariable(pointerAddr, "intPointer", "mangled_intPointer", *intptr, akStack, nondistributed);
    CHECKPOINT
    registerPointerChange(rs, pointerAddr, heapAddr, *intptr, false);

    CHECKPOINT
    //simulate iteration over array
    for(int i=0; i<10 ; i++)
        registerPointerChange(rs, pointerAddr, heapAddr+ i*sizeof(int), *intptr, true);

    // write in second allocation ( not allowed to changed mem-chunk)
    try { registerPointerChange(rs, pointerAddr,heapAddr+ 10*sizeof(int), *intptr, true); }
    TEST_CATCH ( RuntimeViolation::INVALID_PTR_ASSIGN )

    // write in illegal mem region before
    try { registerPointerChange(rs, pointerAddr, heapAddr - sizeof(int), *intptr, true); }
    TEST_CATCH ( RuntimeViolation::INVALID_READ )

    freeMemory(rs, heapAddr);
    freeMemory(rs, heapAddr+10*sizeof(int));

    endScope(rs);
    rs.setViolationPolicy( RuntimeViolation::INVALID_PTR_ASSIGN, ViolationPolicy::InvalidatePointer );

    CLEANUP
}

void testDoubleArrayHeapAccess()
{
    TEST_INIT("Testing Heap Double Array (e.g. int**)")
    errorFound=false; /*tps unused variable - removing warning */
    TypeSystem& ts = rs.getTypeSystem();

    AddressDesc          ptr_desc = rted_ptr();
    const RsPointerType* int_ptr = ts.getPointerType( "SgTypeInt", ptr_desc );
    AddressDesc          ptr_ptr_desc = rted_address_of(ptr_desc);
    const RsPointerType* int_ptr_ptr = ts.getPointerType( "SgTypeInt", ptr_ptr_desc );

    Address var_addr = asAddr(0x7ffb0);
    Address heap_addr_outer = asAddr(0x42);
    Address heap_addr_inner = asAddr(0x24601);

    createMemory(rs,  heap_addr_outer, 2 * sizeof( int* ));
    createMemory(rs,  heap_addr_inner, 2 * sizeof( int ));

    // int** ptr;
    rs.createVariable( var_addr, "int**", "mangled_int**", *int_ptr_ptr, akStack, nondistributed );
    // ptr = (int**) malloc( 2 * sizeof( int* ));
    registerPointerChange( rs, var_addr, heap_addr_outer, *int_ptr_ptr, false );

    // ptr[ 0 ] = (int*) malloc( 2 * sizeof( int ));
    checkMemWrite( rs, heap_addr_outer, sizeof( int* ), int_ptr );
    rs.checkpoint(srcPosition("?", __LINE__, __LINE__));
    registerPointerChange( rs, heap_addr_outer, heap_addr_inner, *int_ptr );

    freeMemory(rs, heap_addr_inner );
    freeMemory(rs, heap_addr_outer );

    CLEANUP
}

// -------------------------------------- CStdLib Tests ------------------------------------------

void test_memcpy()
{
    TEST_INIT("Testing calls to memcpy");

    Address address = asAddr(0);

    createMemory(rs,  address += 4, 16);
    Address ptr1 = address;

    createMemory(rs,  address += 16, 16);
    checkMemWrite(rs,  address, 16);
    Address ptr2 = address;

    // 4..20 doesn't overlap 20..36
    rs.check_memcpy( point_to<void>(ptr1), point_to<void>(ptr2), 16);

    // but 4..20 overlaps 16..32
    try { rs.check_memcpy( point_to<void>(ptr1), point_to<void>(ptr2 - 4), 16);}
    TEST_CATCH( RuntimeViolation::INVALID_MEM_OVERLAP)

    freeMemory(rs,  ptr1);
    freeMemory(rs,  ptr2);

    CLEANUP
}

void test_memmove()
{
    TEST_INIT("Testing calls to memmove");
    Address address = asAddr(0);

    createMemory(rs,  address += 4, 16);
    Address ptr1 = address;

    createMemory(rs,  address += 16, 16);
    Address ptr2 = address;

    try { rs.check_memmove( point_to<void>(ptr1), point_to<void>(ptr2 - 4), 16);}
    TEST_CATCH( RuntimeViolation::INVALID_READ)

    checkMemWrite(rs,  address, 16);
    rs.check_memmove( point_to<void>(ptr1), point_to<void>(ptr2), 16);

    freeMemory(rs,  ptr1);
    freeMemory(rs,  ptr2);

    CLEANUP
}

void test_strcpy()
{
    //~ TEST_INIT("Testing calls to strcpy");
//~
    //~ #undef TRY_BODY
    //~ #define TRY_BODY rs.check_strcpy(  dest, (const char*) source);
    //~ TEST_INIT_STRING( DEST_SOURCE)
    //~ TEST_STRING_READ_TERMINATED( source)
    //~ TEST_STRING_WRITE( dest, SZ / 2, SZ)
//~
    //~ // also, it's not legal for the strings to overlap
    //~ try { rs.check_strcpy( source + (N/2), source); }
    //~ TEST_CATCH( RuntimeViolation::INVALID_MEM_OVERLAP);
//~
    //~ TRY_BODY
    //~ TEST_STRING_CLEANUP( dest)
    //~ TEST_STRING_CLEANUP( source)
//~
    //~ CLEANUP
}

void test_strncpy()
{
    //~ TEST_INIT("Testing calls to strncpy");
//~
    //~ #undef TRY_BODY
    //~ #define TRY_BODY rs.check_strncpy(  dest, (const char*) source, N / 2);
    //~ TEST_INIT_STRING( DEST_SOURCE)
    //~ TEST_STRING_READ( source)
    //~ TEST_STRING_WRITE( dest, SZ / 4, SZ / 2)
//~
    //~ // also it's not legal for the strings to overlap
    //~ try { rs.check_strncpy(  source + (N/2),  source, N); }
    //~ TEST_CATCH( RuntimeViolation::INVALID_MEM_OVERLAP);
//~
    //~ TRY_BODY
    //~ TEST_STRING_CLEANUP( dest)
    //~ TEST_STRING_CLEANUP( source)
//~
    //~ CLEANUP
}

void test_strcat()
{
    TEST_INIT("Testing calls to strcat");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strcat(  dest, (const char*) source);
    TEST_INIT_STRING( DEST_SOURCE)
    TEST_STRING_READ_TERMINATED( source)
    TEST_STRING_READ_TERMINATED( dest)
    TEST_STRING_CLEANUP( dest)
    TEST_STRING_CAT( dest, SZ)

    TRY_BODY
    TEST_STRING_CLEANUP( dest)
    TEST_STRING_CLEANUP( source)

    CLEANUP
}

void test_strncat()
{
    TEST_INIT("Testing calls to strncat");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strncat(  dest, (const char*) source, N / 2);
    TEST_INIT_STRING( DEST_SOURCE)
    TEST_STRING_READ( source)
    TEST_STRING_READ( dest)
    TEST_STRING_CLEANUP( dest)
    TEST_STRING_CAT( dest, SZ / 2)

    TRY_BODY
    TEST_STRING_CLEANUP( dest)
    TEST_STRING_CLEANUP( source)

    CLEANUP
}

void test_strchr()
{
    TEST_INIT("Testing calls to strchr");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strchr(  (const char*) str, 'x');
    TEST_INIT_STRING( char *str = NULL)
    TEST_STRING_READ_TERMINATED( str)

    TRY_BODY
    TEST_STRING_CLEANUP( str)

    CLEANUP
}

void test_strpbrk()
{
    TEST_INIT("Testing calls to strpbrk");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strpbrk(  (const char*) str1, (const char*) str2);
    TEST_STR1_STR2

    CLEANUP
}

void test_strspn()
{
    TEST_INIT("Testing calls to strspn");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strspn(  (const char*) str1, (const char*) str2);
    TEST_STR1_STR2

    CLEANUP
}

void test_strstr()
{
    TEST_INIT("Testing calls to strstr");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strstr(  (const char*) str1, (const char*) str2);
    TEST_STR1_STR2

    CLEANUP
}

void test_strlen()
{
    TEST_INIT("Testing calls to strlen");

    #undef TRY_BODY
    #define TRY_BODY rs.check_strlen(  (const char*) str);
    TEST_INIT_STRING( char* str = NULL)
    TEST_STRING_READ_TERMINATED( str)

    TRY_BODY
    TEST_STRING_CLEANUP( str)

    CLEANUP
}

void test_memcpy_strict_overlap()
{
    TEST_INIT(  "Testing that memcpy complains about overlap for allocated "
                "ranges, not merely for the copied ranges.")

    const char* s1;
    const char* s2 = "here is string 2";

    createMemory(rs,  memAddr(s2), 16 * sizeof( char ));
    checkMemWrite(rs,  memAddr(s2), 16 * sizeof( char ));

    s1 = &s2[ 7 ];

    // even though there's no overlap with the copied ranges, memcpy shouldn't
    // be called when the allocated blocks overlap
    try { rs.check_memcpy( s1, s2, 3);}
    TEST_CATCH( RuntimeViolation::INVALID_MEM_OVERLAP)

    freeMemory(rs,  memAddr(s2));

    CLEANUP
}

void test_meminit_nullterm_included()
{
    TEST_INIT(  "Testing that strcpy et. al set the full destination "
                "initialized, including the null terminator");
    errorFound=false; /*tps unused variable - removing warning */
    size_t n = 9; // sizeof("a string") + 1 for \0
    char s1[ 9 ];
    char s2[ 9 ] = "a string";
    char s3[ 9 ];

    createMemory(rs,  memAddr(s1), n);
    createMemory(rs,  memAddr(s2), n);
    createMemory(rs,  memAddr(s3), n);

    checkMemWrite(rs,  memAddr(s2), n);

    rs.check_strcpy( (char*) s1, (const char*) s2);
    strcpy( s1, s2);
    rs.check_strcpy( (char*) s3, (const char*) s1);

    freeMemory(rs,  memAddr(s1));
    freeMemory(rs,  memAddr(s2));
    freeMemory(rs,  memAddr(s3));
    CLEANUP
}

void test_range_overlap()
{
    TEST_INIT("Testing that overlap checks cover ranges")

    char* s1;
    char s2[ 20 ];
    char s3[ 9 ] = "a string";

    createMemory(rs,  memAddr(s2), sizeof(s2));
    createMemory(rs,  memAddr(s3), sizeof(s3));
    checkMemWrite(rs,  memAddr(s3), sizeof(s3));
    rs.check_strcpy( s2, s3);

    strcpy( s2, s3);
    s1 = &s2[ 3 ];

    try { rs.check_strcat( s1, s2);}
    TEST_CATCH( RuntimeViolation::INVALID_MEM_OVERLAP)

    rs.check_strcpy( &s2[ 10 ], s3);
    strcpy( &s2[ 10 ], s3);

    // this should be fine -- the cat doesn't reach s2[ 10 ]
    s2[ 0 ] = '\0';
    s1 = &s2[0];
    rs.check_strcat( s1, &s2[ 10 ]);

    s1[ 0 ] = ' ';
    s1[ 3 ] = '\0';

    // now the cat will reach and an overlap occurs
    try { rs.check_strcat( s1, &s2[ 10 ]);}
    TEST_CATCH( RuntimeViolation::INVALID_MEM_OVERLAP)

    freeMemory(rs,  memAddr(s2));
    freeMemory(rs,  memAddr(s3));

    CLEANUP
}

void testTypeSystemDetectNested()
{
    TEST_INIT("Testing TypeSystem: nested type detection")

    TypeSystem& ts = rs.getTypeSystem();

    // Register Struct A
    struct A { int a1; char a2; double a3; };
    RsClassType * typeA = &ts.getClassType("A",sizeof(A),false);
    typeA->addMember("a1",ts.getTypeInfo("SgTypeInt"),   offsetof(A,a1));
    typeA->addMember("a2",ts.getTypeInfo("SgTypeChar"),  offsetof(A,a2));
    typeA->addMember("a3",ts.getTypeInfo("SgTypeDouble"),offsetof(A,a3));
    assert(typeA->isComplete());

    // Register Struct B
    struct B { A arr[10]; char b1; int b2; };
    RsClassType * typeB = &ts.getClassType("B",sizeof(B),false);
    typeB->addMember("arr",ts.getArrayType("A",10 * sizeof(struct A)),    offsetof(B,arr));
    typeB->addMember("b1",ts.getTypeInfo("SgTypeChar"),offsetof(B,b1) );
    typeB->addMember("b2",ts.getTypeInfo("SgTypeInt"), offsetof(B,b2));
    assert(typeB->isComplete());

    CHECKPOINT
    // Create Memory with first an A and then a B
    const Address ADDR = asAddr(42);
    createMemory(rs, ADDR, sizeof(A)+sizeof(B));
    MemoryType* mt = rs.getMemManager().getMemoryType(ADDR);
    registerMemType(*mt, 0, ts.getTypeInfo("A"));
    CHECKPOINT
    registerMemType(*mt, 0 + sizeof(A), ts.getTypeInfo("B"));
    CHECKPOINT
    registerMemType(*mt, 0 + sizeof(A) + offsetof(A,a3), ts.getTypeInfo("SgTypeDouble"));

    //rs.setQtDebuggerEnabled(true);
    //rs.checkpoint(SourcePosition());
    //rs.setQtDebuggerEnabled(false);
    /*
    RsType * type1 = mt->getTypeAt(sizeof(A)+offsetof(B,arr),sizeof(A));
    RsType * type2 = mt->getTypeAt(sizeof(A)+offsetof(B,arr) + 5*sizeof(A)+1,sizeof(A));
    cout << "Type1 " << (type1 ? type1->getName() : "NULL") << endl;
    cout << "Type2 " << (type2 ? type2->getName() : "NULL") << endl;
    */

    CHECKPOINT
    //Access to padded area
    try { registerMemType(*mt, 0 + offsetof(A,a2)+1,ts.getTypeInfo("SgTypeChar")); }
    TEST_CATCH( RuntimeViolation::INVALID_TYPE_ACCESS)

    CHECKPOINT
    //Access to padded area
    //Wrong type
    try { registerMemType(*mt, 0, ts.getTypeInfo("B")); }
    TEST_CATCH( RuntimeViolation::INVALID_TYPE_ACCESS)

    CHECKPOINT
    //Access to padded area
    //Wrong basic type
    registerMemType(*mt, 0 + offsetof(A,a2), ts.getTypeInfo("SgTypeChar"));
    try { registerMemType(*mt, 0 + offsetof(A,a2), ts.getTypeInfo("SgTypeInt")); }
    TEST_CATCH( RuntimeViolation::INVALID_TYPE_ACCESS)

    rs.log() << "Type System Status after test" << endl;
    ts.print(rs.log());

    CHECKPOINT
    freeMemory(rs, asAddr(42));

    CLEANUP
}

void testTypeSystemMerge()
{
    TEST_INIT("Testing TypeSystem: Merging basic types into a struct ")
    TypeSystem& ts = rs.getTypeSystem();

    struct A { int a1; int a2; float a3; };
    RsClassType * typeA = &ts.getClassType("A",sizeof(A),false);
    typeA->addMember("a1", ts.getTypeInfo("SgTypeInt"),   offsetof(A,a1));
    typeA->addMember("a2", ts.getTypeInfo("SgTypeInt"),   offsetof(A,a2));
    typeA->addMember("a3", ts.getTypeInfo("SgTypeFloat"), offsetof(A,a3));
    assert(typeA->isComplete());

    rs.checkpoint( srcPosition("?", __LINE__, __LINE__) );
    const Address ADDR = asAddr(42);
    createMemory(rs, ADDR, 100);

        MemoryType* mt = rs.getMemManager().getMemoryType(ADDR);
        //first part in mem is a double
        registerMemType(*mt, 0, ts.getTypeInfo("SgTypeDouble"));

        //then two ints are accessed
        registerMemType(*mt, 0 + sizeof(double)+offsetof(A,a1),ts.getTypeInfo("SgTypeInt"));
        registerMemType(*mt, 0 + sizeof(double)+offsetof(A,a2),ts.getTypeInfo("SgTypeInt") );
        //then the same location is accessed with an struct of two int -> has to merge
        registerMemType(*mt, 0 + sizeof(double),typeA);

        // because of struct access it is known that after the two ints a float follows -> access with int failes
        try { registerMemType(*mt, 0 + sizeof(double) + offsetof(A,a3), ts.getTypeInfo("SgTypeInt")); }
        TEST_CATCH( RuntimeViolation::INVALID_TYPE_ACCESS)

    rs.checkpoint( srcPosition("?", __LINE__, __LINE__) );
    freeMemory(rs, ADDR);

    CLEANUP
}

void testPartialTypeSystemArrayAccess() {
    TEST_INIT("Testing types: array access of type with subtype overlap")
    errorFound=false; /*tps unused variable - removing warning */
    MemoryManager& mm = rs.getMemManager();
    TypeSystem& ts = rs.getTypeSystem();

    // register type(s)
    struct Typ { char a; int b; };
    RsClassType *typ = &ts.getClassType( "Typ", sizeof( Typ ),false);
    typ -> addMember( "a", ts.getTypeInfo( "SgTypeInt" ), offsetof( Typ, a ));
    typ -> addMember( "b", ts.getTypeInfo( "SgTypeInt" ), offsetof( Typ, b ));
    assert( typ -> isComplete() );

    Address Addr = asAddr(0x42);
    size_t el2_offset = sizeof( Typ );
  //  size_t el2_a_offset = el2_offset + offsetof( Typ, a );
    size_t el2_b_offset = el2_offset + offsetof( Typ, b );

    createMemory(rs, Addr, 2 * sizeof( Typ ) );
    // register known memory
    //
    //  0       8   12  16
    //  ////[int]////[int]
    //  [  Typ  ]/////////
    MemoryType* mt = mm.getMemoryType( Addr );
    registerMemType( *mt, 0, typ );
    registerMemType( *mt, 0 + el2_b_offset, ts.getTypeInfo( "SgTypeInt" ));

    // Check array access of larger type.  So far we have no reason to complain:
    // we don't know the full type at 8..16, but the part we do know is
    // consistent with the requested type.
    //
    //  0       8   12  16
    //          [  Typ?  ]
    CHECKPOINT
    checkIfSameChunk( mm, Addr, Addr + el2_offset, (size_t)sizeof( Typ ));

    freeMemory(rs,  Addr );
    CLEANUP
}

void testTypeSystemSubtypes() {
    TEST_INIT("Testing types: createObject should handle subtypes")
    errorFound=false; /*tps unused variable - removing warning */
    MemoryManager& mm = rs.getMemManager();
    TypeSystem& ts = rs.getTypeSystem();

    // register types
    class Base { public: int x; };
    class Sub : public Base { public: int y[ 200 ]; };
    RsClassType* rs_base = new RsClassType( "Base", sizeof( Base ), false );
    rs_base -> addMember( "x", ts.getTypeInfo( "SgTypeInt" ), offsetof( Base, x ));
    assert( rs_base -> isComplete() );

    RsClassType* rs_sub = new RsClassType( "Sub", sizeof( Sub ), false );
    rs_sub -> addMember(
        "y",
        ts.getArrayType( "SgTypeInt", sizeof( int[ 200 ])),
        offsetof( Sub, y ));
    assert( rs_sub -> isComplete() );

    // we should be able to call createObject for the same address in either
    // order and end up with the more specific (larger) type.
    rs.createObject( asAddr(0x42), rs_base );
    rs.createObject( asAddr(0x42), rs_sub );
    MemoryType* mt = mm.findContainingMem( asAddr(0x42), 1 );
    assert( mt );
    assert( rs_sub == mt -> getTypeAt( 0, mt -> getSize() ));

    freeMemory(rs, asAddr(0x42) );

    // same test, but we call createObject in the reverse order
    rs.createObject( asAddr(0x42), rs_sub );
    rs.createObject( asAddr(0x42), rs_base );
    mt = mm.findContainingMem( asAddr(0x42), 1 );
    assert( mt );
    assert( rs_sub == mt -> getTypeAt( 0, mt -> getSize() ));

    freeMemory(rs, asAddr(0x42) );

    CLEANUP
}

void testTypeSystemNested() {
    TEST_INIT("Testing types: createObject should ignore nested types")
    errorFound=false; /*tps unused variable - removing warning */
    MemoryManager& mm = rs.getMemManager();
    TypeSystem& ts = rs.getTypeSystem();

    // register types
    class Base { public: int x; };
    class Composite { public: int p; Base y[ 200 ]; };
    RsClassType* rs_base = new RsClassType( "Base", sizeof( Base ), false );
    rs_base -> addMember( "x", ts.getTypeInfo( "SgTypeInt" ), offsetof( Base, x ));
    assert( rs_base -> isComplete() );

    RsClassType* rs_composite = new RsClassType( "Composite", sizeof( Composite ), false );
    rs_composite -> addMember( "p", ts.getTypeInfo( "SgTypeInt" ), offsetof( Composite, p ));
    rs_composite -> addMember(
        "y",
        ts.getArrayType( rs_base, sizeof( Base[ 200 ])),
        offsetof( Composite, y ));
    assert( rs_composite -> isComplete() );

    // Once we create the larger class, we should ignore calls to the composite
    // types.  If we did this in the reverse order the types would be merged.
    rs.createObject( asAddr(0x42), rs_composite );
    MemoryType* mt = mm.findContainingMem( asAddr(0x42), 1 );
    assert( mt );
    assert( rs_composite == mt -> getTypeAt( 0, mt -> getSize() ));

    rs.createObject( asAddr(0x42) + offsetof( Composite, y ), rs_base );
    assert( mt );
    assert( rs_composite == mt -> getTypeAt( 0, mt -> getSize() ));

    freeMemory(rs,  asAddr(0x42) );

    CLEANUP
}

void testTypeConsistencyChecking() {
    TEST_INIT("Testing type consistency checking")
    errorFound=false; /*tps unused variable - removing warning */
    TypeSystem& ts = rs.getTypeSystem();

    // register user types
    struct Typ { char a; int b; };
    RsClassType *typ = &ts.getClassType( "TypA", sizeof( Typ ), false);
    typ -> addMember( "a", ts.getTypeInfo( "SgTypeChar" ), offsetof( Typ, a ));
    typ -> addMember( "b", ts.getTypeInfo( "SgTypeInt" ), offsetof( Typ, b ));
    assert( typ -> isComplete() );

    typ = &ts.getClassType( "TypB", sizeof( Typ ),false);
    typ -> addMember( "a", ts.getTypeInfo( "SgTypeChar" ), offsetof( Typ, a ));
    typ -> addMember( "b", ts.getTypeInfo( "SgTypeInt" ), offsetof( Typ, b ));
    assert( typ -> isComplete() );

    // gather types
    const RsType & int_typ = *(ts.getTypeInfo( "SgTypeInt" ));
    const RsType & typA = *(ts.getTypeInfo( "TypA" ));
    const RsType & typB = *(ts.getTypeInfo( "TypB" ));

    vector< RsType* > to_delete;
    // char, 4 unknown
    RsCompoundType* compound = new RsCompoundType( sizeof( Typ ));
    RsType &compound_char = *compound;
    to_delete.push_back( compound );
    compound -> addMember( "", ts.getTypeInfo( "SgTypeChar" ), offsetof( Typ, a ));

    // 1 unknown, int
    compound = new RsCompoundType( sizeof( Typ ));
    RsType &compound_int = *compound;
    to_delete.push_back( compound );
    compound -> addMember( "", ts.getTypeInfo( "SgTypeInt" ), offsetof( Typ, b ));

    // 5 char
    compound = new RsCompoundType( sizeof( Typ ));
    RsType &compound_array = *compound;
    to_delete.push_back( compound );
    compound
        -> addMember(
            "",
            ts.getArrayType( "SgTypeChar", 5 * sizeof( char )),
            offsetof( Typ, a ));

    assert( !( int_typ.isConsistentWith( typA )));
    assert( !( typA.isConsistentWith( int_typ )));
    assert( !( int_typ.isConsistentWith( typB )));

    // even though typeA and typB have the same members, if we know something is
    // a "TypB" then it cannot be a "TypA"
    assert( !( typA.isConsistentWith( typB )));

    assert( typA.isConsistentWith( compound_char ));
    assert( typA.isConsistentWith( compound_int ));
    assert( !(typA.isConsistentWith( compound_array )));
    assert( compound_char.isConsistentWith( typA ));
    assert( compound_int.isConsistentWith( typA ));

    assert( compound_char.isConsistentWith( compound_int ));
    assert( compound_char.isConsistentWith( compound_array ));

    assert( compound_int.isConsistentWith( compound_char ));
    assert( !( compound_int.isConsistentWith( compound_array )));

    // FIXME 3: we don't handle this case (see
    // RsCompoundType::checkConsistencyWith )
    // [ int ]
    // ? [int ]
    // not consistent b/c of space in the type for the char
    // assert( !(compound_int.isConsistentWith( int_typ )));
    assert( !(compound_char.isConsistentWith( int_typ )));

    BOOST_FOREACH( RsType* target, to_delete ) {
        delete target;
    }
    CLEANUP
}

extern "C"
{
  int upc_main(int, char**, char**)
  {
      std::cout << "Start RTED single thread tests " << std::endl;

      rted_UpcAllInitWorkzone();
      rted_UpcEnterWorkzone();

      try
      {
          RuntimeSystem& rs = RuntimeSystem::instance();
          rs.setTestingMode(true);
          rs.setOutputFile("test_output.txt");

          testTypeConsistencyChecking();
//~ //~
          testTypeSystemDetectNested();
          testTypeSystemMerge();
          testPartialTypeSystemArrayAccess();
//~ //~
          testTypeSystemSubtypes();
          testTypeSystemNested();
  //~ //~
          testSuccessfulMallocFree();
  //~ //~
          testFreeInsideBlock();
          testInvalidFree();
          testInvalidStackFree();
          testDoubleFree();
          testDoubleAllocation();
          testMemoryLeaks();
          testEmptyAllocation();
          testMemAccess();
          testMallocDeleteCombinations();
  //~ //~
          testFileDoubleClose();
          testFileDoubleOpen();
          testFileInvalidClose();
          testFileUnclosed();
          testFileInvalidAccess();
  //~ //~
          testScopeFreesStack();
          testImplicitScope();
  //~
          testLostMemRegion();
          testLostMemRegionFromDoublePointer();
          testPointerChanged();
          testInvalidPointerAssign();
          testPointerTracking();
          testArrayAccess();
          testDoubleArrayHeapAccess();
          testMultidimensionalStackArrayAccess();
  //~ //~
          test_memcpy();
          test_memmove();
          test_strcpy();
          test_strncpy();
          test_strcat();
          test_strncat();
          test_strchr();
          test_strpbrk();
          test_strspn();
          test_strstr();
          test_strlen();
  //~ //~
          test_memcpy_strict_overlap();
          test_meminit_nullterm_included();
          test_range_overlap();

    rs.doProgramExitChecks();
    printf("All tests passed. \n");
      }
      catch( RuntimeViolation& e)
      {
          out << "Unexpected Error: " << endl << e;
          exit( 1);
      }

      return 0;
  }

#ifdef WITH_UPC
  // \hack see comment in CppRuntimeSystem/ptrops.upc
  // \note since this is a single threaded test, we just provide the name
  char rted_base_hack[0];
#else
  int main(int noargs, char** args, char** envp)
  {
    upc_main(noargs, args, envp);
  }
#endif /* !WITH_UPC */
}

max_stars_repo_name: maurizioabba/rose

max_issues_repo_name: sujankh/rose-matlab

max_forks_repo_name: sujankh/rose-matlab


text:
/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file logic.hpp
 *
 * @brief Logic operations
 *
 * @author Mathias Soeken
 * @since  2.2
 */

#ifndef LOGIC_HPP
#define LOGIC_HPP

#include <boost/assign/std/vector.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>

#include <classical/sat/sat_solver.hpp>

using namespace boost::assign;

namespace cirkit
{

template<class S>
inline void blocking_and( S& solver, int sel, int a, int b, int c )
{
  add_clause( solver )( {-sel, a, -c} );
  add_clause( solver )( {-sel, b, -c} );
  add_clause( solver )( {-sel, -a, -b, c} );
}

template<class S>
void blocking_and( S& solver, int sel, const clause_t& x, int c )
{
  using boost::adaptors::transformed;

  for ( auto l : x )
  {
    add_clause( solver )( {-sel, l, -c} );
  }
  clause_t clause = { -sel };
  boost::push_back( clause, x | transformed( []( int l ) { return -l; } ) );
  clause += c;
  add_clause( solver )( clause );
}

template<class S>
inline void blocking_or( S& solver, int sel, int a, int b, int c )
{
  add_clause( solver )( {-sel, -a, c} );
  add_clause( solver )( {-sel, -b, c} );
  add_clause( solver )( {-sel, a, b, -c} );
}

template<class S>
void blocking_or( S& solver, int sel, const clause_t& x, int c )
{
  for ( auto l : x )
  {
    add_clause( solver )( {-sel, -l, c} );
  }
  clause_t clause( x.begin(), x.end() );
  clause += -sel;
  clause += -c;
  add_clause( solver )( clause );
}

template<class S>
inline void blocking_xor( S& solver, int sel, int a, int b, int c )
{
  add_clause( solver )( {-sel, -a, b, c} );
  add_clause( solver )( {-sel, a, -b, c} );
  add_clause( solver )( {-sel, a, b, -c} );
  add_clause( solver )( {-sel, -a, -b, -c} );
}

template<class S>
inline void blocking_xnor( S& solver, int sel, int a, int b, int c )
{
  add_clause( solver )( {-sel, -a, b, -c} );
  add_clause( solver )( {-sel, a, -b, -c} );
  add_clause( solver )( {-sel, a, b, c} );
  add_clause( solver )( {-sel, -a, -b, c} );
}

template<class S>
inline void logic_and( S& solver, int a, int b, int c )
{
  add_clause( solver )( {a, -c} );
  add_clause( solver )( {b, -c} );
  add_clause( solver )( {-a, -b, c} );
}

template<class S>
void logic_and( S& solver, const clause_t& x, int c )
{
  using boost::adaptors::transformed;

  for ( auto l : x )
  {
    add_clause( solver )( {l, -c} );
  }
  clause_t clause;
  boost::push_back( clause, x | transformed( []( int l ) { return -l; } ) );
  clause += c;
  add_clause( solver )( clause );
}

template<class S>
inline void logic_or( S& solver, int a, int b, int c )
{
  add_clause( solver )( {-a, c} );
  add_clause( solver )( {-b, c} );
  add_clause( solver )( {a, b, -c} );
}

template<class S>
void logic_or( S& solver, const clause_t& x, int c )
{
  for ( auto l : x )
  {
    add_clause( solver )( {-l, c} );
  }
  clause_t clause( x.begin(), x.end() );
  clause += -c;
  add_clause( solver )( clause );
}

template<class S>
inline void logic_xor( S& solver, int a, int b, int c )
{
  add_clause( solver )( {-a, b, c} );
  add_clause( solver )( {a, -b, c} );
  add_clause( solver )( {a, b, -c} );
  add_clause( solver )( {-a, -b, -c} );
}

template<class S>
inline void logic_xnor( S& solver, int a, int b, int c )
{
  add_clause( solver )( {-a, b, -c} );
  add_clause( solver )( {a, -b, -c} );
  add_clause( solver )( {a, b, c} );
  add_clause( solver )( {-a, -b, c} );
}

}

#endif

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:

ext: hpp

max_stars_repo_name: eletesta/cirkit

max_issues_repo_name: eletesta/cirkit

max_forks_repo_name: eletesta/cirkit


text:
#ifndef SERVER_HPP
#define SERVER_HPP

#include "server/connection.hpp"
#include "server/request_handler.hpp"
#include "server/service_handler.hpp"

#include "util/integer_range.hpp"
#include "util/log.hpp"

#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include <zlib.h>

#ifndef _WIN32
#include <sys/socket.h>
#include <sys/types.h>
#endif

#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <vector>

namespace osrm
{
namespace server
{

class Server
{
  public:
    // Note: returns a shared instead of a unique ptr as it is captured in a lambda somewhere else
    static std::shared_ptr<Server>
    CreateServer(std::string &ip_address, int ip_port, unsigned requested_num_threads)
    {
        util::Log() << "http 1.1 compression handled by zlib version " << zlibVersion();
        const unsigned hardware_threads = std::max(1u, std::thread::hardware_concurrency());
        const unsigned real_num_threads = std::min(hardware_threads, requested_num_threads);
        return std::make_shared<Server>(ip_address, ip_port, real_num_threads);
    }

    explicit Server(const std::string &address, const int port, const unsigned thread_pool_size)
        : thread_pool_size(thread_pool_size), acceptor(io_service),
          new_connection(std::make_shared<Connection>(io_service, request_handler))
    {
        const auto port_string = std::to_string(port);

        boost::asio::ip::tcp::resolver resolver(io_service);
        boost::asio::ip::tcp::resolver::query query(address, port_string);
        boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);

        acceptor.open(endpoint.protocol());
#ifdef SO_REUSEPORT
        const int option = 1;
        setsockopt(acceptor.native_handle(), SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option));
#endif
        acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
        acceptor.bind(endpoint);
        acceptor.listen();

        util::Log() << "Listening on: " << acceptor.local_endpoint();

        acceptor.async_accept(
            new_connection->socket(),
            boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
    }

    void Run()
    {
        std::vector<std::shared_ptr<std::thread>> threads;
        for (unsigned i = 0; i < thread_pool_size; ++i)
        {
            std::shared_ptr<std::thread> thread = std::make_shared<std::thread>(
                boost::bind(&boost::asio::io_service::run, &io_service));
            threads.push_back(thread);
        }
        for (auto thread : threads)
        {
            thread->join();
        }
    }

    void Stop() { io_service.stop(); }

    void RegisterServiceHandler(std::unique_ptr<ServiceHandlerInterface> service_handler_)
    {
        request_handler.RegisterServiceHandler(std::move(service_handler_));
    }

  private:
    void HandleAccept(const boost::system::error_code &e)
    {
        if (!e)
        {
            new_connection->start();
            new_connection = std::make_shared<Connection>(io_service, request_handler);
            acceptor.async_accept(
                new_connection->socket(),
                boost::bind(&Server::HandleAccept, this, boost::asio::placeholders::error));
        }
    }

    unsigned thread_pool_size;
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::acceptor acceptor;
    std::shared_ptr<Connection> new_connection;
    RequestHandler request_handler;
};
}
}

#endif // SERVER_HPP

max_stars_repo_name: jhermsmeier/osrm-backend

max_issues_repo_name: serarca/osrm-backend

max_forks_repo_name: serarca/osrm-backend


text:
#ifndef YANNQ_GEOMETRY_FISHERMATIRX_HPP
#define YANNQ_GEOMETRY_FISHERMATIRX_HPP
#include <Eigen/Core>
#include <Eigen/Dense>

#include "Utilities/Utility.hpp"
#include "Observables/Observable.hpp"

#include <Eigen/IterativeLinearSolvers>
#include <unsupported/Eigen/IterativeSolvers>

namespace yannq
{
template<typename Machine>
class FisherMatrix;
} //namespace yannq

namespace Eigen {
namespace internal {
	template<typename Machine>
	struct traits<yannq::FisherMatrix<Machine> > :  public Eigen::internal::traits<Eigen::SparseMatrix<typename Machine::Scalar> > {};
}
} //namespace Eigen

namespace yannq
{
/**
 * Construct the fisher information metric for quantum states
 * */
template<class Machine>
class FisherMatrix
	: public Observable<FisherMatrix<Machine> >,
	public Eigen::EigenBase<FisherMatrix<Machine> >
{
public:
	using Scalar = typename Machine::Scalar;
	using RealScalar = typename remove_complex<Scalar>::type;

	using Matrix = typename Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
	using Vector = typename Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
	using RealMatrix = typename Eigen::Matrix<RealScalar, Eigen::Dynamic, Eigen::Dynamic>;
	using RealVector = typename Eigen::Matrix<RealScalar, Eigen::Dynamic, 1>;

private:
	uint32_t n_;

	const Machine& qs_;
	RealScalar shift_;

	Matrix deltas_;
	Vector deltaMean_;

public:
	// Required typedefs, constants, and method:
	typedef int StorageIndex;

	enum {
		ColsAtCompileTime = Eigen::Dynamic,
		MaxColsAtCompileTime = Eigen::Dynamic,
		IsRowMajor = false
	};

	Eigen::Index rows() const { return qs_.getDim(); }
	Eigen::Index cols() const { return qs_.getDim(); }

	template<typename Rhs>
	Eigen::Product<FisherMatrix<Machine>, Rhs, Eigen::AliasFreeProduct>
			operator*(const Eigen::MatrixBase<Rhs>& x) const {
	  return Eigen::Product<FisherMatrix<Machine>, Rhs, Eigen::AliasFreeProduct>(*this, x.derived());
	}

	void setShift(RealScalar shift)
	{
		shift_ = shift;
	}

	RealScalar getShift() const
	{
		return shift_;
	}

	void initIter(int nsmp)
	{
		deltas_.setZero(nsmp, qs_.getDim());
	}

	template<class Elt, class State>
	inline void eachSample(int n, Elt&& elt, State&& state)
	{
		(void)state;
		deltas_.row(n) = qs_.logDeriv(elt);
	}

	void finIter()
	{
		deltaMean_ = deltas_.colwise().mean();
		deltas_ = deltas_.rowwise() - deltaMean_.transpose();
	}

	/**
	 * \param weights normalized weights for each sigma
	 * */
	void finIter(const Eigen::Ref<const RealVector>& weights)
	{
		weights_ = weights;
		deltaMean_ = weights.transpose()*deltas_;
		deltas_ = deltas_.rowwise() - deltaMean_.transpose();
	}

	inline
	const Matrix& logDervs() const&
	{
		return deltas_;
	}

	inline
	Matrix logDervs() &&
	{
		return std::move(deltas_);
	}

	inline
	const Vector& oloc() const&
	{
		return deltaMean_;
	}
	inline
	Vector oloc() &&
	{
		return std::move(deltaMean_);
	}

	Matrix corrMat() const
	{
		int nsmp = deltas_.rows();
		if(weights_.size() == 0)
			return (deltas_.adjoint() * deltas_)/nsmp;
		else
			return (deltas_.adjoint() * weights_.asDiagonal() * deltas_);
	}

	RealVector diagCorrMat() const
	{
		RealMatrix sqrDeltas = deltas_.cwiseAbs2();
		return sqrDeltas.colwise().mean();
	}

	FisherMatrix(const Machine& qs)
	  : n_{qs.getN()}, qs_(qs), shift_{1e-3}
	{
	}

	template<class Rhs>
	typename Machine::Vector apply(const Rhs& rhs) const
	{
		assert(rhs.size() == qs_.getDim());
		Vector r = deltas_*rhs;

		Vector res;

		if(weights_.size() == 0)
			res = deltas_.adjoint()*r/r.rows();
		else
			res = deltas_.adjoint() * weights_.asDiagonal() * r;

		return res + Scalar(shift_)*rhs;
	}
};
}//namespace yannq

// Implementation of yannq::SRMat * Eigen::DenseVector though a specialization of internal::generic_product_impl:
namespace Eigen {
namespace internal {
	template<typename Rhs, typename Machine>
	struct generic_product_impl<yannq::FisherMatrix<Machine>, Rhs, SparseShape, DenseShape, GemvProduct> // GEMV stands for matrix-vector
	: generic_product_impl_base<yannq::FisherMatrix<Machine>, Rhs, generic_product_impl<yannq::FisherMatrix<Machine>, Rhs> >
	{
		typedef typename Product<yannq::FisherMatrix<Machine>, Rhs>::Scalar Scalar;
		template<typename Dest>
		static void scaleAndAddTo(Dest& dst, const yannq::FisherMatrix<Machine>& lhs, const Rhs& rhs, const Scalar& alpha)
		{
			// This method should implement "dst += alpha * lhs * rhs" inplace,
			// however, for iterative solvers, alpha is always equal to 1, so let's not bother about it.
			assert(alpha==Scalar(1) && "scaling is not implemented");
			EIGEN_ONLY_USED_FOR_DEBUG(alpha);

			dst += lhs.apply(rhs);
		}
	};
} //namespace internal
} //namespace Eigen

#endif//YANNQ_GEOMETRY_FISHERMATIRX_HPP

max_stars_repo_name: cecri/yannq

max_issues_repo_name: cecri/yannq

max_forks_repo_name: cecri/yannq


text:
/*******************************<SCHWARZ LIB LICENSE>***********************
Copyright (c) 2019, the SCHWARZ LIB authors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************<SCHWARZ LIB LICENSE>*************************/

#ifndef initialization_hpp
#define initialization_hpp

#include <cmath>
#include <functional>
#include <memory>
#include <random>
#include <vector>

#include <schwarz/config.hpp>

#if SCHW_HAVE_DEALII
#include <deal.II/lac/sparse_matrix.h>
#endif

#include <partition_tools.hpp>
#include <settings.hpp>

namespace schwz {

/**
 * The initialization class that provides methods for initialization of the
 * solver.
 *
 * @tparam ValueType  The type of the floating point values.
 * @tparam IndexType  The type of the index type values.
 *
 * @ref init
 * @ingroup init
 */
template <typename ValueType = gko::default_precision,
          typename IndexType = gko::int32>
class Initialize : public Settings, public Metadata<ValueType, IndexType> {
public:
    Initialize(Settings &settings, Metadata<ValueType, IndexType> &metadata);

    /**
     * The partition indices containing the subdomains to which each row(vertex)
     * of the matrix(graph) belongs to.
     */
    std::vector<unsigned int> partition_indices;

    /**
     * The cell weights for the partition algorithm.
     */
    std::vector<unsigned int> cell_weights;

    /**
     * Generates the right hand side vector
     *
     * @param rhs  The rhs vector.
     */
    void generate_rhs(std::vector<ValueType> &rhs);

    /**
     * Generates the 2D global laplacian matrix.
     *
     * @param oned_laplacian_size  The size of the one d laplacian grid.
     * @param global_matrix  The global matrix.
     */
#if SCHW_HAVE_DEALII
    void setup_global_matrix(
        const std::string &filename, const gko::size_type &oned_laplacian_size,
        const dealii::SparseMatrix<ValueType> &matrix,
        std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>> &global_matrix);
#else
    void setup_global_matrix(
        const std::string &filename, const gko::size_type &oned_laplacian_size,
        std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>> &global_matrix);
#endif

    /**
     * The partitioning function. Allows the partition of the global matrix
     * depending with METIS and a regular 1D decomposition.
     *
     * @param settings  The settings struct.
     * @param metadata  The metadata struct.
     * @param global_matrix  The global matrix.
     * @param partition_indices  The partition indices [OUTPUT].
     */
    void partition(const Settings &settings,
                   const Metadata<ValueType, IndexType> &metadata,
                   const std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>>
                       &global_matrix,
                   std::vector<unsigned int> &partition_indices);

    /**
     * Setup the vectors with default values and allocate mameory if not
     * allocated.
     *
     * @param settings  The settings struct.
     * @param metadata  The metadata struct.
     * @param local_rhs  The local right hand side vector in the subdomain.
     * @param global_rhs  The global right hand side vector.
     * @param local_solution  The local solution vector in the subdomain.
     */
    void setup_vectors(
        const Settings &settings,
        const Metadata<ValueType, IndexType> &metadata,
        std::vector<ValueType> &rhs,
        std::shared_ptr<gko::matrix::Dense<ValueType>> &local_rhs,
        std::shared_ptr<gko::matrix::Dense<ValueType>> &global_rhs,
        std::shared_ptr<gko::matrix::Dense<ValueType>> &local_solution);

    /**
     * Sets up the local and the interface matrices from the global matrix and
     * the partition indices.
     *
     * @param settings  The settings struct.
     * @param metadata  The metadata struct.
     * @param partition_indices  The array containing the partition indices.
     * @param global_matrix The global system matrix.
     * @param local_matrix The local system matrix.
     * @param interface_matrix The interface matrix containing the interface and
     *                         the overlap data mainly used for exchanging
     *                         values between different sub-domains.
     * @param local_perm  The local permutation, obtained through RCM or METIS.
     */
    virtual void setup_local_matrices(
        Settings &settings, Metadata<ValueType, IndexType> &metadata,
        std::vector<unsigned int> &partition_indices,
        std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>> &global_matrix,
        std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>> &local_matrix,
        std::shared_ptr<gko::matrix::Csr<ValueType, IndexType>>
            &interface_matrix) = 0;

private:
    Settings &settings;

    Metadata<ValueType, IndexType> &metadata;
};

}  // namespace schwz

#endif  // initialization.hpp

max_stars_repo_name: soumyadipghosh/schwarz-lib

max_issues_repo_name: soumyadipghosh/schwarz-lib

max_forks_repo_name: soumyadipghosh/schwarz-lib


text:
// Copyright 2020 Josh Pieper, jjp@pobox.com.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "mjlib/telemetry/file_reader.h"

#include <cstdlib>
#include <cstring>
#include <deque>
#include <set>

#include <boost/crc.hpp>

#include <fmt/format.h>

#include <snappy.h>

#include "mjlib/base/crc_stream.h"
#include "mjlib/base/file_stream.h"
#include "mjlib/base/system_error.h"
#include "mjlib/telemetry/error.h"

namespace mjlib {
namespace telemetry {

namespace {
class FilePtr {
 public:
  FilePtr(std::string_view name) {
    file_ = ::fopen(name.data(), "rb");
    mjlib::base::system_error::throw_if(
        file_ == nullptr,
        fmt::format("When opening: '{}'", name));
    base::system_error::throw_if(::fseek(file_, 0, SEEK_END) < 0);
    size_ = Tell();
    base::system_error::throw_if(::fseek(file_, 0, SEEK_SET) < 0);
  }

  ~FilePtr() {
    ::fclose(file_);
  }

  FILE* file() {
    return file_;
  }

  void Seek(int64_t index) {
    base::system_error::throw_if(::fseek(file_, index, SEEK_SET) < 0);
  }

  int64_t Tell() {
    const auto result = ::ftell(file_);
    base::system_error::throw_if(result < 0);
    return result;
  }

  int64_t size() const { return size_; }

 private:
  FILE* file_ = nullptr;
  int64_t size_ = 0;
};

/// Guarantee that an exact amount is read (or ignored) from an
/// underlying stream.
class BlockStream : public base::ReadStream {
 public:
  BlockStream(base::ReadStream& base, std::streamsize size)
      : base_(base), size_(size) {}

  ~BlockStream() override {
    if (size_ > 0) {
      base_.ignore(size_);
    }
  }

  void ignore(std::streamsize size) override {
    MJ_ASSERT(size <= size_);
    size_ -= size;
    base_.ignore(size);
  }

  void read(const base::string_span& data) override {
    MJ_ASSERT(data.size() <= size_);
    size_ -= data.size();
    base_.read(data);
  }

  std::streamsize gcount() const override {
    return base_.gcount();
  }

  std::streamsize remaining() const {
    return size_;
  }

  void shrink(std::streamsize size) { size_ -= size; }

 private:
  base::ReadStream& base_;
  std::streamsize size_;
};
}  // namespace

class Filter {
 public:
  virtual ~Filter() {}
  virtual bool check(FileReader::Identifier) = 0;
  virtual void new_schema(FileReader::Identifier, const std::string&) = 0;
};

struct FileReader::ItemRangeContext : public Filter {
  ~ItemRangeContext() override {}

  FileReader::Impl* impl = nullptr;
  std::set<std::string> unknown_names;
  std::set<FileReader::Identifier> ids;
  FileReader::ItemsOptions options;

  bool check(Identifier identifier) override {
    if (options.records.empty()) { return true; }
    if (ids.count(identifier)) { return true; }
    return false;
  }

  void new_schema(Identifier identifier, const std::string& name) override {
    if (unknown_names.count(name)) {
      unknown_names.erase(name);
      ids.insert(identifier);
    }
  }
};

class FileReader::Impl {
 public:
  Impl(std::string_view filename, const Options& options)
      : options_(options),
        fptr_(filename) {
    char header[8] = {};
    file_.read(header);
    if (std::memcmp(header, "TLOG0003", 8) != 0) {
      throw base::system_error(errc::kInvalidHeader);
    }
    telemetry::ReadStream stream{file_};
    const auto header_flags = stream.ReadVaruint();
    if (header_flags != 0) {
      // There are no known header flags yet.
      throw base::system_error(errc::kInvalidHeaderFlags);
    }

    start_ = fptr_.Tell();

    MaybeProcessIndex();
  }

  ~Impl() {
  }

  ItemRange items(const ItemsOptions& options) {
    auto context = std::make_shared<ItemRangeContext>();
    context->impl = this;
    context->options = options;
    for (const auto& name : options.records) {
      const auto it = name_to_record_.find(name);
      if (it != name_to_record_.end()) {
        context->ids.insert(it->second->identifier);
      } else {
        context->unknown_names.insert(name);
      }
    }

    return ItemRange(context);
  }

  struct Header {
    Format::BlockType type = {};
    uint64_t size = {};
  };

  std::optional<Header> ReadHeader(base::ReadStream& base_stream,
                                   bool throw_on_error=true) {
    telemetry::ReadStream stream{base_stream};
    const auto maybe_type = stream.ReadVaruint();
    if (!maybe_type) { return {}; }
    const auto type = *maybe_type;
    if (type > static_cast<uint64_t>(Format::BlockType::kNumTypes) ||
        type == 0) {
      if (throw_on_error) {
        throw base::system_error(errc::kInvalidBlockType);
      } else {
        return {};
      }
    }

    const auto size = stream.ReadVaruint().value();
    return Header{static_cast<Format::BlockType>(type), size};
  }

  const Record* ProcessSchema(BlockStream& block_stream, Filter* filter) {
    telemetry::ReadStream stream{block_stream};

    const auto identifier = stream.ReadVaruint().value();
    {
      auto it = id_to_record_.find(identifier);
      if (it != id_to_record_.end()) { return it->second; }
    }

    records_.push_back({});
    auto& record = records_.back();

    record.identifier = identifier;
    record.flags = stream.ReadVaruint().value();

    auto flags = record.flags;
    if (flags) {
      throw base::system_error(errc::kUnknownBlockSchemaFlag);
    }

    record.name = stream.ReadString().value();
    record.raw_schema.resize(block_stream.remaining());
    block_stream.read(record.raw_schema);

    record.schema = std::make_unique<BinarySchemaParser>(
        record.raw_schema, record.name);

    id_to_record_[identifier] = &record;
    name_to_record_[record.name] = &record;

    if (filter) {
      filter->new_schema(record.identifier, record.name);
    }
    return &record;
  }

  std::pair<Index, Index> ReadUntil(Index start, Filter* filter) {
    fptr_.Seek(start);

    while (true) {
      start = fptr_.Tell();

      const auto maybe_header = ReadHeader(file_);
      if (!maybe_header) {
        // EOF
        return std::make_pair(-1, -1);
      }
      const auto& header = *maybe_header;

      BlockStream block_stream{file_, static_cast<std::streamsize>(header.size)};
      telemetry::ReadStream stream{block_stream};

      switch (header.type) {
        case Format::BlockType::kData: {
          if (start > final_item_) { final_item_ = start; }
          const auto identifier = stream.ReadVaruint().value();
          if (!filter->check(identifier)) { break; }

          // This is what we want!
          const auto next = fptr_.Tell() + block_stream.remaining();
          return std::make_pair(start, next);
        }
        case Format::BlockType::kSchema: {
          ProcessSchema(block_stream, filter);
          break;
        }
        case Format::BlockType::kIndex:
        case Format::BlockType::kCompressionDictionary:
        case Format::BlockType::kSeekMarker: {
          break;
        }
      }
    }
  }

  Item Read(Index index) {
    fptr_.Seek(index);

    base::CrcReadStream<boost::crc_32_type> crc_stream{file_};

    const auto maybe_header = ReadHeader(crc_stream);
    MJ_ASSERT(!!maybe_header);
    const auto& header = *maybe_header;

    MJ_ASSERT(header.type == Format::BlockType::kData);
    BlockStream block_stream{
      crc_stream, static_cast<std::streamsize>(header.size)};
    telemetry::ReadStream stream{block_stream};

    Item result;
    result.index = index;
    const auto identifier = stream.ReadVaruint().value();
    result.flags = stream.ReadVaruint().value();

    auto flags = result.flags;
    auto check_flags = [&](auto flag) {
      const auto u64_flag = static_cast<uint64_t>(flag);
      if (flags & u64_flag) {
        flags &= ~u64_flag;
        return true;
      }
      return false;
    };

    if (check_flags(Format::BlockDataFlags::kPreviousOffset)) {
      stream.ReadVaruint(); // discard
    }
    if (check_flags(Format::BlockDataFlags::kTimestamp)) {
      result.timestamp = stream.ReadTimestamp().value();
    }

    std::optional<uint32_t> checksum;
    if (check_flags(Format::BlockDataFlags::kChecksum)) {
      // We need to feed the CRC all 0s.
      const uint32_t all_zeros = 0;
      crc_stream.crc().process_bytes(&all_zeros, sizeof(all_zeros));

      // And then we need to read the CRC on the sly.
      telemetry::ReadStream nocrc_stream{file_};
      checksum = nocrc_stream.Read<uint32_t>().value();

      // And then fudge our block stream.
      block_stream.shrink(sizeof(all_zeros));
    }

    const bool snappy =
        check_flags(Format::BlockDataFlags::kSnappy);

    if (flags != 0) {
      throw base::system_error(errc::kUnknownBlockDataFlag);
    }

    result.data.resize(block_stream.remaining());
    block_stream.read(result.data);

    if (snappy) {
      size_t decompressed_size = 0;
      {
        const bool success = snappy::GetUncompressedLength(
            result.data.data(), result.data.size(),
            &decompressed_size);
        if (!success) {
          throw base::system_error(errc::kDecompressionError);
        }
      }
      std::string decompressed;
      decompressed.resize(decompressed_size);
      {
        const bool success = snappy::RawUncompress(
            result.data.data(), result.data.size(),
            &decompressed[0]);
        if (!success) {
          throw base::system_error(errc::kDecompressionError);
        }
      }
      std::swap(decompressed, result.data);
    }

    if (checksum && options_.verify_checksums) {
      if (*checksum != crc_stream.checksum()) {
        throw base::system_error(
            {errc::kDataChecksumMismatch,
                  fmt::format("Expected checksum 0x{:08x} got 0x{:08x}",
                              crc_stream.checksum(), *checksum)});
      }
    }

    result.record = id_to_record_.at(identifier);

    return result;
  }

  const Record* record(std::string_view name_view) {
    std::string name{name_view};
    if (name_to_record_.count(name)) {
      return name_to_record_.at(name);
    }
    if (all_records_found_) { return nullptr; }

    // We haven't read everything, just do a full scan for now to
    // ensure we've processed everything.
    FullScan();
    if (name_to_record_.count(name)) {
      return name_to_record_.at(name);
    }
    return nullptr;
  }

  std::vector<const Record*> records() {
    if (!all_records_found_) { FullScan(); }
    std::vector<const Record*> result;
    for (const auto& record : records_) {
      result.push_back(&record);
    }
    return result;
  }

  Index final_item() {
    if (!all_records_found_) { FullScan(); }
    return final_item_;
  }

  struct SeekMarkerResult {
    boost::posix_time::ptime timestamp;
    Index index;
    SeekResult seek_result;
  };

  std::optional<SeekMarkerResult> EvaluateSeekMarker(Index index) {
    // @p index points to the last byte of the marker.  See if we can
    // read a valid block out of this.

    const uint8_t header_len = [&]() {
      ReadStream stream{file_};
      stream.Read<uint32_t>();  // crc
      return stream.Read<uint8_t>().value();
    }();
    if (header_len > 10) {
      // The max varuint size is 9 + 1 for the block type.
      return {};
    }
    const auto possible_start = index - 7 - header_len;
    if (possible_start < start_) {
      // It can't be before the beginning of the file.
      return {};
    }

    base::CrcReadStream<boost::crc_32_type> crc_stream{file_};

    fptr_.Seek(possible_start);
    const auto maybe_header = ReadHeader(crc_stream, false);
    if (!maybe_header) { return {}; }
    const auto header = *maybe_header;
    if (header.type != Format::BlockType::kSeekMarker) {
      return {};
    }

    SeekMarkerResult result;
    result.index = possible_start;
    BlockStream block_stream{crc_stream, static_cast<std::streamsize>(header.size)};
    ReadStream stream{block_stream};

    stream.Read<uint64_t>().value();  // marker
    const auto crc = [&]() {
      // We want to tell the crc stream that we had all zeros here.
      const uint32_t all_zeros = 0;
      crc_stream.crc().process_bytes(&all_zeros, sizeof(all_zeros));

      // Tell our block stream we skipped those bytes.
      block_stream.shrink(sizeof(all_zeros));

      // Now we want to read the actual value straight from the file.
      ReadStream nocrc_stream{file_};
      return nocrc_stream.Read<uint32_t>().value();
    }();
    stream.Read<uint8_t>().value();  // header_len
    const auto flags = stream.ReadVaruint().value();
    if (flags) {
      throw base::system_error(errc::kUnknownSeekMarkerFlag);
    }
    result.timestamp = stream.ReadTimestamp().value();
    const auto nelements = stream.ReadVaruint().value();
    for (uint64_t i = 0; i < nelements; i++) {
      const auto identifier = stream.ReadVaruint().value();
      const auto previous_offset = stream.ReadVaruint().value();
      result.seek_result.insert(
          std::make_pair(
              id_to_record_.at(identifier), possible_start - previous_offset));
    }

    if (block_stream.remaining() != 0) {
      return {};
    }

    if (crc != crc_stream.checksum()) {
      // We'll count a checksum mismatch as just meaning we got a
      // false positive.
      return {};
    }

    return result;
  }

  std::optional<SeekMarkerResult> FindSeekMarker(Index index, Index end) {
    fptr_.Seek(index);
    const auto stop_point = std::min(fptr_.size(), end);

    // Do the dumb thing for now, our search pattern is only 8 bytes
    // long after all.
    constexpr uint8_t to_match[] = {
      0x64, 0x75, 0x86, 0x97, 0xa8, 0xb9, 0xca, 0xfd,
    };
    int matched = 0;
    while (true) {
      uint8_t c = {};
      file_.read(base::string_span(reinterpret_cast<char*>(&c), 1));
      if (c == to_match[matched]) {
        matched++;
        if (matched == 8) {
          auto maybe_result = EvaluateSeekMarker(index);
          if (!!maybe_result) {
            return std::move(*maybe_result);
          }
          // Guess not, just keep looking.
          fptr_.Seek(index);
          matched = 0;
        }
      } else {
        matched = 0;
      }
      index++;
      if (index >= stop_point) {
        // We got to the end and haven't found anything.
        return {};
      }
    }
  }

  SeekResult Seek(const boost::posix_time::ptime timestamp) {
    // We need to know about all schemas before we can do this.
    if (!all_records_found_) { FullScan(); }

    // We look exclusively for SeekMarkers, as they have a known
    // signature and guaranteed checksum.  Our strategy is to find two
    // SeekMarkers that bound the given timestamp, then walk from the
    // first to the second updating the results as we go.
    int64_t low = start_;
    int64_t high = final_item_;

    SeekResult result;

    constexpr int64_t kMinSpacing = 1 << 16;
    while ((high - low) > kMinSpacing) {
      const int64_t mid_search_point = low + (high - low) / 2;
      const auto seek = FindSeekMarker(mid_search_point, high);
      if (!seek) {
        // There are no seek points in our second half.  Just linear
        // search from the current low point.
        break;
      }
      if (seek->timestamp <= timestamp) {
        low = seek->index;
        result = seek->seek_result;
      } else {
        high = seek->index;
      }
    }

    ItemsOptions items_options;
    items_options.start = low;
    items_options.end = high;
    for (const auto& item : items(items_options)) {
      if (item.timestamp.is_not_a_date_time()) { break; }
      if (item.timestamp > timestamp) { break; }
      auto& current_last = result[item.record];
      if (item.index > current_last) { current_last = item.index; }
    }

    return result;
  }

  void FullScan() {
    class NoFilter : public Filter {
     public:
      bool check(Identifier) override { return false; }
      void new_schema(Identifier, const std::string&) override {}
    };

    NoFilter no_filter;
    ReadUntil(start_, &no_filter);
    all_records_found_ = true;
  }

  void MaybeProcessIndex() {
    // Seek to 8 bytes from the end.
    fptr_.Seek(fptr_.size() - 8);
    char trailer[8] = {};
    file_.read(trailer);

    if (std::memcmp(trailer, "TLOGIDEX", 8) != 0) {
      // Nope, definitely not an index.
      return;
    }

    // We have something that looks plausibly like an index.  Lets see
    // if it validates as an entire block.
    fptr_.Seek(fptr_.size() - 12);
    telemetry::ReadStream stream{file_};
    const uint32_t trailer_size = stream.Read<uint32_t>().value();
    if (trailer_size >= (fptr_.size() - start_)) {
      // This purported record would be bigger than the entire log.
      return;
    }

    fptr_.Seek(fptr_.size() - trailer_size);
    const auto maybe_header = ReadHeader(file_);
    if (!maybe_header) {
      // Nope.  Some other corruption.
      return;
    }
    const auto header = *maybe_header;
    if (header.type != Format::BlockType::kIndex) {
      // Hmmmph.  Wrong type.
      return;
    }

    // From here on out we'll assume the index was supposed to be
    // here, and thus we'll let other parse errors trickle up as
    // exceptions rather than silently ignoring the index block.
    const auto flags = stream.ReadVaruint().value();
    if (flags != 0) {
      throw base::system_error(errc::kUnknownIndexFlag);
    }

    struct LocalRecord {
      uint64_t identifier = {};
      int64_t schema_location = {};
      int64_t final_record = {};
    };

    std::vector<LocalRecord> local_records;

    const auto nelements = stream.ReadVaruint().value();
    for (uint64_t i = 0; i < nelements; i++) {
      LocalRecord record;
      record.identifier = stream.ReadVaruint().value();
      record.schema_location = static_cast<int64_t>(stream.Read<uint64_t>().value());
      record.final_record = static_cast<int64_t>(stream.Read<uint64_t>().value());
      local_records.push_back(record);
    }

    // Now go and find all the schemas so that we can fill in our
    // records structures.
    MJ_ASSERT(records_.empty());
    final_item_ = 0;
    for (const auto& local_record : local_records) {
      fptr_.Seek(local_record.schema_location);
      const auto header = ReadHeader(file_).value();
      BlockStream block_stream{file_, static_cast<std::streamsize>(header.size)};
      const auto* record = ProcessSchema(block_stream, nullptr);
      MJ_ASSERT(record->identifier == local_record.identifier);
      if (local_record.final_record > final_item_) {
        final_item_ = local_record.final_record;
      }
    }

    has_index_ = true;
    all_records_found_ = true;
  }

  const Options options_;
  FilePtr fptr_;
  base::FileStream file_{fptr_.file()};

  std::deque<Record> records_;
  std::map<Identifier, const Record*> id_to_record_;
  std::map<std::string, const Record*> name_to_record_;

  Index final_item_ = -1;
  bool has_index_ = false;
  bool all_records_found_ = false;
  int64_t start_ = 0;
};

FileReader::FileReader(std::string_view filename, const Options& options)
    : impl_(std::make_unique<Impl>(filename, options)) {}

FileReader::~FileReader() {}

const FileReader::Record* FileReader::record(std::string_view name) {
  return impl_->record(name);
}

std::vector<const FileReader::Record*> FileReader::records() {
  return impl_->records();
}

bool FileReader::has_index() const {
  return impl_->has_index_;
}

FileReader::Index FileReader::final_item() {
  return impl_->final_item();
}

FileReader::SeekResult FileReader::Seek(boost::posix_time::ptime timestamp) {
  return impl_->Seek(timestamp);
}

FileReader::Item FileReader::ItemIterator::operator*() {
  return context_->impl->Read(index_);
}

FileReader::ItemIterator& FileReader::ItemIterator::operator++() {
  // This first call gives us where we started at.
  auto [first, after] = context_->impl->ReadUntil(index_, context_.get());
  auto [advanced, _] = context_->impl->ReadUntil(after, context_.get());
  index_ = advanced;
  return *this;
}

bool FileReader::ItemIterator::operator!=(const ItemIterator& rhs) const {
  return index_ != rhs.index_;
}

FileReader::ItemIterator FileReader::ItemRange::begin() {
  // For now, always start at the very beginning.
  auto [first, next] = context_->impl->ReadUntil(
      context_->options.start < 0 ? context_->impl->start_ :
      context_->options.start,
      context_.get());
  return ItemIterator(context_, first);
}

FileReader::ItemIterator FileReader::ItemRange::end() {
  return ItemIterator(context_, -1);
}

FileReader::ItemRange FileReader::items(const ItemsOptions& options) {
  return impl_->items(options);
}

}
}

ext: cc


text:
//---------------------------------------------------------------------------//
//!
//! \file   MonteCarlo_SimulationPhotonProperties.hpp
//! \author Alex Robinson, Luke Kersting
//! \brief  Simulation photon properties class decl.
//!
//---------------------------------------------------------------------------//

#ifndef MONTE_CARLO_SIMULATION_PHOTON_PROPERTIES_HPP
#define MONTE_CARLO_SIMULATION_PHOTON_PROPERTIES_HPP

// Boost Includes
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/export.hpp>

// FRENSIE Includes
#include "MonteCarlo_ParticleModeType.hpp"
#include "MonteCarlo_IncoherentModelType.hpp"
#include "Utility_ExplicitSerializationTemplateInstantiationMacros.hpp"

namespace MonteCarlo{

/*! The simulation photon properties class
 * \todo Modify XML parser to handle all options in this class. Use this class
 * in all parts of code that require runtime configuration.
 */
class SimulationPhotonProperties
{

public:

  //! Constructor
  SimulationPhotonProperties();

  //! Destructor
  virtual ~SimulationPhotonProperties()
  { /* ... */ }

  //! Set the minimum photon energy (MeV)
  void setMinPhotonEnergy( const double energy );

  //! Return the minimum photon energy (MeV)
  double getMinPhotonEnergy() const;

  //! Return the absolute minimum photon energy (MeV)
  static double getAbsoluteMinPhotonEnergy();

  //! Set the maximum photon energy (MeV)
  void setMaxPhotonEnergy( const double energy );

  //! Return the maximum photon energy (MeV)
  double getMaxPhotonEnergy() const;

  //! Return the absolute maximum photon energy (MeV)
  static double getAbsoluteMaxPhotonEnergy();

  //! Set the Kahn sampling cutoff energy (MeV)
  void setKahnSamplingCutoffEnergy( const double energy );

  //! Return the Kahn sampling cutoff energy (MeV)
  double getKahnSamplingCutoffEnergy() const;

  //! Return the absolute min Kahn sampling cutoff energy (MeV)
  static double getAbsoluteMinKahnSamplingCutoffEnergy();

  //! Set the number of photon hash grid bins
  void setNumberOfPhotonHashGridBins( const unsigned bins );

  //! Get the number of photon hash grid bins
  unsigned getNumberOfPhotonHashGridBins() const;

  //! Set the incoherent model type
  void setIncoherentModelType( const IncoherentModelType model );

  //! Return the incoherent model
  IncoherentModelType getIncoherentModelType() const;

  //! Set atomic relaxation mode to off (on by default)
  void setAtomicRelaxationModeOff();

  //! Set atomic relaxation mode to on (on by default)
  void setAtomicRelaxationModeOn();

  //! Return if atomic relaxation mode is on
  bool isAtomicRelaxationModeOn() const;

  //! Set detailed pair production mode to off (off by default)
  void setDetailedPairProductionModeOff();

  //! Set detailed pair production mode to on (off by default)
  void setDetailedPairProductionModeOn();

  //! Return if detailed pair production mode is on
  bool isDetailedPairProductionModeOn() const;

  //! Set photonuclear interaction mode to off (off by default)
  void setPhotonuclearInteractionModeOff();

  //! Set photonuclear interaction mode to on (off by default)
  void setPhotonuclearInteractionModeOn();

  //! Return if photonuclear interaction mode is on
  bool isPhotonuclearInteractionModeOn() const;

  //! Set the cutoff roulette threshold weight
  void setPhotonRouletteThresholdWeight( const double threshold_weight );

  //! Return the cutoff roulette threshold weight
  double getPhotonRouletteThresholdWeight() const;

  //! Set the cutoff roulette survival weight
  void setPhotonRouletteSurvivalWeight( const double survival_weight );

  //! Return the cutoff roulette survival weight
  double getPhotonRouletteSurvivalWeight() const;

private:

  // Save/load the state to an archive
  template<typename Archive>
  void serialize( Archive& ar, const unsigned version );

  // Declare the boost serialization access object as a friend
  friend class boost::serialization::access;

  // The absolute minimum photon energy (MeV)
  static const double s_absolute_min_photon_energy;

  // The absolute maximum photon energy
  static const double s_absolute_max_photon_energy;

  // The absolute min Kahn sampling cutoff energy (MeV)
  static const double s_absolute_min_kahn_sampling_cutoff_energy;

  // The minimum photon energy (MeV)
  double d_min_photon_energy;

  // The maximum photon energy (MeV)
  double d_max_photon_energy;

  // The Kahn sampling cutoff energy (MeV)
  double d_kahn_sampling_cutoff_energy;

  // The number of photon hash grid bins
  unsigned d_num_photon_hash_grid_bins;

  // The incoherent model
  IncoherentModelType d_incoherent_model_type;

  // The atomic relaxation mode (true = on - default, false = off)
  bool d_atomic_relaxation_mode_on;

  // The detailed pair production mode (true = on, false = off - default)
  bool d_detailed_pair_production_mode_on;

  // The photonuclear interaction mode (true = on, false = off - default)
  bool d_photonuclear_interaction_mode_on;

  // The roulette threshold weight
  double d_threshold_weight;

  // The roulette survival weight
  double d_survival_weight;
};

// Save/load the state to an archive
template<typename Archive>
void SimulationPhotonProperties::serialize( Archive& ar,
                                            const unsigned version )
{
  ar & BOOST_SERIALIZATION_NVP( d_min_photon_energy );
  ar & BOOST_SERIALIZATION_NVP( d_max_photon_energy );
  ar & BOOST_SERIALIZATION_NVP( d_kahn_sampling_cutoff_energy );
  ar & BOOST_SERIALIZATION_NVP( d_num_photon_hash_grid_bins );
  ar & BOOST_SERIALIZATION_NVP( d_incoherent_model_type );
  ar & BOOST_SERIALIZATION_NVP( d_atomic_relaxation_mode_on );
  ar & BOOST_SERIALIZATION_NVP( d_detailed_pair_production_mode_on );
  ar & BOOST_SERIALIZATION_NVP( d_photonuclear_interaction_mode_on );
  ar & BOOST_SERIALIZATION_NVP( d_threshold_weight );
  ar & BOOST_SERIALIZATION_NVP( d_survival_weight );
}

} // end MonteCarlo namespace

#if !defined SWIG

BOOST_CLASS_VERSION( MonteCarlo::SimulationPhotonProperties, 0 );
BOOST_CLASS_EXPORT_KEY2( MonteCarlo::SimulationPhotonProperties, "SimulationPhotonProperties" );
EXTERN_EXPLICIT_CLASS_SERIALIZE_INST( MonteCarlo, SimulationPhotonProperties );

#endif // end !defined SWIG

#endif // end MONTE_CARLO_SIMULATION_PHOTON_PROPERTIES_HPP

//---------------------------------------------------------------------------//
// end MonteCarlo_SimulationPhotonProperties.cpp
//---------------------------------------------------------------------------//