<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    <exception>
#include    <malloc.h>

#if     qPlatform_POSIX
#include    <unistd.h>
#endif

#include    "../Memory/Common.h"

#include    "MallocGuard.h"

using   namespace   Stroika::Foundation;
using   Memory::Byte;

#if     qStroika_Foundation_Debug_MallocGuard
namespace {
    using   GuradBytes_ =   Byte[16];
    constexpr   GuradBytes_ kMallocGuardHeader_ =   { 0xf3, 0xfa, 0x0b, 0x93, 0x48, 0x50, 0x46, 0xe6, 0x22, 0xf1, 0xfa, 0xc0, 0x9a, 0x0b, 0xeb, 0x23, };
    constexpr   GuradBytes_ kMallocGuardFooter_ =   { 0x07, 0x41, 0xa4, 0x2b, 0xba, 0x97, 0xcb, 0x38, 0x46, 0x1e, 0x3c, 0x42, 0x3c, 0x5f, 0x0c, 0x80, };
    constexpr   Byte        kDeadMansLand_[]    =   { 0x1d, 0xb6, 0x20, 0x27, 0x43, 0x7a, 0x3d, 0x1a, 0x13, 0x65, };

    struct alignas(alignof(long double))  HeaderOrFooter_ {
        GuradBytes_ fGuard;
        size_t      fRequestedBlockSize;
    };

    void    OhShit_ ()
    {
        static  bool    sDone_      { false };      // doing terminate MIGHT allocate more memory ... just go with the flow if that happens - and dont re-barf (e.g. allow backtrace if possible)
        if (not sDone_) {
            sDone_ = true;
            const char  kMsg_[] =   "Fatal Error detected in Stroika Malloc Guard\n";
            ::write (2, kMsg_, NEltsOf (kMsg_));
            std::terminate ();
        }
    }

    void*   ExposedPtrToBackendPtr_ (void* p)
    {
        if (p == nullptr) {
            OhShit_ ();
        }
        return reinterpret_cast<HeaderOrFooter_*> (p) - 1;
    }
    void*   BackendPtrToExposedPtr_ (void* p)
    {
        if (p == nullptr) {
            OhShit_ ();
        }
        return reinterpret_cast<HeaderOrFooter_*> (p) + 1;
    }
    size_t  AdjustMallocSize_ (size_t s)
    {
        return s + 2 * sizeof (HeaderOrFooter_);
    }

    bool    IsDeadMansLand_ (const Byte* s, const Byte* e)
    {
        return false;
    }
    void    SetDeadMansLand_ (Byte* s, Byte* e)
    {
        const   Byte*   pBadFillStart   =   begin (kDeadMansLand_);
        const   Byte*   pBadFillEnd     =   end (kDeadMansLand_);
        const   Byte*   badFillI        =   pBadFillStart;
        for (Byte* oi = s; oi != e; ++oi) {
            *oi = *badFillI;
            badFillI++;
            if (badFillI == pBadFillEnd) {
                badFillI = pBadFillStart;
            }
        }
    }
    void    SetDeadMansLand_ (void* p)
    {
        const HeaderOrFooter_*  hp  =   reinterpret_cast<const HeaderOrFooter_*> (p);
        SetDeadMansLand_ (reinterpret_cast<Byte*> (p), reinterpret_cast<Byte*> (p) + AdjustMallocSize_ (hp->fRequestedBlockSize));
    }

    /*
     *  not 100% threadsafe, but OK.
     *
     *  Also FreeList alway uses BackendPtr - not ExternalPtr
     */
    void*   sFreeList_[100];
    void**  sFreeList_NextFreeI_    =   &sFreeList_[0];
    void    Add2FreeList_ (void* p)
    {
        *sFreeList_NextFreeI_ = p;
        void**  next = sFreeList_NextFreeI_ + 1;
        if (next >= end (sFreeList_)) {
            next = begin (sFreeList_);
        }
        sFreeList_NextFreeI_ = next;    // race in that we could SKIP recording a free element, but thats harmless - just a missed opportunity to detect an error
    }
    void    ClearFromFreeList_ (void* p)
    {
        // not a race because you cannot free and allocate the same pointer at the same time
        for (void** i = begin (sFreeList_); i != end (sFreeList_); ++i) {
            if (*i == p) {
                *i = nullptr;
            }
        }
    }
    bool    IsInFreeList_ (const void* p)
    {
        for (void** i = begin (sFreeList_); i != end (sFreeList_); ++i) {
            if (*i == p) {
                return true;
            }
        }
        return false;
    }

    void    Validate_ (const HeaderOrFooter_& header, const HeaderOrFooter_& footer)
    {
        if (::memcmp (&header.fGuard, &kMallocGuardHeader_, sizeof (kMallocGuardHeader_)) != 0) {
            OhShit_ ();
        }
        if (::memcmp (&footer.fGuard, &kMallocGuardFooter_, sizeof (kMallocGuardFooter_)) != 0) {
            OhShit_ ();
        }
        if (header.fRequestedBlockSize != footer.fRequestedBlockSize) {
            OhShit_ ();
        }
        // OK
    }
    void    ValidateBackendPtr_ (const void* p)
    {
        const HeaderOrFooter_*  hp  =   reinterpret_cast<const HeaderOrFooter_*> (p);
        const HeaderOrFooter_*  fp  =   reinterpret_cast<const HeaderOrFooter_*> (reinterpret_cast<const Byte*> (hp + 1) + hp->fRequestedBlockSize);
        HeaderOrFooter_ footer;
        (void)::memcpy (&footer, fp, sizeof (footer));  // align access
        Validate_ (*hp, footer);
        if (IsInFreeList_ (p)) {
            OhShit_ ();
        }
    }

    void   PatchNewPointer_ (void* p, size_t requestedSize)
    {
        HeaderOrFooter_*  hp   =   reinterpret_cast< HeaderOrFooter_*> (p);
        (void)::memcpy (begin (hp->fGuard), begin (kMallocGuardHeader_),  NEltsOf (kMallocGuardHeader_));
        hp->fRequestedBlockSize = requestedSize;
        HeaderOrFooter_*  fp  =    reinterpret_cast< HeaderOrFooter_*> (reinterpret_cast<Byte*> (hp + 1) + hp->fRequestedBlockSize);
        (void)::memcpy (begin (fp->fGuard), begin (kMallocGuardFooter_),  NEltsOf (kMallocGuardFooter_));
        fp->fRequestedBlockSize = requestedSize;
    }
}
#endif

#if     qStroika_Foundation_Debug_MallocGuard

extern "C"  void    __libc_free (void* __ptr);
extern "C"  void*   __libc_malloc (size_t __size);
extern "C"  void*   __libc_realloc (void* __ptr, size_t __size);
extern "C"  void*   __libc_calloc (size_t __nmemb, size_t __size);
extern "C"  void    __libc_free (void* __ptr);

extern "C"  void*   calloc (size_t __nmemb, size_t __size)
{
    size_t  n   =   __nmemb * __size;
    void*   p   =   malloc (n);
    (void)::memset (p, 0, n);
    return p;
}

extern "C"  void    cfree (void* __ptr)
{
    free (__ptr);
}

extern "C"  void    free (void* __ptr)
{
    if (__ptr == nullptr) {
        // according to http://linux.die.net/man/3/free
        // "if ptr is NULL, no operation is performed." - and glibc does call this internally
        return;
    }
    void*   p = ExposedPtrToBackendPtr_ (__ptr);
    ValidateBackendPtr_ (p);
    SetDeadMansLand_ (p);
    Add2FreeList_ (p);
    __libc_free (p);
}

extern "C"  void*   malloc (size_t __size)
{
    void*   p   =   __libc_malloc (AdjustMallocSize_ (__size));
    PatchNewPointer_ (p, __size);
    ClearFromFreeList_ (p);
    ValidateBackendPtr_ (p);
    if (p != nullptr) {
        p = BackendPtrToExposedPtr_ (p);
    }
    return p;
}

extern "C"  void*    realloc (void* __ptr, size_t __size)
{
    if (__ptr == nullptr) {
        // from http://linux.die.net/man/3/realloc
        // If ptr is NULL, then the call is equivalent to malloc(size),
        return malloc (__size);
    }
    if (__ptr != nullptr and __size == 0) {
        // from http://linux.die.net/man/3/realloc
        // if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr).
        free (__ptr);
        return nullptr;
    }
    void*   p   =   ExposedPtrToBackendPtr_ (__ptr);
    ValidateBackendPtr_ (p);
    size_t  n   =   AdjustMallocSize_ (__size);
    void*   newP = __libc_realloc (p, n);
    if (newP != nullptr) {
        PatchNewPointer_ (newP, __size);
        if (newP != p) {
            //Already been freed, so not safe to set at this point!!! - SetDeadMansLand_ (p);
            Add2FreeList_ (p);
            ClearFromFreeList_ (newP);
        }
        ValidateBackendPtr_ (newP);
        newP = BackendPtrToExposedPtr_ (newP);
    }
    return newP;
}

extern "C"  void*   valloc (size_t __size)
{
    // http://linux.die.net/man/3/valloc "OBSOLETE"
    OhShit_ ();
    return nullptr;
}

extern "C"  void*   pvalloc (size_t __size)
{
    // http://linux.die.net/man/3/valloc "OBSOLETE"
    OhShit_ ();
    return nullptr;
}

extern "C"  void*   memalign (size_t __alignment, size_t __size)
{
    // http://linux.die.net/man/3/valloc "OBSOLETE"
    OhShit_ ();
    return nullptr;
}

extern "C"  size_t malloc_usable_size (void* ptr)
{
    if (ptr == nullptr) {
        return 0;
    }
    void*   p   =   ExposedPtrToBackendPtr_ (ptr);
    ValidateBackendPtr_ (p);
    const HeaderOrFooter_*  hp  =   reinterpret_cast<const HeaderOrFooter_*> (p);
    return hp->fRequestedBlockSize;
}

extern "C"  int posix_memalign (void** memptr, size_t alignment, size_t size)
{
    // Probably SHOULD implement ... but so far not running into trouble cuz anything I link to calling this...
    OhShit_ ();
    return 0;
}
#endif
<commit_msg>use atomicload / store for freelist in MallocGuard to avoid false posatives<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../StroikaPreComp.h"

#include    <atomic>
#include    <exception>
#include    <malloc.h>

#if     qPlatform_POSIX
#include    <unistd.h>
#endif

#include    "../Memory/Common.h"

#include    "MallocGuard.h"

using   namespace   Stroika::Foundation;
using   Memory::Byte;

#if     qStroika_Foundation_Debug_MallocGuard
namespace {
    using   GuradBytes_ =   Byte[16];
    constexpr   GuradBytes_ kMallocGuardHeader_ =   { 0xf3, 0xfa, 0x0b, 0x93, 0x48, 0x50, 0x46, 0xe6, 0x22, 0xf1, 0xfa, 0xc0, 0x9a, 0x0b, 0xeb, 0x23, };
    constexpr   GuradBytes_ kMallocGuardFooter_ =   { 0x07, 0x41, 0xa4, 0x2b, 0xba, 0x97, 0xcb, 0x38, 0x46, 0x1e, 0x3c, 0x42, 0x3c, 0x5f, 0x0c, 0x80, };
    constexpr   Byte        kDeadMansLand_[]    =   { 0x1d, 0xb6, 0x20, 0x27, 0x43, 0x7a, 0x3d, 0x1a, 0x13, 0x65, };

    struct alignas(alignof(long double))  HeaderOrFooter_ {
        GuradBytes_ fGuard;
        size_t      fRequestedBlockSize;
    };

    void    OhShit_ ()
    {
        static  bool    sDone_      { false };      // doing terminate MIGHT allocate more memory ... just go with the flow if that happens - and dont re-barf (e.g. allow backtrace if possible)
        if (not sDone_) {
            sDone_ = true;
            const char  kMsg_[] =   "Fatal Error detected in Stroika Malloc Guard\n";
            ::write (2, kMsg_, NEltsOf (kMsg_));
            std::terminate ();
        }
    }

    void*   ExposedPtrToBackendPtr_ (void* p)
    {
        if (p == nullptr) {
            OhShit_ ();
        }
        return reinterpret_cast<HeaderOrFooter_*> (p) - 1;
    }
    void*   BackendPtrToExposedPtr_ (void* p)
    {
        if (p == nullptr) {
            OhShit_ ();
        }
        return reinterpret_cast<HeaderOrFooter_*> (p) + 1;
    }
    size_t  AdjustMallocSize_ (size_t s)
    {
        return s + 2 * sizeof (HeaderOrFooter_);
    }

    bool    IsDeadMansLand_ (const Byte* s, const Byte* e)
    {
        // NYI cuz not clear if/how/where to use...
        return false;
    }
    void    SetDeadMansLand_ (Byte* s, Byte* e)
    {
        const   Byte*   pBadFillStart   =   begin (kDeadMansLand_);
        const   Byte*   pBadFillEnd     =   end (kDeadMansLand_);
        const   Byte*   badFillI        =   pBadFillStart;
        for (Byte* oi = s; oi != e; ++oi) {
            *oi = *badFillI;
            badFillI++;
            if (badFillI == pBadFillEnd) {
                badFillI = pBadFillStart;
            }
        }
    }
    void    SetDeadMansLand_ (void* p)
    {
        const HeaderOrFooter_*  hp  =   reinterpret_cast<const HeaderOrFooter_*> (p);
        SetDeadMansLand_ (reinterpret_cast<Byte*> (p), reinterpret_cast<Byte*> (p) + AdjustMallocSize_ (hp->fRequestedBlockSize));
    }

    /*
     *  Not 100% threadsafe, but probably OK.
     *
     *  If we add something and it doesn't really get added, we just miss the opporuntity to detect a bug, but we don't create one.
     *
     *  Assure we flush any entries CLEARED with ClearFromFreeList_ (why we use atomic_store_explicit)
     *
     *  Also FreeList alway uses BackendPtr - not ExternalPtr
     */
    volatile    void*   sFreeList_[100];
    void**  sFreeList_NextFreeI_    =   &sFreeList_[0];
    void    Add2FreeList_ (void* p)
    {
        *sFreeList_NextFreeI_ = p;
        void**  next = sFreeList_NextFreeI_ + 1;
        if (next >= end (sFreeList_)) {
            next = begin (sFreeList_);
        }
        sFreeList_NextFreeI_ = next;    // race in that we could SKIP recording a free element, but thats harmless - just a missed opportunity to detect an error
    }
    void    ClearFromFreeList_ (void* p)
    {
        // not a race because you cannot free and allocate the same pointer at the same time
        for (volatile void** i = begin (sFreeList_); i != end (sFreeList_); ++i) {
            if (std::atomic_load_explicit (i, memory_order_acquire) == p) {
                std::atomic_store_explicit (i, nullptr, memory_order_release);
            }
        }
    }
    bool    IsInFreeList_ (const void* p)
    {
        for (void** i = begin (sFreeList_); i != end (sFreeList_); ++i) {
            if (std::atomic_load_explicit (i, memory_order_acquire) == p) {
                return true;
            }
        }
        return false;
    }

    void    Validate_ (const HeaderOrFooter_& header, const HeaderOrFooter_& footer)
    {
        if (::memcmp (&header.fGuard, &kMallocGuardHeader_, sizeof (kMallocGuardHeader_)) != 0) {
            OhShit_ ();
        }
        if (::memcmp (&footer.fGuard, &kMallocGuardFooter_, sizeof (kMallocGuardFooter_)) != 0) {
            OhShit_ ();
        }
        if (header.fRequestedBlockSize != footer.fRequestedBlockSize) {
            OhShit_ ();
        }
        // OK
    }
    void    ValidateBackendPtr_ (const void* p)
    {
        const HeaderOrFooter_*  hp  =   reinterpret_cast<const HeaderOrFooter_*> (p);
        const HeaderOrFooter_*  fp  =   reinterpret_cast<const HeaderOrFooter_*> (reinterpret_cast<const Byte*> (hp + 1) + hp->fRequestedBlockSize);
        HeaderOrFooter_ footer;
        (void)::memcpy (&footer, fp, sizeof (footer));  // align access
        Validate_ (*hp, footer);
        if (IsInFreeList_ (p)) {
            OhShit_ ();
        }
    }

    void   PatchNewPointer_ (void* p, size_t requestedSize)
    {
        HeaderOrFooter_*  hp   =   reinterpret_cast< HeaderOrFooter_*> (p);
        (void)::memcpy (begin (hp->fGuard), begin (kMallocGuardHeader_),  NEltsOf (kMallocGuardHeader_));
        hp->fRequestedBlockSize = requestedSize;
        HeaderOrFooter_*  fp  =    reinterpret_cast< HeaderOrFooter_*> (reinterpret_cast<Byte*> (hp + 1) + hp->fRequestedBlockSize);
        (void)::memcpy (begin (fp->fGuard), begin (kMallocGuardFooter_),  NEltsOf (kMallocGuardFooter_));
        fp->fRequestedBlockSize = requestedSize;
    }
}
#endif

#if     qStroika_Foundation_Debug_MallocGuard

extern "C"  void    __libc_free (void* __ptr);
extern "C"  void*   __libc_malloc (size_t __size);
extern "C"  void*   __libc_realloc (void* __ptr, size_t __size);
extern "C"  void*   __libc_calloc (size_t __nmemb, size_t __size);
extern "C"  void    __libc_free (void* __ptr);

extern "C"  void*   calloc (size_t __nmemb, size_t __size)
{
    size_t  n   =   __nmemb * __size;
    void*   p   =   malloc (n);
    (void)::memset (p, 0, n);
    return p;
}

extern "C"  void    cfree (void* __ptr)
{
    free (__ptr);
}

extern "C"  void    free (void* __ptr)
{
    if (__ptr == nullptr) {
        // according to http://linux.die.net/man/3/free
        // "if ptr is NULL, no operation is performed." - and glibc does call this internally
        return;
    }
    void*   p = ExposedPtrToBackendPtr_ (__ptr);
    ValidateBackendPtr_ (p);
    SetDeadMansLand_ (p);
    Add2FreeList_ (p);
    __libc_free (p);
}

extern "C"  void*   malloc (size_t __size)
{
    void*   p   =   __libc_malloc (AdjustMallocSize_ (__size));
    PatchNewPointer_ (p, __size);
    ClearFromFreeList_ (p);
    ValidateBackendPtr_ (p);
    if (p != nullptr) {
        p = BackendPtrToExposedPtr_ (p);
    }
    return p;
}

extern "C"  void*    realloc (void* __ptr, size_t __size)
{
    if (__ptr == nullptr) {
        // from http://linux.die.net/man/3/realloc
        // If ptr is NULL, then the call is equivalent to malloc(size),
        return malloc (__size);
    }
    if (__ptr != nullptr and __size == 0) {
        // from http://linux.die.net/man/3/realloc
        // if size is equal to zero, and ptr is not NULL, then the call is equivalent to free(ptr).
        free (__ptr);
        return nullptr;
    }
    void*   p   =   ExposedPtrToBackendPtr_ (__ptr);
    ValidateBackendPtr_ (p);
    size_t  n   =   AdjustMallocSize_ (__size);
    void*   newP = __libc_realloc (p, n);
    if (newP != nullptr) {
        PatchNewPointer_ (newP, __size);
        if (newP != p) {
            //Already been freed, so not safe to set at this point!!! - SetDeadMansLand_ (p);
            Add2FreeList_ (p);
            ClearFromFreeList_ (newP);
        }
        ValidateBackendPtr_ (newP);
        newP = BackendPtrToExposedPtr_ (newP);
    }
    return newP;
}

extern "C"  void*   valloc (size_t __size)
{
    // http://linux.die.net/man/3/valloc "OBSOLETE"
    OhShit_ ();
    return nullptr;
}

extern "C"  void*   pvalloc (size_t __size)
{
    // http://linux.die.net/man/3/valloc "OBSOLETE"
    OhShit_ ();
    return nullptr;
}

extern "C"  void*   memalign (size_t __alignment, size_t __size)
{
    // http://linux.die.net/man/3/valloc "OBSOLETE"
    OhShit_ ();
    return nullptr;
}

extern "C"  size_t malloc_usable_size (void* ptr)
{
    if (ptr == nullptr) {
        return 0;
    }
    void*   p   =   ExposedPtrToBackendPtr_ (ptr);
    ValidateBackendPtr_ (p);
    const HeaderOrFooter_*  hp  =   reinterpret_cast<const HeaderOrFooter_*> (p);
    return hp->fRequestedBlockSize;
}

extern "C"  int posix_memalign (void** memptr, size_t alignment, size_t size)
{
    // Probably SHOULD implement ... but so far not running into trouble cuz anything I link to calling this...
    OhShit_ ();
    return 0;
}
#endif
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include "stinger_core/xmalloc.h"
#include "stinger_core/stinger_error.h"
#include "stinger_core/stinger.h"
#include "stinger_net/mon_handling.h"
#include "stinger_net/stinger_mon.h"

#define MONGO_HAVE_STDINT
#include "mongo_c_driver/mongo.h"
#include "alg_to_mongo.h"

using namespace gt::stinger;

int
array_to_bson   (
			    bson ** documents,
			    stinger_t * S,
			    int64_t nv,
			    StingerAlgState * alg_state,
			    uint64_t timestamp,
			    int64_t start,
			    int64_t end
			    )
{
  if (!S) {
    LOG_E("STINGER pointer is invalid");
    return -1;
  }

  if (!alg_state) {
    LOG_E("StingerAlgState pointer is invalid");
    return -1;
  }

  const char * description_string = alg_state->data_description.c_str();

  /* Temporary storage for description string to parse */
  size_t len = strlen(description_string);
  char * tmp = (char *) xmalloc ((len+1) * sizeof(char));

  int64_t item_count = 0;

  for (int64_t vtx = start; vtx < end && vtx < nv; vtx++, item_count++)
  {
    size_t off = 0;
    bson * bson_ptr = documents[item_count];
    char * physID;
    size_t len;

    /* initialize BSON object for this vertex */
    bson_init (bson_ptr);
    bson_append_new_oid (bson_ptr, "_id");
    bson_append_long (bson_ptr, "time", timestamp);

    strcpy(tmp, description_string);

    /* get the physical name of the vertex */
    if (-1 == stinger_mapping_physid_direct(S, vtx, &physID, &len)) {  // XXX: check and see if this is null-terminated
      physID = (char *) "\0";
      len = 0;
    }

    bson_append_string (bson_ptr, "vtx", physID);

    /* get a fresh copy of the alg data pointer */
    uint8_t * data = (uint8_t *) alg_state->data;

    /* the description string is space-delimited */
    char * placeholder;
    char * ptr = strtok_r (tmp, " ", &placeholder);

    /* skip the formatting */
    char * pch = strtok_r (NULL, " ", &placeholder);

    while (pch != NULL)
    {
      switch (description_string[off]) {
	case 'f':
	  {
	    double value = (double)((float *) data)[vtx];
	    bson_append_double (bson_ptr, pch, value);
	    break;
	  }

	case 'd':
	  {
	    double value = (double)((double *) data)[vtx];
	    bson_append_double (bson_ptr, pch, value);
	    break;
	  }

	case 'i':
	  {
	    int value = (int)((int32_t *) data)[vtx];
	    bson_append_int (bson_ptr, pch, value);
	    break;
	  }

	case 'l':
	  {
	    int64_t value = (int64_t)((int64_t *) data)[vtx];
	    bson_append_long (bson_ptr, pch, value);
	    break;
	  }

	case 'b':
	  {
	    uint8_t value = (uint8_t)((uint8_t *) data)[vtx];
	    bson_append_int (bson_ptr, pch, value);
	    break;
	  }

	default:
	  LOG_W_A("Umm...what letter was that?\ndescription_string: %s", description_string);
	  return -1;

      }

      /* advance the data pointer to the next field */
      switch (description_string[off]) {
	case 'f':
	  data += (nv * sizeof(float));
	  break;

	case 'd':
	  data += (nv * sizeof(double));
	  break;

	case 'i':
	  data += (nv * sizeof(int32_t));
	  break;

	case 'l':
	  data += (nv * sizeof(int64_t));
	  break;

	case 'b':
	  data += (nv * sizeof(uint8_t));
	  break;

	default:
	  LOG_W_A("Umm...what letter was that?\ndescription_string: %s", description_string);
	  return -1;

      }
      off++;

      pch = strtok_r (NULL, " ", &placeholder);
    } /* pch */

    bson_finish (bson_ptr);

  } /* vtx */

  free(tmp);

  return item_count;
}
<commit_msg>changed variable type to match function call type<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include "stinger_core/xmalloc.h"
#include "stinger_core/stinger_error.h"
#include "stinger_core/stinger.h"
#include "stinger_net/mon_handling.h"
#include "stinger_net/stinger_mon.h"

#define MONGO_HAVE_STDINT
#include "mongo_c_driver/mongo.h"
#include "alg_to_mongo.h"

using namespace gt::stinger;

int
array_to_bson   (
			    bson ** documents,
			    stinger_t * S,
			    int64_t nv,
			    StingerAlgState * alg_state,
			    uint64_t timestamp,
			    int64_t start,
			    int64_t end
			    )
{
  if (!S) {
    LOG_E("STINGER pointer is invalid");
    return -1;
  }

  if (!alg_state) {
    LOG_E("StingerAlgState pointer is invalid");
    return -1;
  }

  const char * description_string = alg_state->data_description.c_str();

  /* Temporary storage for description string to parse */
  size_t len = strlen(description_string);
  char * tmp = (char *) xmalloc ((len+1) * sizeof(char));

  int64_t item_count = 0;

  for (int64_t vtx = start; vtx < end && vtx < nv; vtx++, item_count++)
  {
    size_t off = 0;
    bson * bson_ptr = documents[item_count];
    char * physID;
    uint64_t len;

    /* initialize BSON object for this vertex */
    bson_init (bson_ptr);
    bson_append_new_oid (bson_ptr, "_id");
    bson_append_long (bson_ptr, "time", timestamp);

    strcpy(tmp, description_string);

    /* get the physical name of the vertex */
    if (-1 == stinger_mapping_physid_direct(S, vtx, &physID, &len)) {  // XXX: check and see if this is null-terminated
      physID = (char *) "\0";
      len = 0;
    }

    bson_append_string (bson_ptr, "vtx", physID);

    /* get a fresh copy of the alg data pointer */
    uint8_t * data = (uint8_t *) alg_state->data;

    /* the description string is space-delimited */
    char * placeholder;
    char * ptr = strtok_r (tmp, " ", &placeholder);

    /* skip the formatting */
    char * pch = strtok_r (NULL, " ", &placeholder);

    while (pch != NULL)
    {
      switch (description_string[off]) {
	case 'f':
	  {
	    double value = (double)((float *) data)[vtx];
	    bson_append_double (bson_ptr, pch, value);
	    break;
	  }

	case 'd':
	  {
	    double value = (double)((double *) data)[vtx];
	    bson_append_double (bson_ptr, pch, value);
	    break;
	  }

	case 'i':
	  {
	    int value = (int)((int32_t *) data)[vtx];
	    bson_append_int (bson_ptr, pch, value);
	    break;
	  }

	case 'l':
	  {
	    int64_t value = (int64_t)((int64_t *) data)[vtx];
	    bson_append_long (bson_ptr, pch, value);
	    break;
	  }

	case 'b':
	  {
	    uint8_t value = (uint8_t)((uint8_t *) data)[vtx];
	    bson_append_int (bson_ptr, pch, value);
	    break;
	  }

	default:
	  LOG_W_A("Umm...what letter was that?\ndescription_string: %s", description_string);
	  return -1;

      }

      /* advance the data pointer to the next field */
      switch (description_string[off]) {
	case 'f':
	  data += (nv * sizeof(float));
	  break;

	case 'd':
	  data += (nv * sizeof(double));
	  break;

	case 'i':
	  data += (nv * sizeof(int32_t));
	  break;

	case 'l':
	  data += (nv * sizeof(int64_t));
	  break;

	case 'b':
	  data += (nv * sizeof(uint8_t));
	  break;

	default:
	  LOG_W_A("Umm...what letter was that?\ndescription_string: %s", description_string);
	  return -1;

      }
      off++;

      pch = strtok_r (NULL, " ", &placeholder);
    } /* pch */

    bson_finish (bson_ptr);

  } /* vtx */

  free(tmp);

  return item_count;
}
<|endoftext|>


<commit_before>/*=============================================================================

  Library: CTK

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  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 "ctkCmdLineModuleManager.h"

#include "ctkCmdLineModuleBackend.h"
#include "ctkCmdLineModuleFrontend.h"
#include "ctkCmdLineModuleCache_p.h"
#include "ctkCmdLineModuleFuture.h"
#include "ctkCmdLineModuleXmlValidator.h"
#include "ctkCmdLineModuleReference.h"
#include "ctkCmdLineModuleReference_p.h"

#include <ctkException.h>

#include <QFileInfo>
#include <QDir>
#include <QStringList>
#include <QBuffer>
#include <QUrl>
#include <QHash>
#include <QList>
#include <QMutex>

#include <QFuture>

#if (QT_VERSION < QT_VERSION_CHECK(4,7,0))
extern int qHash(const QUrl& url);
#endif

//----------------------------------------------------------------------------
struct ctkCmdLineModuleManagerPrivate
{
  ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode, const QString& cacheDir)
    : ValidationMode(mode)
  {
    QFileInfo fileInfo(cacheDir);
    if (!fileInfo.exists())
    {
      if (!QDir().mkpath(cacheDir))
      {
        qWarning() << "Command line module cache disabled. Directory" << cacheDir << "could not be created.";
        return;
      }
    }

    if (fileInfo.isWritable())
    {
      ModuleCache.reset(new ctkCmdLineModuleCache(cacheDir));
    }
    else
    {
      qWarning() << "Command line module cache disabled. Directory" << cacheDir << "is not writable.";
    }
  }

  void checkBackends_unlocked(const QUrl& location)
  {
    if (!this->SchemeToBackend.contains(location.scheme()))
    {
      throw ctkInvalidArgumentException(QString("No suitable backend registered for module at ") + location.toString());
    }
  }

  QMutex Mutex;
  QHash<QString, ctkCmdLineModuleBackend*> SchemeToBackend;
  QHash<QUrl, ctkCmdLineModuleReference> LocationToRef;
  QScopedPointer<ctkCmdLineModuleCache> ModuleCache;

  const ctkCmdLineModuleManager::ValidationMode ValidationMode;
};

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode, const QString& cacheDir)
  : d(new ctkCmdLineModuleManagerPrivate(validationMode, cacheDir))
{
}

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::~ctkCmdLineModuleManager()
{
}

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::ValidationMode ctkCmdLineModuleManager::validationMode() const
{
  return d->ValidationMode;
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend)
{
  QMutexLocker lock(&d->Mutex);

  QList<QString> supportedSchemes = backend->schemes();

  // Check if there is already a backend registerd for any of the
  // supported schemes. We only supported one backend per scheme.
  foreach (QString scheme, supportedSchemes)
  {
    if (d->SchemeToBackend.contains(scheme))
    {
      throw ctkInvalidArgumentException(QString("A backend for scheme %1 is already registered.").arg(scheme));
    }
  }

  // All good
  foreach (QString scheme, supportedSchemes)
  {
    d->SchemeToBackend[scheme] = backend;
  }
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference
ctkCmdLineModuleManager::registerModule(const QUrl &location)
{
  QByteArray xml;
  ctkCmdLineModuleBackend* backend = NULL;
  {
    QMutexLocker lock(&d->Mutex);

    d->checkBackends_unlocked(location);

    // If the module is already registered, just return the reference
    if (d->LocationToRef.contains(location))
    {
      return d->LocationToRef[location];
    }

    backend = d->SchemeToBackend[location.scheme()];
  }

  bool fromCache = false;
  qint64 newTimeStamp = 0;
  if (d->ModuleCache)
  {
    newTimeStamp = backend->timeStamp(location);
    if (d->ModuleCache->timeStamp(location) < newTimeStamp)
    {
      // newly fetch the XML description
      try
      {
        xml = backend->rawXmlDescription(location);
      }
      catch (...)
      {
        // cache the failed attempt
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
        throw;
      }
    }
    else
    {
      // use the cached XML description
      xml = d->ModuleCache->rawXmlDescription(location);
      fromCache = true;
    }
  }
  else
  {
    xml = backend->rawXmlDescription(location);
  }

  if (xml.isEmpty())
  {
    if (!fromCache && d->ModuleCache)
    {
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
    }
    throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString());
  }

  ctkCmdLineModuleReference ref;
  ref.d->Location = location;
  ref.d->RawXmlDescription = xml;
  ref.d->Backend = backend;

  if (d->ValidationMode != SKIP_VALIDATION)
  {
    // validate the outputted xml description
    QBuffer input(&xml);
    input.open(QIODevice::ReadOnly);

    ctkCmdLineModuleXmlValidator validator(&input);
    if (!validator.validateInput())
    {
      if (d->ModuleCache)
      {
        // validation failed, cache the description anyway
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }

      if (d->ValidationMode == STRICT_VALIDATION)
      {
        throw ctkInvalidArgumentException(QString("Validating module at %1 failed: %2")
                                          .arg(location.toString()).arg(validator.errorString()));
      }
      else
      {
        ref.d->XmlValidationErrorString = validator.errorString();
      }
    }
    else
    {
      if (d->ModuleCache && newTimeStamp > 0)
      {
        // successfully validated the xml, cache it
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }
    }
  }
  else
  {
    if (!fromCache && d->ModuleCache)
    {
      // cache it
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
    }
  }

  {
    QMutexLocker lock(&d->Mutex);
    // Check that we don't have a race condition
    if (d->LocationToRef.contains(location))
    {
      // Another thread registered a module with the same location
      return d->LocationToRef[location];
    }
    d->LocationToRef[location] = ref;
  }

  emit moduleRegistered(ref);
  return ref;
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
{
  if (!ref) return;

  {
    QMutexLocker lock(&d->Mutex);
    if (!d->LocationToRef.contains(ref.location()))
    {
      return;
    }
    d->LocationToRef.remove(ref.location());
    if (d->ModuleCache)
    {
      d->ModuleCache->removeCacheEntry(ref.location());
    }
  }
  emit moduleUnregistered(ref);
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::clearCache()
{
  d->ModuleCache->clearCache();
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const
{
  QMutexLocker lock(&d->Mutex);
  QHash<QUrl, ctkCmdLineModuleReference>::const_iterator iter = d->LocationToRef.find(location);
  return (iter == d->LocationToRef.end()) ? ctkCmdLineModuleReference() : iter.value();
}

//----------------------------------------------------------------------------
QList<ctkCmdLineModuleReference> ctkCmdLineModuleManager::moduleReferences() const
{
  QMutexLocker lock(&d->Mutex);
  return d->LocationToRef.values();
}

//----------------------------------------------------------------------------
ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend)
{
  QMutexLocker lock(&d->Mutex);
  d->checkBackends_unlocked(frontend->location());

  ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend);
  frontend->setFuture(future);
  emit frontend->started();
  return future;
}
<commit_msg>Don't update cache timestamp, if reading XML from cache<commit_after>/*=============================================================================

  Library: CTK

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  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 "ctkCmdLineModuleManager.h"

#include "ctkCmdLineModuleBackend.h"
#include "ctkCmdLineModuleFrontend.h"
#include "ctkCmdLineModuleCache_p.h"
#include "ctkCmdLineModuleFuture.h"
#include "ctkCmdLineModuleXmlValidator.h"
#include "ctkCmdLineModuleReference.h"
#include "ctkCmdLineModuleReference_p.h"

#include <ctkException.h>

#include <QFileInfo>
#include <QDir>
#include <QStringList>
#include <QBuffer>
#include <QUrl>
#include <QHash>
#include <QList>
#include <QMutex>

#include <QFuture>

#if (QT_VERSION < QT_VERSION_CHECK(4,7,0))
extern int qHash(const QUrl& url);
#endif

//----------------------------------------------------------------------------
struct ctkCmdLineModuleManagerPrivate
{
  ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode, const QString& cacheDir)
    : ValidationMode(mode)
  {
    QFileInfo fileInfo(cacheDir);
    if (!fileInfo.exists())
    {
      if (!QDir().mkpath(cacheDir))
      {
        qWarning() << "Command line module cache disabled. Directory" << cacheDir << "could not be created.";
        return;
      }
    }

    if (fileInfo.isWritable())
    {
      ModuleCache.reset(new ctkCmdLineModuleCache(cacheDir));
    }
    else
    {
      qWarning() << "Command line module cache disabled. Directory" << cacheDir << "is not writable.";
    }
  }

  void checkBackends_unlocked(const QUrl& location)
  {
    if (!this->SchemeToBackend.contains(location.scheme()))
    {
      throw ctkInvalidArgumentException(QString("No suitable backend registered for module at ") + location.toString());
    }
  }

  QMutex Mutex;
  QHash<QString, ctkCmdLineModuleBackend*> SchemeToBackend;
  QHash<QUrl, ctkCmdLineModuleReference> LocationToRef;
  QScopedPointer<ctkCmdLineModuleCache> ModuleCache;

  const ctkCmdLineModuleManager::ValidationMode ValidationMode;
};

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode, const QString& cacheDir)
  : d(new ctkCmdLineModuleManagerPrivate(validationMode, cacheDir))
{
}

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::~ctkCmdLineModuleManager()
{
}

//----------------------------------------------------------------------------
ctkCmdLineModuleManager::ValidationMode ctkCmdLineModuleManager::validationMode() const
{
  return d->ValidationMode;
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend)
{
  QMutexLocker lock(&d->Mutex);

  QList<QString> supportedSchemes = backend->schemes();

  // Check if there is already a backend registerd for any of the
  // supported schemes. We only supported one backend per scheme.
  foreach (QString scheme, supportedSchemes)
  {
    if (d->SchemeToBackend.contains(scheme))
    {
      throw ctkInvalidArgumentException(QString("A backend for scheme %1 is already registered.").arg(scheme));
    }
  }

  // All good
  foreach (QString scheme, supportedSchemes)
  {
    d->SchemeToBackend[scheme] = backend;
  }
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference
ctkCmdLineModuleManager::registerModule(const QUrl &location)
{
  QByteArray xml;
  ctkCmdLineModuleBackend* backend = NULL;
  {
    QMutexLocker lock(&d->Mutex);

    d->checkBackends_unlocked(location);

    // If the module is already registered, just return the reference
    if (d->LocationToRef.contains(location))
    {
      return d->LocationToRef[location];
    }

    backend = d->SchemeToBackend[location.scheme()];
  }

  bool fromCache = false;
  qint64 newTimeStamp = 0;
  qint64 cacheTimeStamp = 0;
  if (d->ModuleCache)
  {
    newTimeStamp = backend->timeStamp(location);
    cacheTimeStamp = d->ModuleCache->timeStamp(location);
    if (cacheTimeStamp < 0                // i.e. timestamp is invalid
        || cacheTimeStamp < newTimeStamp) // i.e. timestamp is genuinely out of date
    {
      // newly fetch the XML description
      try
      {
        xml = backend->rawXmlDescription(location);
      }
      catch (...)
      {
        // cache the failed attempt
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
        throw;
      }
    }
    else
    {
      // use the cached XML description
      xml = d->ModuleCache->rawXmlDescription(location);
      fromCache = true;
    }
  }
  else
  {
    xml = backend->rawXmlDescription(location);
  }

  if (xml.isEmpty())
  {
    if (!fromCache && d->ModuleCache)
    {
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray());
    }
    throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString());
  }

  ctkCmdLineModuleReference ref;
  ref.d->Location = location;
  ref.d->RawXmlDescription = xml;
  ref.d->Backend = backend;

  if (d->ValidationMode != SKIP_VALIDATION)
  {
    // validate the outputted xml description
    QBuffer input(&xml);
    input.open(QIODevice::ReadOnly);

    ctkCmdLineModuleXmlValidator validator(&input);
    if (!validator.validateInput())
    {
      if (d->ModuleCache)
      {
        // validation failed, cache the description anyway
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }

      if (d->ValidationMode == STRICT_VALIDATION)
      {
        throw ctkInvalidArgumentException(QString("Validating module at %1 failed: %2")
                                          .arg(location.toString()).arg(validator.errorString()));
      }
      else
      {
        ref.d->XmlValidationErrorString = validator.errorString();
      }
    }
    else
    {
      if (d->ModuleCache && newTimeStamp > 0 && !fromCache)
      {
        // successfully validated the xml, cache it
        d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
      }
    }
  }
  else
  {
    if (!fromCache && d->ModuleCache)
    {
      // cache it
      d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml);
    }
  }

  {
    QMutexLocker lock(&d->Mutex);
    // Check that we don't have a race condition
    if (d->LocationToRef.contains(location))
    {
      // Another thread registered a module with the same location
      return d->LocationToRef[location];
    }
    d->LocationToRef[location] = ref;
  }

  emit moduleRegistered(ref);
  return ref;
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
{
  if (!ref) return;

  {
    QMutexLocker lock(&d->Mutex);
    if (!d->LocationToRef.contains(ref.location()))
    {
      return;
    }
    d->LocationToRef.remove(ref.location());
    if (d->ModuleCache)
    {
      d->ModuleCache->removeCacheEntry(ref.location());
    }
  }
  emit moduleUnregistered(ref);
}

//----------------------------------------------------------------------------
void ctkCmdLineModuleManager::clearCache()
{
  d->ModuleCache->clearCache();
}

//----------------------------------------------------------------------------
ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const
{
  QMutexLocker lock(&d->Mutex);
  QHash<QUrl, ctkCmdLineModuleReference>::const_iterator iter = d->LocationToRef.find(location);
  return (iter == d->LocationToRef.end()) ? ctkCmdLineModuleReference() : iter.value();
}

//----------------------------------------------------------------------------
QList<ctkCmdLineModuleReference> ctkCmdLineModuleManager::moduleReferences() const
{
  QMutexLocker lock(&d->Mutex);
  return d->LocationToRef.values();
}

//----------------------------------------------------------------------------
ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend)
{
  QMutexLocker lock(&d->Mutex);
  d->checkBackends_unlocked(frontend->location());

  ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend);
  frontend->setFuture(future);
  emit frontend->started();
  return future;
}
<|endoftext|>


<commit_before>#include "../cshared/shared.h"
#include "../cshared/opcodes.h"
#include "../cshared/opcodes_format.h"
#include "../cshared/opcodes_debug.h"
#include "../cshared/asm_stream.h"
#include "../cshared/stream.h"

struct Arg
{
    uint64_t    fixnum = 0;
    std::string string;

    Arg(uint64_t fixnum) : fixnum(fixnum)
    {
    }
    Arg(dab_register_t reg) : fixnum(reg.value())
    {
    }
    Arg(std::vector<dab_register_t> regs)
    {
        (void)regs;
    }
    Arg(std::string string) : string(string)
    {
    }
};

struct Op
{
    size_t           code;
    std::vector<Arg> data;

    uint16_t arg_uint16(size_t index)
    {
        return data[index].fixnum;
    }

    std::string arg_string(size_t index)
    {
        return data[index].string;
    }
};

void read_stream(Stream &stream)
{
    byte buffer[1024];
    while (!feof(stdin))
    {
        size_t bytes = fread(buffer, 1, 1024, stdin);
        if (bytes)
        {
            stream.append(buffer, bytes);
        }
    }
}

void parse_stream(Stream &stream, std::function<void(Op)> func)
{
    while (!stream.eof())
    {
        auto opcode = stream.read_uint8();
        assert(opcode < countof(g_opcodes));
        const auto &data = g_opcodes[opcode];
        Op          op;
        op.code = opcode;
        for (const auto &arg : data.args)
        {
            switch (arg)
            {
            case OpcodeArg::ARG_INT8:
                op.data.push_back(stream.read_int8());
                break;
            case OpcodeArg::ARG_UINT8:
                op.data.push_back(stream.read_uint8());
                break;
            case OpcodeArg::ARG_UINT16:
                op.data.push_back(stream.read_uint16());
                break;
            case OpcodeArg::ARG_UINT64:
                op.data.push_back(stream.read_uint64());
                break;
            case OpcodeArg::ARG_INT16:
                op.data.push_back(stream.read_int16());
                break;
            case OpcodeArg::ARG_VLC:
                op.data.push_back(stream.read_vlc_string());
                break;
            case OpcodeArg::ARG_UINT32:
                op.data.push_back(stream.read_uint32());
                break;
            case OpcodeArg::ARG_INT32:
                op.data.push_back(stream.read_int32());
                break;
            case OpcodeArg::ARG_INT64:
                op.data.push_back(stream.read_int64());
                break;
            case OpcodeArg::ARG_REG:
                op.data.push_back(stream.read_reg());
                break;
            case OpcodeArg::ARG_SYMBOL:
                op.data.push_back(stream.read_symbol());
                break;
            case OpcodeArg::ARG_REGLIST:
                op.data.push_back(stream.read_reglist());
                break;
            case OpcodeArg::ARG_STRING4:
                op.data.push_back(stream.read_string4());
                break;
            case OpcodeArg::ARG_CSTRING:
                op.data.push_back(stream.read_cstring());
                break;
            }
        }
        func(op);
    }
};

int main()
{
    std::map<uint64_t, std::string>        files;
    std::map<uint64_t, std::set<uint64_t>> lines;

    Stream stream;
    read_stream(stream);
    auto header = stream.peek_header();
    fprintf(stderr, "cdumpcov: %d sections\n", (int)header->section_count);
    for (size_t i = 0; i < header->section_count; i++)
    {
        auto section = header->sections[i];
        fprintf(stderr, "cdumpcov: section[%d] '%s'\n", (int)i, section.name);
        std::string section_name = section.name;
        if (section_name == "cove")
        {
            auto size_of_cov_file    = sizeof(uint64_t);
            auto number_of_cov_files = section.length / size_of_cov_file;
            fprintf(stderr, "cdumpcov: %d cov files\n", (int)number_of_cov_files);
            for (size_t j = 0; j < number_of_cov_files; j++)
            {
                auto ptr    = section.pos + size_of_cov_file * j;
                auto data   = stream.uint64_data(ptr);
                auto string = stream.cstring_data(data);
                fprintf(stderr, "cdumpcov: cov[%d] %p -> %p -> '%s'\n", (int)j, (void *)ptr,
                        (void *)data, string.c_str());
                files[j + 1] = string;
            }
        }
        if (section_name == "code")
        {
            auto substream = stream.section_stream(i);
            parse_stream(substream, [&files, &lines](Op op) {
                if (op.code == OP_COV)
                {
                    lines[op.arg_uint16(0)].insert(op.arg_uint16(1));
                }
            });
        }
    }

    printf("[");
    int j = 0;
    for (auto f : files)
    {
        if (j++ > 0)
            printf(",");
        printf("{\"file\": \"%s\", \"lines\": [", f.second.c_str());
        auto &file_lines = lines[f.first];
        int   i          = 0;
        for (auto line : file_lines)
        {
            if (i++ > 0)
                printf(", ");
            printf("%d", (int)line);
        }
        printf("]}");
    }
    printf("]\n");

    return 0;
}
<commit_msg>dumpcov: remove unused arg_string function<commit_after>#include "../cshared/shared.h"
#include "../cshared/opcodes.h"
#include "../cshared/opcodes_format.h"
#include "../cshared/opcodes_debug.h"
#include "../cshared/asm_stream.h"
#include "../cshared/stream.h"

struct Arg
{
    uint64_t    fixnum = 0;
    std::string string;

    Arg(uint64_t fixnum) : fixnum(fixnum)
    {
    }
    Arg(dab_register_t reg) : fixnum(reg.value())
    {
    }
    Arg(std::vector<dab_register_t> regs)
    {
        (void)regs;
    }
    Arg(std::string string) : string(string)
    {
    }
};

struct Op
{
    size_t           code;
    std::vector<Arg> data;

    uint16_t arg_uint16(size_t index)
    {
        return data[index].fixnum;
    }
};

void read_stream(Stream &stream)
{
    byte buffer[1024];
    while (!feof(stdin))
    {
        size_t bytes = fread(buffer, 1, 1024, stdin);
        if (bytes)
        {
            stream.append(buffer, bytes);
        }
    }
}

void parse_stream(Stream &stream, std::function<void(Op)> func)
{
    while (!stream.eof())
    {
        auto opcode = stream.read_uint8();
        assert(opcode < countof(g_opcodes));
        const auto &data = g_opcodes[opcode];
        Op          op;
        op.code = opcode;
        for (const auto &arg : data.args)
        {
            switch (arg)
            {
            case OpcodeArg::ARG_INT8:
                op.data.push_back(stream.read_int8());
                break;
            case OpcodeArg::ARG_UINT8:
                op.data.push_back(stream.read_uint8());
                break;
            case OpcodeArg::ARG_UINT16:
                op.data.push_back(stream.read_uint16());
                break;
            case OpcodeArg::ARG_UINT64:
                op.data.push_back(stream.read_uint64());
                break;
            case OpcodeArg::ARG_INT16:
                op.data.push_back(stream.read_int16());
                break;
            case OpcodeArg::ARG_VLC:
                op.data.push_back(stream.read_vlc_string());
                break;
            case OpcodeArg::ARG_UINT32:
                op.data.push_back(stream.read_uint32());
                break;
            case OpcodeArg::ARG_INT32:
                op.data.push_back(stream.read_int32());
                break;
            case OpcodeArg::ARG_INT64:
                op.data.push_back(stream.read_int64());
                break;
            case OpcodeArg::ARG_REG:
                op.data.push_back(stream.read_reg());
                break;
            case OpcodeArg::ARG_SYMBOL:
                op.data.push_back(stream.read_symbol());
                break;
            case OpcodeArg::ARG_REGLIST:
                op.data.push_back(stream.read_reglist());
                break;
            case OpcodeArg::ARG_STRING4:
                op.data.push_back(stream.read_string4());
                break;
            case OpcodeArg::ARG_CSTRING:
                op.data.push_back(stream.read_cstring());
                break;
            }
        }
        func(op);
    }
};

int main()
{
    std::map<uint64_t, std::string>        files;
    std::map<uint64_t, std::set<uint64_t>> lines;

    Stream stream;
    read_stream(stream);
    auto header = stream.peek_header();
    fprintf(stderr, "cdumpcov: %d sections\n", (int)header->section_count);
    for (size_t i = 0; i < header->section_count; i++)
    {
        auto section = header->sections[i];
        fprintf(stderr, "cdumpcov: section[%d] '%s'\n", (int)i, section.name);
        std::string section_name = section.name;
        if (section_name == "cove")
        {
            auto size_of_cov_file    = sizeof(uint64_t);
            auto number_of_cov_files = section.length / size_of_cov_file;
            fprintf(stderr, "cdumpcov: %d cov files\n", (int)number_of_cov_files);
            for (size_t j = 0; j < number_of_cov_files; j++)
            {
                auto ptr    = section.pos + size_of_cov_file * j;
                auto data   = stream.uint64_data(ptr);
                auto string = stream.cstring_data(data);
                fprintf(stderr, "cdumpcov: cov[%d] %p -> %p -> '%s'\n", (int)j, (void *)ptr,
                        (void *)data, string.c_str());
                files[j + 1] = string;
            }
        }
        if (section_name == "code")
        {
            auto substream = stream.section_stream(i);
            parse_stream(substream, [&files, &lines](Op op) {
                if (op.code == OP_COV)
                {
                    lines[op.arg_uint16(0)].insert(op.arg_uint16(1));
                }
            });
        }
    }

    printf("[");
    int j = 0;
    for (auto f : files)
    {
        if (j++ > 0)
            printf(",");
        printf("{\"file\": \"%s\", \"lines\": [", f.second.c_str());
        auto &file_lines = lines[f.first];
        int   i          = 0;
        for (auto line : file_lines)
        {
            if (i++ > 0)
                printf(", ");
            printf("%d", (int)line);
        }
        printf("]}");
    }
    printf("]\n");

    return 0;
}
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the TEM tomography project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "vtkStreamingWorker.h"

#include "vtkAppendPolyData.h"
#include "vtkDataArray.h"
#include "vtkDataObject.h"
#include "vtkDataSet.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkNew.h"

#include "SubdividedVolume.h"

#include "tbb/tbb_thread.h"
#include "tbb/spin_mutex.h"

#include <iostream>

namespace
{
  typedef tbb::spin_mutex MutexType;

#define temTemplateMacro(call)                                              \
  vtkTemplateMacroCase(VTK_FLOAT, float, call);                             \
  vtkTemplateMacroCase(VTK_INT, int, call);                                 \
  vtkTemplateMacroCase(VTK_UNSIGNED_INT, unsigned int, call);               \
  vtkTemplateMacroCase(VTK_SHORT, short, call);                             \
  vtkTemplateMacroCase(VTK_UNSIGNED_SHORT, unsigned short, call);           \
  vtkTemplateMacroCase(VTK_CHAR, char, call);                               \
  vtkTemplateMacroCase(VTK_UNSIGNED_CHAR, unsigned char, call)

#define temDataArrayIteratorMacro(_array, _call)                           \
  temTemplateMacro(                                                        \
    vtkAbstractArray *_aa(_array);                                         \
    if (vtkDataArrayTemplate<VTK_TT> *_dat =                               \
        vtkDataArrayTemplate<VTK_TT>::FastDownCast(_aa))                   \
      {                                                                    \
      typedef VTK_TT vtkDAValueType;                                       \
      typedef vtkDataArrayTemplate<vtkDAValueType> vtkDAContainerType;     \
      typedef vtkDAContainerType::Iterator vtkDAIteratorType;              \
      vtkDAIteratorType vtkDABegin(_dat->Begin());                         \
      vtkDAIteratorType vtkDAEnd(_dat->End());                             \
      _call;                                                               \
      }                                                                    \
    )

template<typename LoggerType>
struct ComputeFunctor
{
  vtkStreamingWorker::AlgorithmMode Mode;
  TEM::accel::SubdividedVolume& Volume;
  vtkSmartPointer<vtkAppendPolyData>& Appender;
  MutexType* AppenderMutex;
  LoggerType& Logger;
  bool& ContinueWorking;
  bool& FinishedWorkingOnData;

  //----------------------------------------------------------------------------
  ComputeFunctor(vtkStreamingWorker::AlgorithmMode mode,
                 TEM::accel::SubdividedVolume& volume,
                 vtkSmartPointer<vtkAppendPolyData>& appender,
                 MutexType* appenderMutex,
                 bool& keepProcessing,
                 bool& finishedWorkingOnData,
                 LoggerType& logger):
    Mode(mode),
    Volume(volume),
    Appender(appender),
    AppenderMutex(appenderMutex),
    Logger(logger),
    ContinueWorking(keepProcessing),
    FinishedWorkingOnData(finishedWorkingOnData)
  {
  }

  //----------------------------------------------------------------------------
  template<typename ValueType>
  void operator()(double v, ValueType)
  {

  //wrap up this->Volume.method as a function argument
  if(this->Mode == vtkStreamingWorker::CONTOUR)
    {
    TEM::accel::ContourFunctor functor(this->Volume);
    this->run(functor, v, ValueType());
    }
  else if(this->Mode == vtkStreamingWorker::THRESHOLD)
    {
    TEM::accel::ThresholdFunctor functor(this->Volume);
    this->run(functor, v, ValueType());
    }
  }

  //----------------------------------------------------------------------------
  template<typename Functor, typename ValueType>
  void run(Functor functor, double v, ValueType)
  {
  std::size_t numCells=0;

  dax::cont::Timer<> timer;
  const std::size_t totalSubGrids = this->Volume.numSubGrids();
  vtkSmartPointer< vtkPolyData> output;

  bool haveMoreData=false;
  for(std::size_t i=0; i < totalSubGrids && this->ContinueWorking; ++i)
    {
    if(this->ContinueWorking && this->Volume.isValidSubGrid(i, v))
      {
      output = functor(v, i, ValueType(), this->Logger );
      numCells += output->GetNumberOfCells();

        //lock while we add to the appender
        {
        haveMoreData=true;
        MutexType::scoped_lock lock(*this->AppenderMutex);
        this->Appender->AddInputDataObject( output );
        }
      }
    if(i%50==0 && haveMoreData && this->ContinueWorking)
      {
      MutexType::scoped_lock lock(*this->AppenderMutex);
      this->Appender->Update();
      haveMoreData = false;
      }
    }

  //append any remaining subgrids
  if(haveMoreData && this->ContinueWorking)
    {
    MutexType::scoped_lock lock(*this->AppenderMutex);
    this->Appender->Update();
    haveMoreData = false;
    }

  this->Logger << "algorithm time: " << timer.GetElapsedTime() << " num cells " << numCells << std::endl;
  this->FinishedWorkingOnData = true;
  }
};

}

vtkStandardNewMacro(vtkStreamingWorker)

//----------------------------------------------------------------------------
class vtkStreamingWorker::WorkerInternals
{
public:
  //----------------------------------------------------------------------------
  WorkerInternals(std::size_t numSubGridsPerDim):
    Thread(),
    ContinueWorking(false),
    FinishedWorkingOnData(false),
    Volume(),
    ComputedData(),
    CurrentRenderData(),
    NumSubGridsPerDim(numSubGridsPerDim)
  {
    this->ComputedData = vtkSmartPointer<vtkAppendPolyData>::New();
    this->CurrentRenderData = vtkSmartPointer<vtkPolyData>::New();
  }

  //----------------------------------------------------------------------------
  ~WorkerInternals()
  {
    //only try to tell the thread to stop if we actually have a thread running
    if(this->Thread.joinable())
      {
      //tell the thread to stop
      this->ContinueWorking = false;

      //wait for the thread to stop
      this->Thread.join();
      }
  }

  //----------------------------------------------------------------------------
  bool IsValid() const { return this->Volume.numSubGrids() > 0; }

  //----------------------------------------------------------------------------
  void StopWork() { this->ContinueWorking = false; }

  //----------------------------------------------------------------------------
  bool IsFinished() const
  {
    //we need a better check to have this be able to handle the use
    //case that we have finished contouring before ProcessViewRequest
    //with REQUEST_STREAMING_UPDATE has been called and we report we are
    //finished before we ever report we have started.
    //I think the best way is to track that GetFinishedPieces() has been
    //called AFTER the algorithm is finished, only than are we really 'finished'

    return false;
  }

  //----------------------------------------------------------------------------
  template<class IteratorType, class LoggerType>
  bool Run(vtkStreamingWorker::AlgorithmMode mode,
           vtkImageData* input,
           double isoValue,
           IteratorType begin,
           IteratorType end,
           LoggerType& logger)
  {
    typedef typename std::iterator_traits<IteratorType>::value_type ValueType;

    //first check if we have an existing thread
    if(this->Thread.joinable())
      {
      this->ContinueWorking = false;
      this->Thread.join();
      }

    //construct a thread, swap it with the class thread
    //and make it run the code
    this->ContinueWorking = true;
    this->FinishedWorkingOnData = false;

    //clear the appender
    this->ComputedData = vtkSmartPointer<vtkAppendPolyData>::New();

    logger << "CreateSearchStructure" << std::endl;
    this->Volume = TEM::accel::SubdividedVolume( this->NumSubGridsPerDim,
                                                 input,
                                                 logger );

    logger << "ComputeHighLows" << std::endl;
    this->Volume.ComputeHighLows( begin, end, logger );

    //now give the thread the volume to contour
    ComputeFunctor<LoggerType> functor(mode,
                                       this->Volume,
                                       this->ComputedData,
                                       &this->ComputedDataMutex,
                                       this->ContinueWorking,
                                       this->FinishedWorkingOnData,
                                       logger);
    tbb::tbb_thread t(functor, isoValue, ValueType());
    this->Thread.swap(t);

    return true;
  }

//----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData> GetFinishedPieces()
{
  MutexType::scoped_lock lock(this->ComputedDataMutex);
  if(this->ComputedData->GetNumberOfInputPorts() > 0)
    {
    CurrentRenderData->ShallowCopy(ComputedData->GetOutputDataObject(0));
    }
  return this->CurrentRenderData;
}

private:
  tbb::tbb_thread Thread;
  bool ContinueWorking;
  bool FinishedWorkingOnData;

  TEM::accel::SubdividedVolume Volume;
  vtkSmartPointer<vtkAppendPolyData> ComputedData;
  vtkSmartPointer<vtkPolyData> CurrentRenderData;
  MutexType ComputedDataMutex;

  std::size_t NumSubGridsPerDim;
};

//----------------------------------------------------------------------------
vtkStreamingWorker::vtkStreamingWorker():
  Internals( new vtkStreamingWorker::WorkerInternals(6) )
{
}

//----------------------------------------------------------------------------
vtkStreamingWorker::~vtkStreamingWorker()
{
  delete this->Internals;
}

//----------------------------------------------------------------------------
void vtkStreamingWorker::StartContour(vtkImageData* image,
                                      vtkDataArray* data,
                                      double isoValue)
{
  //bad input abort
  if(!image||!data)
    {
    return;
    }
  //todo we need to spawn a thread here I believe
  switch (data->GetDataType())
      {
      temDataArrayIteratorMacro( data,
            this->Internals->Run(CONTOUR, image, isoValue, vtkDABegin, vtkDAEnd, std::cout) );
      default:
        break;
      }
}

//----------------------------------------------------------------------------
void vtkStreamingWorker::StartThreshold(vtkImageData* image,
                                      vtkDataArray* data,
                                      double isoValue)
{
  //bad input abort
  if(!image||!data)
    {
    return;
    }
  //todo we need to spawn a thread here I believe
  switch (data->GetDataType())
      {
      temDataArrayIteratorMacro( data,
            this->Internals->Run(THRESHOLD, image, isoValue, vtkDABegin, vtkDAEnd, std::cout) );
      default:
        break;
      }
}

//----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData>
vtkStreamingWorker::GetFinishedPieces()
{
  return this->Internals->GetFinishedPieces();
}

//----------------------------------------------------------------------------
void vtkStreamingWorker::StopWork()
{
  this->Internals->StopWork();
}

//----------------------------------------------------------------------------
bool vtkStreamingWorker::IsFinished() const
{
  return this->Internals->IsFinished();
}

//----------------------------------------------------------------------------
bool vtkStreamingWorker::AlreadyComputedSearchStructure() const
{
  return this->Internals->IsValid();
}

//------------------------------------------------------------------------------
void vtkStreamingWorker::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<commit_msg>Fix a bug where the vtkStreamingWorker wasn't caching HighLow computation.<commit_after>/******************************************************************************

  This source file is part of the TEM tomography project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "vtkStreamingWorker.h"

#include "vtkAppendPolyData.h"
#include "vtkDataArray.h"
#include "vtkDataObject.h"
#include "vtkDataSet.h"
#include "vtkImageData.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkNew.h"

#include "SubdividedVolume.h"

#include "tbb/tbb_thread.h"
#include "tbb/spin_mutex.h"

#include <iostream>

namespace
{
  typedef tbb::spin_mutex MutexType;

#define temTemplateMacro(call)                                              \
  vtkTemplateMacroCase(VTK_FLOAT, float, call);                             \
  vtkTemplateMacroCase(VTK_INT, int, call);                                 \
  vtkTemplateMacroCase(VTK_UNSIGNED_INT, unsigned int, call);               \
  vtkTemplateMacroCase(VTK_SHORT, short, call);                             \
  vtkTemplateMacroCase(VTK_UNSIGNED_SHORT, unsigned short, call);           \
  vtkTemplateMacroCase(VTK_CHAR, char, call);                               \
  vtkTemplateMacroCase(VTK_UNSIGNED_CHAR, unsigned char, call)

#define temDataArrayIteratorMacro(_array, _call)                           \
  temTemplateMacro(                                                        \
    vtkAbstractArray *_aa(_array);                                         \
    if (vtkDataArrayTemplate<VTK_TT> *_dat =                               \
        vtkDataArrayTemplate<VTK_TT>::FastDownCast(_aa))                   \
      {                                                                    \
      typedef VTK_TT vtkDAValueType;                                       \
      typedef vtkDataArrayTemplate<vtkDAValueType> vtkDAContainerType;     \
      typedef vtkDAContainerType::Iterator vtkDAIteratorType;              \
      vtkDAIteratorType vtkDABegin(_dat->Begin());                         \
      vtkDAIteratorType vtkDAEnd(_dat->End());                             \
      _call;                                                               \
      }                                                                    \
    )

template<typename LoggerType>
struct ComputeFunctor
{
  vtkStreamingWorker::AlgorithmMode Mode;
  TEM::accel::SubdividedVolume& Volume;
  vtkSmartPointer<vtkAppendPolyData>& Appender;
  MutexType* AppenderMutex;
  LoggerType& Logger;
  bool& ContinueWorking;
  bool& FinishedWorkingOnData;

  //----------------------------------------------------------------------------
  ComputeFunctor(vtkStreamingWorker::AlgorithmMode mode,
                 TEM::accel::SubdividedVolume& volume,
                 vtkSmartPointer<vtkAppendPolyData>& appender,
                 MutexType* appenderMutex,
                 bool& keepProcessing,
                 bool& finishedWorkingOnData,
                 LoggerType& logger):
    Mode(mode),
    Volume(volume),
    Appender(appender),
    AppenderMutex(appenderMutex),
    Logger(logger),
    ContinueWorking(keepProcessing),
    FinishedWorkingOnData(finishedWorkingOnData)
  {
  }

  //----------------------------------------------------------------------------
  template<typename ValueType>
  void operator()(double v, ValueType)
  {

  //wrap up this->Volume.method as a function argument
  if(this->Mode == vtkStreamingWorker::CONTOUR)
    {
    TEM::accel::ContourFunctor functor(this->Volume);
    this->run(functor, v, ValueType());
    }
  else if(this->Mode == vtkStreamingWorker::THRESHOLD)
    {
    TEM::accel::ThresholdFunctor functor(this->Volume);
    this->run(functor, v, ValueType());
    }
  }

  //----------------------------------------------------------------------------
  template<typename Functor, typename ValueType>
  void run(Functor functor, double v, ValueType)
  {
  dax::cont::Timer<> timer;
  const std::size_t totalSubGrids = this->Volume.numSubGrids();
  vtkSmartPointer< vtkPolyData> output;

  bool haveMoreData=false;
  for(std::size_t i=0; i < totalSubGrids && this->ContinueWorking; ++i)
    {
    if(this->ContinueWorking && this->Volume.isValidSubGrid(i, v))
      {
      output = functor(v, i, ValueType(), this->Logger );

        //lock while we add to the appender
        {
        haveMoreData=true;
        MutexType::scoped_lock lock(*this->AppenderMutex);
        this->Appender->AddInputDataObject( output );
        }
      }
    if(i%50==0 && haveMoreData && this->ContinueWorking)
      {
      MutexType::scoped_lock lock(*this->AppenderMutex);
      this->Appender->Update();
      haveMoreData = false;
      }
    }

  //append any remaining subgrids
  if(haveMoreData && this->ContinueWorking)
    {
    MutexType::scoped_lock lock(*this->AppenderMutex);
    this->Appender->Update();
    haveMoreData = false;
    }

  this->Logger << "algorithm time: " << timer.GetElapsedTime() << std::endl;
  this->FinishedWorkingOnData = true;
  }
};

}

vtkStandardNewMacro(vtkStreamingWorker)

//----------------------------------------------------------------------------
class vtkStreamingWorker::WorkerInternals
{
public:
  //----------------------------------------------------------------------------
  WorkerInternals(std::size_t numSubGridsPerDim):
    Thread(),
    ContinueWorking(false),
    FinishedWorkingOnData(false),
    CurrentRenderDataFinished(false),
    Volume(),
    ComputedData(),
    CurrentRenderData(),
    NumSubGridsPerDim(numSubGridsPerDim)
  {
    this->ComputedData = vtkSmartPointer<vtkAppendPolyData>::New();
    this->CurrentRenderData = vtkSmartPointer<vtkPolyData>::New();
  }

  //----------------------------------------------------------------------------
  ~WorkerInternals()
  {
    //only try to tell the thread to stop if we actually have a thread running
    if(this->Thread.joinable())
      {
      //tell the thread to stop
      this->ContinueWorking = false;

      //wait for the thread to stop
      this->Thread.join();
      }
  }

  //----------------------------------------------------------------------------
  bool IsValid() const { return this->Volume.numSubGrids() > 0; }

  //----------------------------------------------------------------------------
  void StopWork() { this->ContinueWorking = false; }

  //----------------------------------------------------------------------------
  bool IsFinished() const
  {
    //we need a better check to have this be able to handle the use
    //case that we have finished contouring before ProcessViewRequest
    //with REQUEST_STREAMING_UPDATE has been called and we report we are
    //finished before we ever report we have started.
    //I think the best way is to track that GetFinishedPieces() has been
    //called AFTER the algorithm is finished, only than are we really 'finished'

    return this->CurrentRenderDataFinished;
  }

  //----------------------------------------------------------------------------
  template<class IteratorType, class LoggerType>
  bool Run(vtkStreamingWorker::AlgorithmMode mode,
           vtkImageData* input,
           double isoValue,
           IteratorType begin,
           IteratorType end,
           LoggerType& logger)
  {
    typedef typename std::iterator_traits<IteratorType>::value_type ValueType;

    //first check if we have an existing thread
    if(this->Thread.joinable())
      {
      this->ContinueWorking = false;
      this->Thread.join();
      }

    //construct a thread, swap it with the class thread
    //and make it run the code
    this->ContinueWorking = true;
    this->FinishedWorkingOnData = false;
    this->CurrentRenderDataFinished = false;

    //clear the appender
    this->ComputedData = vtkSmartPointer<vtkAppendPolyData>::New();

    if(this->Volume.numSubGrids() == 0)
      {
      logger << "CreateSearchStructure" << std::endl;
      this->Volume = TEM::accel::SubdividedVolume( this->NumSubGridsPerDim,
                                                   input,
                                                   logger );

      logger << "ComputeHighLows" << std::endl;
      this->Volume.ComputeHighLows( begin, end, logger );
      }

    //now give the thread the volume to contour
    ComputeFunctor<LoggerType> functor(mode,
                                       this->Volume,
                                       this->ComputedData,
                                       &this->ComputedDataMutex,
                                       this->ContinueWorking,
                                       this->FinishedWorkingOnData,
                                       logger);
    tbb::tbb_thread t(functor, isoValue, ValueType());
    this->Thread.swap(t);

    return true;
  }

//----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData> GetFinishedPieces()
{
  MutexType::scoped_lock lock(this->ComputedDataMutex);
  if(this->ComputedData->GetNumberOfInputPorts() > 0)
    {
    CurrentRenderData->ShallowCopy(ComputedData->GetOutputDataObject(0));
    }
  this->CurrentRenderDataFinished = this->FinishedWorkingOnData;

  return this->CurrentRenderData;
}

private:
  tbb::tbb_thread Thread;
  bool ContinueWorking;
  bool FinishedWorkingOnData;
  bool CurrentRenderDataFinished;

  TEM::accel::SubdividedVolume Volume;
  vtkSmartPointer<vtkAppendPolyData> ComputedData;
  vtkSmartPointer<vtkPolyData> CurrentRenderData;
  MutexType ComputedDataMutex;

  std::size_t NumSubGridsPerDim;
};

//----------------------------------------------------------------------------
vtkStreamingWorker::vtkStreamingWorker():
  Internals( new vtkStreamingWorker::WorkerInternals(6) )
{
}

//----------------------------------------------------------------------------
vtkStreamingWorker::~vtkStreamingWorker()
{
  delete this->Internals;
}

//----------------------------------------------------------------------------
void vtkStreamingWorker::StartContour(vtkImageData* image,
                                      vtkDataArray* data,
                                      double isoValue)
{
  //bad input abort
  if(!image||!data)
    {
    return;
    }
  //todo we need to spawn a thread here I believe
  switch (data->GetDataType())
      {
      temDataArrayIteratorMacro( data,
            this->Internals->Run(CONTOUR, image, isoValue, vtkDABegin, vtkDAEnd, std::cout) );
      default:
        break;
      }
}

//----------------------------------------------------------------------------
void vtkStreamingWorker::StartThreshold(vtkImageData* image,
                                      vtkDataArray* data,
                                      double isoValue)
{
  //bad input abort
  if(!image||!data)
    {
    return;
    }
  //todo we need to spawn a thread here I believe
  switch (data->GetDataType())
      {
      temDataArrayIteratorMacro( data,
            this->Internals->Run(THRESHOLD, image, isoValue, vtkDABegin, vtkDAEnd, std::cout) );
      default:
        break;
      }
}

//----------------------------------------------------------------------------
vtkSmartPointer<vtkPolyData>
vtkStreamingWorker::GetFinishedPieces()
{
  return this->Internals->GetFinishedPieces();
}

//----------------------------------------------------------------------------
void vtkStreamingWorker::StopWork()
{
  this->Internals->StopWork();
}

//----------------------------------------------------------------------------
bool vtkStreamingWorker::IsFinished() const
{
  return this->Internals->IsFinished();
}

//----------------------------------------------------------------------------
bool vtkStreamingWorker::AlreadyComputedSearchStructure() const
{
  return this->Internals->IsValid();
}

//------------------------------------------------------------------------------
void vtkStreamingWorker::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<|endoftext|>


<commit_before>#include "Camera.h"

Camera::Camera() {

}

Camera::Camera(const Point3D& position, const uint32_t image_height, const uint32_t image_width)
  : m_position(position), m_image_height(image_height), m_image_width(image_width) {

}

Camera::~Camera(){

}

const bool Camera::insideFrustrum(const Point2D& point_raster, const float depth) const {
  const float half_w = m_image_width / 2;
  const float half_h = m_image_height / 2;
  return (point_raster.x < half_w && point_raster.x > -half_w &&
    point_raster.y < half_h && point_raster.y > -half_h &&
    depth > m_near && depth < m_far);
}<commit_msg>Fixed clipping function bug and added depth value as parameter<commit_after>#include "Camera.h"

Camera::Camera() {

}

Camera::Camera(const Point3D& position, const uint32_t image_height, const uint32_t image_width)
  : m_position(position), m_image_height(image_height), m_image_width(image_width) {

}

Camera::~Camera(){

}

const bool Camera::insideFrustrum(const Point2D& point_raster, const float depth) const {
  return (point_raster.x < m_image_width && point_raster.x >= 0 &&
    point_raster.y < m_image_height && point_raster.y >= 0 &&
    depth >= m_near && depth <= m_far);
}<|endoftext|>


<commit_before>// handy text editor
// Copyright (c) 2016-2021 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "app.h"

#include "alert_view.h"
#include "app.h"
#include "base.h"
#include "base/fs.h"
#include "ctx.h"
#include "doc_view.h"
#include "lua.h"
#include "view.h"

App::App(int argc, char* argv[])
  : m_lua(new Lua)
  , m_term(nullptr) {
  m_running = true;

  for (int i=0; i<argc; ++i) {
    if (std::strcmp(argv[i], "-tui") == 0) {
      m_term = Term::MakeTUI();
    }
    else if (std::strcmp(argv[i], "-gui") == 0) {
#if LAF_SKIA
      m_term = Term::MakeGUI();
#else
      std::printf("There isn't GUI support");
      exit(1);
#endif
    }
  }

  if (!m_term) {
#if LAF_SKIA
    m_term = Term::MakeGUI();
#else
    m_term = Term::MakeTUI();
#endif
  }

  m_main = m_term->makePanel(0, 0, m_term->width(), m_term->height()-1);
  m_status = m_term->makePanel(0, m_term->height()-1, m_term->width(), 1);
  m_panels.push_back(m_main);
  m_panels.push_back(m_status);

  ViewPtr main_view(new DocView(DocPtr(new Doc)));
  m_views.push(main_view);
  main_view->set_panel(m_main);

  m_lua->run_script(base::get_file_title_with_path(argv[0]) + ".lua");
  m_lua->run_code("if init then init() end");
}

App::~App()
{
  m_lua->run_code("if exit then exit() end");
}

// Ctx impl
void App::close() {
  m_running = false;
}

PanelPtr App::status() {
  return m_status;
}

ViewPtr App::view() {
  return m_views.top();
}

void App::set_view(const ViewPtr& v) {
  v->set_panel(view()->panel());
  view()->set_panel(nullptr);
  m_views.push(v);
}

void App::back_view() {
  PanelPtr panel = view()->panel();
  m_views.pop();
  view()->set_panel(panel);
}

int App::alert(const char* msg) {
  ViewPtr alert_view(new AlertView(msg));
  set_view(alert_view);
  while (is_running() && view() == alert_view)
    loop();
  return ((AlertView*)alert_view.get())->result();
}

bool App::is_running() const {
  return m_running;
}

void App::loop() {
  ViewPtr view = this->view();
  view->show(this);

  int ch = view->panel()->get_char();

  view->on_key(this, ch);
}

void App::open_file(const char* fn) {
  DocPtr doc(new Doc);
  if (doc->load(fn))
    set_view(ViewPtr(new DocView(doc)));
}
<commit_msg>Missing <cstring> to use std::strcmp()<commit_after>// handy text editor
// Copyright (c) 2016-2021 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "app.h"

#include "alert_view.h"
#include "app.h"
#include "base.h"
#include "base/fs.h"
#include "ctx.h"
#include "doc_view.h"
#include "lua.h"
#include "view.h"

#include <cstring>

App::App(int argc, char* argv[])
  : m_lua(new Lua)
  , m_term(nullptr) {
  m_running = true;

  for (int i=0; i<argc; ++i) {
    if (std::strcmp(argv[i], "-tui") == 0) {
      m_term = Term::MakeTUI();
    }
    else if (std::strcmp(argv[i], "-gui") == 0) {
#if LAF_SKIA
      m_term = Term::MakeGUI();
#else
      std::printf("There isn't GUI support");
      exit(1);
#endif
    }
  }

  if (!m_term) {
#if LAF_SKIA
    m_term = Term::MakeGUI();
#else
    m_term = Term::MakeTUI();
#endif
  }

  m_main = m_term->makePanel(0, 0, m_term->width(), m_term->height()-1);
  m_status = m_term->makePanel(0, m_term->height()-1, m_term->width(), 1);
  m_panels.push_back(m_main);
  m_panels.push_back(m_status);

  ViewPtr main_view(new DocView(DocPtr(new Doc)));
  m_views.push(main_view);
  main_view->set_panel(m_main);

  m_lua->run_script(base::get_file_title_with_path(argv[0]) + ".lua");
  m_lua->run_code("if init then init() end");
}

App::~App()
{
  m_lua->run_code("if exit then exit() end");
}

// Ctx impl
void App::close() {
  m_running = false;
}

PanelPtr App::status() {
  return m_status;
}

ViewPtr App::view() {
  return m_views.top();
}

void App::set_view(const ViewPtr& v) {
  v->set_panel(view()->panel());
  view()->set_panel(nullptr);
  m_views.push(v);
}

void App::back_view() {
  PanelPtr panel = view()->panel();
  m_views.pop();
  view()->set_panel(panel);
}

int App::alert(const char* msg) {
  ViewPtr alert_view(new AlertView(msg));
  set_view(alert_view);
  while (is_running() && view() == alert_view)
    loop();
  return ((AlertView*)alert_view.get())->result();
}

bool App::is_running() const {
  return m_running;
}

void App::loop() {
  ViewPtr view = this->view();
  view->show(this);

  int ch = view->panel()->get_char();

  view->on_key(this, ch);
}

void App::open_file(const char* fn) {
  DocPtr doc(new Doc);
  if (doc->load(fn))
    set_view(ViewPtr(new DocView(doc)));
}
<|endoftext|>