<commit_before>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// 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 "tessellation_cache.h"

namespace embree
{
  SharedLazyTessellationCache SharedLazyTessellationCache::sharedLazyTessellationCache;

  __thread LocalTessellationCacheThreadInfo* SharedLazyTessellationCache::localThreadInfo = nullptr;

  void resizeTessellationCache(const size_t new_size)
  {
    if (new_size <= 1024 * 1024)
      THROW_RUNTIME_ERROR("tessellation cache size is too small");

    if (SharedLazyTessellationCache::MAX_TESSELLATION_CACHE_SIZE >= new_size &&
	SharedLazyTessellationCache::sharedLazyTessellationCache.getSize() != new_size)
      SharedLazyTessellationCache::sharedLazyTessellationCache.realloc(new_size);
  }

  void clearTessellationCache()
  {
    SharedLazyTessellationCache::sharedLazyTessellationCache.addCurrentIndex(SharedLazyTessellationCache::NUM_CACHE_SEGMENTS);
  }

  /* alloc cache memory */
  float *alloc_tessellation_cache_mem(const size_t blocks)
  {
    return (float*)_mm_malloc(64 * blocks,64);
  }

  /* free cache memory */
  void free_tessellation_cache_mem(void *mem, const size_t blocks)
  {
    assert(mem);
    _mm_free(mem);
  }

  void SharedLazyTessellationCache::createLocalThreadInfo()
  {
    localThreadInfo = new LocalTessellationCacheThreadInfo( SharedLazyTessellationCache::sharedLazyTessellationCache.getNextRenderThreadID() );
  }

  SharedLazyTessellationCache::SharedLazyTessellationCache()
  {
    size                   = DEFAULT_TESSELLATION_CACHE_SIZE;
#if defined(_MSC_VER)
    data                   = (float*)os_malloc(size);
#else
    data                   = (float*)os_reserve(size);
#endif

    maxBlocks              = size/64;
    index                  = 0; // 1
    next_block             = 0;
    numRenderThreads       = 0;
#if FORCE_SIMPLE_FLUSH == 1
    switch_block_threshold = maxBlocks;
#else
    switch_block_threshold = maxBlocks/NUM_CACHE_SEGMENTS;
#endif
    numMaxRenderThreads = MAX_MIC_THREADS;
    threadWorkState     = (ThreadWorkState*)malloc(sizeof(ThreadWorkState)*numMaxRenderThreads);

    for (size_t i=0;i<numMaxRenderThreads;i++)
      threadWorkState[i].reset();

    reset_state.reset();
  }

  size_t SharedLazyTessellationCache::getNextRenderThreadID()
  {
    mtx_threads.lock();
    const size_t id = numRenderThreads.add(1);
    if (numRenderThreads >= numMaxRenderThreads)
      {
    	numMaxRenderThreads *= 2;
	threadWorkState      = (ThreadWorkState*)std::realloc(threadWorkState,sizeof(ThreadWorkState)*numMaxRenderThreads); // FIXME: this is buggy! cannot reallocate while thread are working on this array!

	for (size_t i=id;i<numMaxRenderThreads;i++)
	  threadWorkState[i].reset();

	assert( threadWorkState );
	if (!threadWorkState)
          THROW_RUNTIME_ERROR("realloc threadWorkState");
      }
    mtx_threads.unlock();
    return id;
  }

  void SharedLazyTessellationCache::waitForUsersLessEqual(const unsigned int threadID,
							  const unsigned int users)
   {
     while( !(threadWorkState[threadID].counter <= users) )
       {
#if defined(__MIC__)
	 _mm_delay_32(128);
#else
	 _mm_pause();
	 _mm_pause();
	 _mm_pause();
	 _mm_pause();
#endif
       }
   }

  void SharedLazyTessellationCache::resetCache()
  {
#if NEW_TCACHE_SYNC == 1

    if (reset_state.try_lock())
      {
	if (next_block >= switch_block_threshold)
	  {
	    //double msec = getSeconds();

	    for (size_t i=0;i<numRenderThreads;i++)
	      lockThread(i);

	    addCurrentIndex();

	    CACHE_STATS(PRINT("RESET TESS CACHE"));
	    //PRINT("RESET TESS CACHE");

	    for (size_t i=0;i<numRenderThreads;i++)
	      waitForUsersLessEqual(i,1);

#if FORCE_SIMPLE_FLUSH == 1
	    next_block = 0;
	    switch_block_threshold = maxBlocks;
#else
	    const size_t region = index % NUM_CACHE_SEGMENTS;
	    next_block = region * (maxBlocks/NUM_CACHE_SEGMENTS);
	    switch_block_threshold = next_block + (maxBlocks/NUM_CACHE_SEGMENTS);

#if 0
	    PRINT( region );
	    PRINT( maxBlocks );
	    PRINT( NUM_CACHE_SEGMENTS );
	    PRINT( maxBlocks/NUM_CACHE_SEGMENTS );
	    PRINT( next_block );
	    PRINT( switch_block_threshold );
#endif

	    assert( switch_block_threshold <= maxBlocks );

#endif

	    CACHE_STATS(SharedTessellationCacheStats::cache_flushes++);

	    for (size_t i=0;i<numRenderThreads;i++)
	      unlockThread(i);

	    //msec = getSeconds()-msec;
	    //PRINT( 1000.0f * msec );

	  }
	reset_state.unlock();
      }
    else
      reset_state.wait_until_unlocked();

#else

    if (reset_state.try_lock())
      {
	if (next_block >= switch_block_threshold)
	  {
	    //double msec = getSeconds();

	    for (size_t i=0;i<numRenderThreads;i++)
	      //lockThread(i);
	      if (lockThread(i) == 1)
		waitForUsersLessEqual(i,1);

	    //for (size_t i=0;i<numRenderThreads;i++)
	    //waitForUsersLessEqual(i,1);

	    addCurrentIndex();
	    CACHE_STATS(PRINT("RESET TESS CACHE"));
	    //PRINT("RESET TESS CACHE");

#if FORCE_SIMPLE_FLUSH == 1
	    next_block = 0;
	    switch_block_threshold = maxBlocks;
#else
	    const size_t region = index % NUM_CACHE_SEGMENTS;
	    next_block = region * (maxBlocks/NUM_CACHE_SEGMENTS);
	    switch_block_threshold = next_block + (maxBlocks/NUM_CACHE_SEGMENTS);

#if 0
	    PRINT( region );
	    PRINT( maxBlocks );
	    PRINT( NUM_CACHE_SEGMENTS );
	    PRINT( maxBlocks/NUM_CACHE_SEGMENTS );
	    PRINT( next_block );
	    PRINT( switch_block_threshold );
#endif

	    assert( switch_block_threshold <= maxBlocks );

#endif

	    CACHE_STATS(SharedTessellationCacheStats::cache_flushes++);

	    for (size_t i=0;i<numRenderThreads;i++)
	      unlockThread(i);

	    //msec = getSeconds()-msec;
	    //PRINT( 1000.0f * msec );

	  }
	reset_state.unlock();
      }
    else
      reset_state.wait_until_unlocked();
#endif
  }

  void SharedLazyTessellationCache::realloc(const size_t new_size)
  {
    if (data)
      {
	os_free(data,size);
      }
    size      = new_size;
    data      = (float*)os_malloc(size);
    maxBlocks = size/64;
#if FORCE_SIMPLE_FLUSH == 1
    switch_block_threshold = maxBlocks;
#else
    switch_block_threshold = maxBlocks/NUM_CACHE_SEGMENTS;
#endif

    std::cout << "Reallocating tessellation cache to " << size << " bytes, " << maxBlocks << " 64-byte blocks" << std::endl;
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////

  AtomicCounter SharedTessellationCacheStats::cache_accesses           = 0;
  AtomicCounter SharedTessellationCacheStats::cache_hits               = 0;
  AtomicCounter SharedTessellationCacheStats::cache_misses             = 0;
  AtomicCounter SharedTessellationCacheStats::cache_flushes            = 0;
  AtomicMutex   SharedTessellationCacheStats::mtx;
  AtomicCounter *SharedTessellationCacheStats::cache_patch_builds      = NULL;
  size_t SharedTessellationCacheStats::cache_num_patches               = 0;
  float **SharedTessellationCacheStats::cache_new_delete_ptr           = NULL;

  void SharedTessellationCacheStats::printStats()
  {
    PRINT(cache_accesses);
    PRINT(cache_misses);
    PRINT(cache_hits);
    PRINT(cache_flushes);
    PRINT(100.0f * cache_hits / cache_accesses);
    assert(cache_hits + cache_misses == cache_accesses);
    PRINT(cache_num_patches);
    size_t patches = 0;
    size_t builds  = 0;
    for (size_t i=0;i<cache_num_patches;i++)
      if (cache_patch_builds[i])
	{
	  patches++;
	  builds += cache_patch_builds[i];
	}
    PRINT(patches);
    PRINT(builds);
    PRINT((double)builds/patches);
  }

  void SharedTessellationCacheStats::clearStats()
  {
    SharedTessellationCacheStats::cache_accesses  = 0;
    SharedTessellationCacheStats::cache_hits      = 0;
    SharedTessellationCacheStats::cache_misses    = 0;
    SharedTessellationCacheStats::cache_flushes   = 0;
    for (size_t i=0;i<cache_num_patches;i++)
      cache_patch_builds[i] = 0;
  }

  void SharedTessellationCacheStats::incPatchBuild(const size_t ID, const size_t numPatches)
  {
    if (!cache_patch_builds)
      {
	mtx.lock();
	if (!cache_patch_builds)
	  {
	    PRINT(numPatches);
	    cache_num_patches = numPatches;
	    cache_patch_builds = (AtomicCounter*)os_malloc(numPatches*sizeof(AtomicCounter));
	    memset(cache_patch_builds,0,numPatches*sizeof(AtomicCounter));
	  }
	mtx.unlock();
      }
    assert(ID < cache_num_patches);
    cache_patch_builds[ID].add(1);
  }

  void SharedTessellationCacheStats::newDeletePatchPtr(const size_t ID, const size_t numPatches, const size_t size)
  {
    assert(ID < numPatches);
    if(!cache_new_delete_ptr)
      {
	mtx.lock();
	if(!cache_new_delete_ptr)
	  {
	    PRINT(numPatches);
	    cache_num_patches = numPatches;
	    cache_new_delete_ptr = new float*[numPatches];
	    memset(cache_new_delete_ptr,0,sizeof(float*)*numPatches);
	  }
	mtx.unlock();
      }
    if (cache_new_delete_ptr[ID])
      free(cache_new_delete_ptr[ID]);
    cache_new_delete_ptr[ID] = (float*)malloc(size);
    memset(cache_new_delete_ptr[ID],0,size);
  }

};

extern "C" void printTessCacheStats()
{
  PRINT("SHARED TESSELLATION CACHE");
  embree::SharedTessellationCacheStats::printStats();
  embree::SharedTessellationCacheStats::clearStats();
}
<commit_msg>increased numMaxRenderThreads in tessellation_cache.cpp to large value to workaround resize bug<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// 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 "tessellation_cache.h"

namespace embree
{
  SharedLazyTessellationCache SharedLazyTessellationCache::sharedLazyTessellationCache;

  __thread LocalTessellationCacheThreadInfo* SharedLazyTessellationCache::localThreadInfo = nullptr;

  void resizeTessellationCache(const size_t new_size)
  {
    if (new_size <= 1024 * 1024)
      THROW_RUNTIME_ERROR("tessellation cache size is too small");

    if (SharedLazyTessellationCache::MAX_TESSELLATION_CACHE_SIZE >= new_size &&
	SharedLazyTessellationCache::sharedLazyTessellationCache.getSize() != new_size)
      SharedLazyTessellationCache::sharedLazyTessellationCache.realloc(new_size);
  }

  void clearTessellationCache()
  {
    SharedLazyTessellationCache::sharedLazyTessellationCache.addCurrentIndex(SharedLazyTessellationCache::NUM_CACHE_SEGMENTS);
  }

  /* alloc cache memory */
  float *alloc_tessellation_cache_mem(const size_t blocks)
  {
    return (float*)_mm_malloc(64 * blocks,64);
  }

  /* free cache memory */
  void free_tessellation_cache_mem(void *mem, const size_t blocks)
  {
    assert(mem);
    _mm_free(mem);
  }

  void SharedLazyTessellationCache::createLocalThreadInfo()
  {
    localThreadInfo = new LocalTessellationCacheThreadInfo( SharedLazyTessellationCache::sharedLazyTessellationCache.getNextRenderThreadID() );
  }

  SharedLazyTessellationCache::SharedLazyTessellationCache()
  {
    size                   = DEFAULT_TESSELLATION_CACHE_SIZE;
#if defined(_MSC_VER)
    data                   = (float*)os_malloc(size);
#else
    data                   = (float*)os_reserve(size);
#endif

    maxBlocks              = size/64;
    index                  = 0; // 1
    next_block             = 0;
    numRenderThreads       = 0;
#if FORCE_SIMPLE_FLUSH == 1
    switch_block_threshold = maxBlocks;
#else
    switch_block_threshold = maxBlocks/NUM_CACHE_SEGMENTS;
#endif
    numMaxRenderThreads = 1024; //MAX_MIC_THREADS;
    threadWorkState     = (ThreadWorkState*)malloc(sizeof(ThreadWorkState)*numMaxRenderThreads);

    for (size_t i=0;i<numMaxRenderThreads;i++)
      threadWorkState[i].reset();

    reset_state.reset();
  }

  size_t SharedLazyTessellationCache::getNextRenderThreadID()
  {
    mtx_threads.lock();
    const size_t id = numRenderThreads.add(1);
    if (numRenderThreads >= numMaxRenderThreads)
      {
    	numMaxRenderThreads *= 2;
	threadWorkState      = (ThreadWorkState*)std::realloc(threadWorkState,sizeof(ThreadWorkState)*numMaxRenderThreads); // FIXME: this is buggy! cannot reallocate while thread are working on this array!

	for (size_t i=id;i<numMaxRenderThreads;i++)
	  threadWorkState[i].reset();

	assert( threadWorkState );
	if (!threadWorkState)
          THROW_RUNTIME_ERROR("realloc threadWorkState");
      }
    mtx_threads.unlock();
    return id;
  }

  void SharedLazyTessellationCache::waitForUsersLessEqual(const unsigned int threadID,
							  const unsigned int users)
   {
     while( !(threadWorkState[threadID].counter <= users) )
       {
#if defined(__MIC__)
	 _mm_delay_32(128);
#else
	 _mm_pause();
	 _mm_pause();
	 _mm_pause();
	 _mm_pause();
#endif
       }
   }

  void SharedLazyTessellationCache::resetCache()
  {
#if NEW_TCACHE_SYNC == 1

    if (reset_state.try_lock())
      {
	if (next_block >= switch_block_threshold)
	  {
	    //double msec = getSeconds();

	    for (size_t i=0;i<numRenderThreads;i++)
	      lockThread(i);

	    addCurrentIndex();

	    CACHE_STATS(PRINT("RESET TESS CACHE"));
	    //PRINT("RESET TESS CACHE");

	    for (size_t i=0;i<numRenderThreads;i++)
	      waitForUsersLessEqual(i,1);

#if FORCE_SIMPLE_FLUSH == 1
	    next_block = 0;
	    switch_block_threshold = maxBlocks;
#else
	    const size_t region = index % NUM_CACHE_SEGMENTS;
	    next_block = region * (maxBlocks/NUM_CACHE_SEGMENTS);
	    switch_block_threshold = next_block + (maxBlocks/NUM_CACHE_SEGMENTS);

#if 0
	    PRINT( region );
	    PRINT( maxBlocks );
	    PRINT( NUM_CACHE_SEGMENTS );
	    PRINT( maxBlocks/NUM_CACHE_SEGMENTS );
	    PRINT( next_block );
	    PRINT( switch_block_threshold );
#endif

	    assert( switch_block_threshold <= maxBlocks );

#endif

	    CACHE_STATS(SharedTessellationCacheStats::cache_flushes++);

	    for (size_t i=0;i<numRenderThreads;i++)
	      unlockThread(i);

	    //msec = getSeconds()-msec;
	    //PRINT( 1000.0f * msec );

	  }
	reset_state.unlock();
      }
    else
      reset_state.wait_until_unlocked();

#else

    if (reset_state.try_lock())
      {
	if (next_block >= switch_block_threshold)
	  {
	    //double msec = getSeconds();

	    for (size_t i=0;i<numRenderThreads;i++)
	      //lockThread(i);
	      if (lockThread(i) == 1)
		waitForUsersLessEqual(i,1);

	    //for (size_t i=0;i<numRenderThreads;i++)
	    //waitForUsersLessEqual(i,1);

	    addCurrentIndex();
	    CACHE_STATS(PRINT("RESET TESS CACHE"));
	    //PRINT("RESET TESS CACHE");

#if FORCE_SIMPLE_FLUSH == 1
	    next_block = 0;
	    switch_block_threshold = maxBlocks;
#else
	    const size_t region = index % NUM_CACHE_SEGMENTS;
	    next_block = region * (maxBlocks/NUM_CACHE_SEGMENTS);
	    switch_block_threshold = next_block + (maxBlocks/NUM_CACHE_SEGMENTS);

#if 0
	    PRINT( region );
	    PRINT( maxBlocks );
	    PRINT( NUM_CACHE_SEGMENTS );
	    PRINT( maxBlocks/NUM_CACHE_SEGMENTS );
	    PRINT( next_block );
	    PRINT( switch_block_threshold );
#endif

	    assert( switch_block_threshold <= maxBlocks );

#endif

	    CACHE_STATS(SharedTessellationCacheStats::cache_flushes++);

	    for (size_t i=0;i<numRenderThreads;i++)
	      unlockThread(i);

	    //msec = getSeconds()-msec;
	    //PRINT( 1000.0f * msec );

	  }
	reset_state.unlock();
      }
    else
      reset_state.wait_until_unlocked();
#endif
  }

  void SharedLazyTessellationCache::realloc(const size_t new_size)
  {
    if (data)
      {
	os_free(data,size);
      }
    size      = new_size;
    data      = (float*)os_malloc(size);
    maxBlocks = size/64;
#if FORCE_SIMPLE_FLUSH == 1
    switch_block_threshold = maxBlocks;
#else
    switch_block_threshold = maxBlocks/NUM_CACHE_SEGMENTS;
#endif

    std::cout << "Reallocating tessellation cache to " << size << " bytes, " << maxBlocks << " 64-byte blocks" << std::endl;
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  ////////////////////////////////////////////////////////////////////////////////////////////////////////////

  AtomicCounter SharedTessellationCacheStats::cache_accesses           = 0;
  AtomicCounter SharedTessellationCacheStats::cache_hits               = 0;
  AtomicCounter SharedTessellationCacheStats::cache_misses             = 0;
  AtomicCounter SharedTessellationCacheStats::cache_flushes            = 0;
  AtomicMutex   SharedTessellationCacheStats::mtx;
  AtomicCounter *SharedTessellationCacheStats::cache_patch_builds      = NULL;
  size_t SharedTessellationCacheStats::cache_num_patches               = 0;
  float **SharedTessellationCacheStats::cache_new_delete_ptr           = NULL;

  void SharedTessellationCacheStats::printStats()
  {
    PRINT(cache_accesses);
    PRINT(cache_misses);
    PRINT(cache_hits);
    PRINT(cache_flushes);
    PRINT(100.0f * cache_hits / cache_accesses);
    assert(cache_hits + cache_misses == cache_accesses);
    PRINT(cache_num_patches);
    size_t patches = 0;
    size_t builds  = 0;
    for (size_t i=0;i<cache_num_patches;i++)
      if (cache_patch_builds[i])
	{
	  patches++;
	  builds += cache_patch_builds[i];
	}
    PRINT(patches);
    PRINT(builds);
    PRINT((double)builds/patches);
  }

  void SharedTessellationCacheStats::clearStats()
  {
    SharedTessellationCacheStats::cache_accesses  = 0;
    SharedTessellationCacheStats::cache_hits      = 0;
    SharedTessellationCacheStats::cache_misses    = 0;
    SharedTessellationCacheStats::cache_flushes   = 0;
    for (size_t i=0;i<cache_num_patches;i++)
      cache_patch_builds[i] = 0;
  }

  void SharedTessellationCacheStats::incPatchBuild(const size_t ID, const size_t numPatches)
  {
    if (!cache_patch_builds)
      {
	mtx.lock();
	if (!cache_patch_builds)
	  {
	    PRINT(numPatches);
	    cache_num_patches = numPatches;
	    cache_patch_builds = (AtomicCounter*)os_malloc(numPatches*sizeof(AtomicCounter));
	    memset(cache_patch_builds,0,numPatches*sizeof(AtomicCounter));
	  }
	mtx.unlock();
      }
    assert(ID < cache_num_patches);
    cache_patch_builds[ID].add(1);
  }

  void SharedTessellationCacheStats::newDeletePatchPtr(const size_t ID, const size_t numPatches, const size_t size)
  {
    assert(ID < numPatches);
    if(!cache_new_delete_ptr)
      {
	mtx.lock();
	if(!cache_new_delete_ptr)
	  {
	    PRINT(numPatches);
	    cache_num_patches = numPatches;
	    cache_new_delete_ptr = new float*[numPatches];
	    memset(cache_new_delete_ptr,0,sizeof(float*)*numPatches);
	  }
	mtx.unlock();
      }
    if (cache_new_delete_ptr[ID])
      free(cache_new_delete_ptr[ID]);
    cache_new_delete_ptr[ID] = (float*)malloc(size);
    memset(cache_new_delete_ptr[ID],0,size);
  }

};

extern "C" void printTessCacheStats()
{
  PRINT("SHARED TESSELLATION CACHE");
  embree::SharedTessellationCacheStats::printStats();
  embree::SharedTessellationCacheStats::clearStats();
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <vespa/fastos/fastos.h>
#include "mockfileprovider.h"
#include <vespa/filedistribution/rpc/filedistributorrpc.h>
#include <vespa/frtstream/frtclientstream.h>
#include <iostream>
#include <boost/test/unit_test.hpp>

namespace fd = filedistribution;

using fd::MockFileProvider;

const std::string MockFileProvider::_queueForeverFileReference("queue-forever");

BOOST_AUTO_TEST_CASE(fileDistributionRPCTest) {
    const std::string spec("tcp/localhost:9111");
    fd::FileProvider::SP provider(new fd::MockFileProvider());
    fd::FileDistributorRPC::SP fileDistributorRPC(new fd::FileDistributorRPC(spec, provider));
    fileDistributorRPC->start();

    frtstream::FrtClientStream rpc(spec);
    frtstream::Method method("waitFor");

    std::string path;
    rpc <<method <<"dd";
    rpc >> path;
    BOOST_CHECK_EQUAL("direct/result/path", path);

    rpc <<method <<"0123456789abcdef";
    rpc >> path;
    BOOST_CHECK_EQUAL("downloaded/path/0123456789abcdef", path);
}

//must be run through valgrind
BOOST_AUTO_TEST_CASE(require_that_queued_requests_does_not_leak_memory) {
    const std::string spec("tcp/localhost:9111");
    fd::FileProvider::SP provider(new fd::MockFileProvider());
    fd::FileDistributorRPC::SP fileDistributorRPC(new fd::FileDistributorRPC(spec, provider));
    fileDistributorRPC->start();

    FRT_Supervisor supervisor;

    supervisor.Start();
    FRT_Target *target = supervisor.GetTarget(spec.c_str());

    FRT_RPCRequest* request = supervisor.AllocRPCRequest();
    request->SetMethodName("waitFor");
    request->GetParams()->AddString(MockFileProvider::_queueForeverFileReference.c_str());
    target->InvokeVoid(request);

    static_cast<fd::MockFileProvider &>(*provider)._queueForeverBarrier.wait(); //the request has been enqueued.
    fileDistributorRPC.reset();

    target->SubRef();
    supervisor.ShutDown(true);

}

BOOST_AUTO_TEST_CASE(require_that_port_can_be_extracted_from_connection_spec) {
    BOOST_CHECK_EQUAL(9056, fd::FileDistributorRPC::get_port("tcp/host:9056"));
    BOOST_CHECK_EQUAL(9056, fd::FileDistributorRPC::get_port("tcp/9056"));
    BOOST_CHECK_EQUAL(9056, fd::FileDistributorRPC::get_port("9056"));
}
<commit_msg>Avoid static cast<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <vespa/fastos/fastos.h>
#include "mockfileprovider.h"
#include <vespa/filedistribution/rpc/filedistributorrpc.h>
#include <vespa/frtstream/frtclientstream.h>
#include <iostream>
#include <boost/test/unit_test.hpp>

namespace fd = filedistribution;

using fd::MockFileProvider;

const std::string MockFileProvider::_queueForeverFileReference("queue-forever");

BOOST_AUTO_TEST_CASE(fileDistributionRPCTest) {
    const std::string spec("tcp/localhost:9111");
    fd::FileProvider::SP provider(new fd::MockFileProvider());
    fd::FileDistributorRPC::SP fileDistributorRPC(new fd::FileDistributorRPC(spec, provider));
    fileDistributorRPC->start();

    frtstream::FrtClientStream rpc(spec);
    frtstream::Method method("waitFor");

    std::string path;
    rpc <<method <<"dd";
    rpc >> path;
    BOOST_CHECK_EQUAL("direct/result/path", path);

    rpc <<method <<"0123456789abcdef";
    rpc >> path;
    BOOST_CHECK_EQUAL("downloaded/path/0123456789abcdef", path);
}

//must be run through valgrind
BOOST_AUTO_TEST_CASE(require_that_queued_requests_does_not_leak_memory) {
    const std::string spec("tcp/localhost:9111");
    std::shared_ptr<MockFileProvider> provider(new MockFileProvider());
    fd::FileDistributorRPC::SP fileDistributorRPC(new fd::FileDistributorRPC(spec, provider));
    fileDistributorRPC->start();

    FRT_Supervisor supervisor;

    supervisor.Start();
    FRT_Target *target = supervisor.GetTarget(spec.c_str());

    FRT_RPCRequest* request = supervisor.AllocRPCRequest();
    request->SetMethodName("waitFor");
    request->GetParams()->AddString(MockFileProvider::_queueForeverFileReference.c_str());
    target->InvokeVoid(request);

    provider->_queueForeverBarrier.wait(); //the request has been enqueued.
    fileDistributorRPC.reset();

    target->SubRef();
    supervisor.ShutDown(true);

}

BOOST_AUTO_TEST_CASE(require_that_port_can_be_extracted_from_connection_spec) {
    BOOST_CHECK_EQUAL(9056, fd::FileDistributorRPC::get_port("tcp/host:9056"));
    BOOST_CHECK_EQUAL(9056, fd::FileDistributorRPC::get_port("tcp/9056"));
    BOOST_CHECK_EQUAL(9056, fd::FileDistributorRPC::get_port("9056"));
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2014 Intel Corporation                                    //
//                                                                          //
// 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 "subdivpatch1cached.h"
#include "common/scene.h"

namespace embree
{
  SubdivPatch1Cached::Type SubdivPatch1Cached::type;

  SubdivPatch1Cached::Type::Type ()
    : PrimitiveType("subdivpatch1",sizeof(SubdivPatch1Cached),1,false,1) {}

  size_t SubdivPatch1Cached::Type::blocks(size_t x) const {
    return x;
  }

  size_t SubdivPatch1Cached::Type::size(const char* This) const {
    return 1;
  }

  /*! Construction from vertices and IDs. */
    SubdivPatch1Cached::SubdivPatch1Cached (const SubdivMesh::HalfEdge * first_half_edge,
                                            const Vec3fa *vertices,
                                            const unsigned int gID,
                                            const unsigned int pID,
                                            const SubdivMesh *const mesh)
      : geom(gID),
        prim(pID),
        flags(0)
    {
      assert(sizeof(SubdivPatch1Cached) == 5 * 64);

      u_range = Vec2f(0.0f,1.0f);
      v_range = Vec2f(0.0f,1.0f);

      /* init irregular patch */

      CatmullClarkPatch ipatch ( first_half_edge, vertices );

      /* init discrete edge tessellation levels and grid resolution */

      assert( ipatch.ring[0].edge_level >= 0.0f );
      assert( ipatch.ring[1].edge_level >= 0.0f );
      assert( ipatch.ring[2].edge_level >= 0.0f );
      assert( ipatch.ring[3].edge_level >= 0.0f );

#if 1
      level[0] = max(ceilf(ipatch.ring[0].edge_level),1.0f);
      level[1] = max(ceilf(ipatch.ring[1].edge_level),1.0f);
      level[2] = max(ceilf(ipatch.ring[2].edge_level),1.0f);
      level[3] = max(ceilf(ipatch.ring[3].edge_level),1.0f);
#else
      /* debugging */
      level[0] = 4;
      level[1] = 4;
      level[2] = 4;
      level[3] = 4;
#endif

      grid_u_res = max(level[0],level[2])+1; // n segments -> n+1 points
      grid_v_res = max(level[1],level[3])+1;

      grid_size_8wide_blocks       = ((grid_u_res*grid_v_res+7)&(-8)) / 8;

      DBG_PRINT( grid_size_8wide_blocks );
      grid_subtree_size_64b_blocks = 4; // single bvh4 leaf with 3x3 grid => 4 cachelines

      /* need stiching? */

      const unsigned int int_edge_points0 = (unsigned int)level[0] + 1;
      const unsigned int int_edge_points1 = (unsigned int)level[1] + 1;
      const unsigned int int_edge_points2 = (unsigned int)level[2] + 1;
      const unsigned int int_edge_points3 = (unsigned int)level[3] + 1;

      if (int_edge_points0 < (unsigned int)grid_u_res ||
	  int_edge_points2 < (unsigned int)grid_u_res ||
	  int_edge_points1 < (unsigned int)grid_v_res ||
	  int_edge_points3 < (unsigned int)grid_v_res)
	flags |= TRANSITION_PATCH;

      /* has displacements? */
      if (mesh->displFunc != NULL)
	flags |= HAS_DISPLACEMENT;

      /* tessellate into 3x3 grid blocks for larger grid resolutions, generate bvh4 subtree over 3x3 grid blocks*/
      if (grid_size_8wide_blocks > 1)
	grid_subtree_size_64b_blocks = getSubTreeSize64bBlocks( 4 ); // u,v,x,y,z

      /* determine whether patch is regular or not */

      if (ipatch.isRegular())
	{
	  flags |= REGULAR_PATCH;
	  patch.init( ipatch );
	}
      else
	{
	  GregoryPatch gpatch;
	  gpatch.init( ipatch );
	  gpatch.exportDenseConrolPoints( patch.v );
	}
#if 0
      DBG_PRINT( grid_u_res );
      DBG_PRINT( grid_v_res );
      DBG_PRINT( grid_size_16wide_blocks );
      DBG_PRINT( grid_mask );
      DBG_PRINT( grid_subtree_size_64b_blocks );
#endif
    }

}
<commit_msg>removed dbg output<commit_after>// ======================================================================== //
// Copyright 2009-2014 Intel Corporation                                    //
//                                                                          //
// 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 "subdivpatch1cached.h"
#include "common/scene.h"

namespace embree
{
  SubdivPatch1Cached::Type SubdivPatch1Cached::type;

  SubdivPatch1Cached::Type::Type ()
    : PrimitiveType("subdivpatch1",sizeof(SubdivPatch1Cached),1,false,1) {}

  size_t SubdivPatch1Cached::Type::blocks(size_t x) const {
    return x;
  }

  size_t SubdivPatch1Cached::Type::size(const char* This) const {
    return 1;
  }

  /*! Construction from vertices and IDs. */
    SubdivPatch1Cached::SubdivPatch1Cached (const SubdivMesh::HalfEdge * first_half_edge,
                                            const Vec3fa *vertices,
                                            const unsigned int gID,
                                            const unsigned int pID,
                                            const SubdivMesh *const mesh)
      : geom(gID),
        prim(pID),
        flags(0)
    {
      assert(sizeof(SubdivPatch1Cached) == 5 * 64);

      u_range = Vec2f(0.0f,1.0f);
      v_range = Vec2f(0.0f,1.0f);

      /* init irregular patch */

      CatmullClarkPatch ipatch ( first_half_edge, vertices );

      /* init discrete edge tessellation levels and grid resolution */

      assert( ipatch.ring[0].edge_level >= 0.0f );
      assert( ipatch.ring[1].edge_level >= 0.0f );
      assert( ipatch.ring[2].edge_level >= 0.0f );
      assert( ipatch.ring[3].edge_level >= 0.0f );

#if 0
      level[0] = max(ceilf(ipatch.ring[0].edge_level),1.0f);
      level[1] = max(ceilf(ipatch.ring[1].edge_level),1.0f);
      level[2] = max(ceilf(ipatch.ring[2].edge_level),1.0f);
      level[3] = max(ceilf(ipatch.ring[3].edge_level),1.0f);
#else
      /* debugging */
      level[0] = 4;
      level[1] = 4;
      level[2] = 4;
      level[3] = 4;
#endif

      grid_u_res = max(level[0],level[2])+1; // n segments -> n+1 points
      grid_v_res = max(level[1],level[3])+1;

      grid_size_8wide_blocks       = ((grid_u_res*grid_v_res+7)&(-8)) / 8;

      grid_subtree_size_64b_blocks = 4; // single bvh4 leaf with 3x3 grid => 4 cachelines

      /* need stiching? */

      const unsigned int int_edge_points0 = (unsigned int)level[0] + 1;
      const unsigned int int_edge_points1 = (unsigned int)level[1] + 1;
      const unsigned int int_edge_points2 = (unsigned int)level[2] + 1;
      const unsigned int int_edge_points3 = (unsigned int)level[3] + 1;

      if (int_edge_points0 < (unsigned int)grid_u_res ||
	  int_edge_points2 < (unsigned int)grid_u_res ||
	  int_edge_points1 < (unsigned int)grid_v_res ||
	  int_edge_points3 < (unsigned int)grid_v_res)
	flags |= TRANSITION_PATCH;

      /* has displacements? */
      if (mesh->displFunc != NULL)
	flags |= HAS_DISPLACEMENT;

      /* tessellate into 3x3 grid blocks for larger grid resolutions, generate bvh4 subtree over 3x3 grid blocks*/
      if (grid_size_8wide_blocks > 1)
	grid_subtree_size_64b_blocks = getSubTreeSize64bBlocks( 4 ); // u,v,x,y,z

      /* determine whether patch is regular or not */

      if (ipatch.isRegular())
	{
	  flags |= REGULAR_PATCH;
	  patch.init( ipatch );
	}
      else
	{
	  GregoryPatch gpatch;
	  gpatch.init( ipatch );
	  gpatch.exportDenseConrolPoints( patch.v );
	}
#if 0
      DBG_PRINT( grid_u_res );
      DBG_PRINT( grid_v_res );
      DBG_PRINT( grid_size_16wide_blocks );
      DBG_PRINT( grid_mask );
      DBG_PRINT( grid_subtree_size_64b_blocks );
#endif
    }

}
<|endoftext|>


<commit_before>#include "Genes/Sphere_of_Influence_Gene.h"

#include <cmath>
#include <array>
#include <memory>
#include <map>
#include <array>
#include <mutex>

#include "Genes/Gene.h"
#include "Game/Board.h"
#include "Game/Square.h"
#include "Moves/Move.h"
#include "Game/Color.h"

#include "Utility/Random.h"

namespace
{
    const static auto king_distances =
        []()
        {
            std::array<std::array<size_t, 64>, 64> result;
            for(auto square_a : Square::all_squares())
            {
                for(auto square_b : Square::all_squares())
                {
                    // The "king distance" between two squares is the minimum number
                    // of moves a king needs to get from one square to the other.
                    auto diff = square_a - square_b;
                    result[square_a.index()][square_b.index()] =
                        size_t(std::max(std::abs(diff.file_change), std::abs(diff.rank_change)));
                }
            }
            return result;
        }();
}

Sphere_of_Influence_Gene::Sphere_of_Influence_Gene() :
    legal_square_score(1.0),
    illegal_square_score(1.0),
    king_target_factor(0.0)
{
    recompute_scalar_cache();
}

std::map<std::string, double> Sphere_of_Influence_Gene::list_properties() const
{
    auto properties = Gene::list_properties();
    properties["Legal Square Score"] = legal_square_score;
    properties["Illegal Square Score"] = illegal_square_score;
    properties["King Target Factor"] = king_target_factor;
    return properties;
}

void Sphere_of_Influence_Gene::load_properties(const std::map<std::string, double>& properties)
{
    Gene::load_properties(properties);
    legal_square_score = properties.at("Legal Square Score");
    illegal_square_score = properties.at("Illegal Square Score");
    king_target_factor = properties.at("King Target Factor");
    recompute_scalar_cache();
}

std::unique_ptr<Gene> Sphere_of_Influence_Gene::duplicate() const
{
    return std::make_unique<Sphere_of_Influence_Gene>(*this);
}

std::string Sphere_of_Influence_Gene::name() const
{
    return "Sphere of Influence Gene";
}

// Count all squares potentially attacked by all pieces with bonus points if
// the attacking move is legal.
double Sphere_of_Influence_Gene::score_board(const Board& board, Color perspective, size_t) const
{
    const auto& opponent_king_square = board.find_king(opposite(perspective));
    auto opponent_king_index = opponent_king_square.index();

    double score = 0.0;
    for(auto square : Square::all_squares())
    {
        double square_score;
        if( ! board.safe_for_king(square, opposite(perspective))) // any piece attacks square
        {
            square_score = legal_square_score;
        }
        else if(board.blocked_attack(square, perspective)) // There are attacks on this square blocked by other pieces
        {
            square_score = illegal_square_score;
        }
        else
        {
            continue;
        }

        auto distance_to_king = king_distances[square.index()][opponent_king_index];
        score += square_score * scalar_cache[distance_to_king];
    }

    return score;
}

void Sphere_of_Influence_Gene::gene_specific_mutation()
{
    make_priority_minimum_zero();

    switch(Random::random_integer(1, 3))
    {
        case 1:
            legal_square_score += Random::random_laplace(0.5);
            break;
        case 2:
            illegal_square_score += Random::random_laplace(0.5);
            break;
        case 3:
            king_target_factor += Random::random_laplace(0.1);
            break;
        default:
            throw std::logic_error("Bad range in Sphere_of_Influence_Gene::gene_specific_mutation()");
    }

    recompute_scalar_cache();
}

void Sphere_of_Influence_Gene::recompute_scalar_cache()
{
    for(size_t king_distance = 0; king_distance < 8; ++king_distance)
    {
        scalar_cache[king_distance] = (1 + king_target_factor/(1 + king_distance))/(64*(std::abs(legal_square_score) + std::abs(illegal_square_score)));
    }
}
<commit_msg>Delete unneeded #includes<commit_after>#include "Genes/Sphere_of_Influence_Gene.h"

#include <cmath>
#include <array>
#include <memory>
#include <map>

#include "Genes/Gene.h"
#include "Game/Board.h"
#include "Game/Square.h"
#include "Moves/Move.h"
#include "Game/Color.h"

#include "Utility/Random.h"

namespace
{
    const static auto king_distances =
        []()
        {
            std::array<std::array<size_t, 64>, 64> result;
            for(auto square_a : Square::all_squares())
            {
                for(auto square_b : Square::all_squares())
                {
                    // The "king distance" between two squares is the minimum number
                    // of moves a king needs to get from one square to the other.
                    auto diff = square_a - square_b;
                    result[square_a.index()][square_b.index()] =
                        size_t(std::max(std::abs(diff.file_change), std::abs(diff.rank_change)));
                }
            }
            return result;
        }();
}

Sphere_of_Influence_Gene::Sphere_of_Influence_Gene() :
    legal_square_score(1.0),
    illegal_square_score(1.0),
    king_target_factor(0.0)
{
    recompute_scalar_cache();
}

std::map<std::string, double> Sphere_of_Influence_Gene::list_properties() const
{
    auto properties = Gene::list_properties();
    properties["Legal Square Score"] = legal_square_score;
    properties["Illegal Square Score"] = illegal_square_score;
    properties["King Target Factor"] = king_target_factor;
    return properties;
}

void Sphere_of_Influence_Gene::load_properties(const std::map<std::string, double>& properties)
{
    Gene::load_properties(properties);
    legal_square_score = properties.at("Legal Square Score");
    illegal_square_score = properties.at("Illegal Square Score");
    king_target_factor = properties.at("King Target Factor");
    recompute_scalar_cache();
}

std::unique_ptr<Gene> Sphere_of_Influence_Gene::duplicate() const
{
    return std::make_unique<Sphere_of_Influence_Gene>(*this);
}

std::string Sphere_of_Influence_Gene::name() const
{
    return "Sphere of Influence Gene";
}

// Count all squares potentially attacked by all pieces with bonus points if
// the attacking move is legal.
double Sphere_of_Influence_Gene::score_board(const Board& board, Color perspective, size_t) const
{
    const auto& opponent_king_square = board.find_king(opposite(perspective));
    auto opponent_king_index = opponent_king_square.index();

    double score = 0.0;
    for(auto square : Square::all_squares())
    {
        double square_score;
        if( ! board.safe_for_king(square, opposite(perspective))) // any piece attacks square
        {
            square_score = legal_square_score;
        }
        else if(board.blocked_attack(square, perspective)) // There are attacks on this square blocked by other pieces
        {
            square_score = illegal_square_score;
        }
        else
        {
            continue;
        }

        auto distance_to_king = king_distances[square.index()][opponent_king_index];
        score += square_score * scalar_cache[distance_to_king];
    }

    return score;
}

void Sphere_of_Influence_Gene::gene_specific_mutation()
{
    make_priority_minimum_zero();

    switch(Random::random_integer(1, 3))
    {
        case 1:
            legal_square_score += Random::random_laplace(0.5);
            break;
        case 2:
            illegal_square_score += Random::random_laplace(0.5);
            break;
        case 3:
            king_target_factor += Random::random_laplace(0.1);
            break;
        default:
            throw std::logic_error("Bad range in Sphere_of_Influence_Gene::gene_specific_mutation()");
    }

    recompute_scalar_cache();
}

void Sphere_of_Influence_Gene::recompute_scalar_cache()
{
    for(size_t king_distance = 0; king_distance < 8; ++king_distance)
    {
        scalar_cache[king_distance] = (1 + king_target_factor/(1 + king_distance))/(64*(std::abs(legal_square_score) + std::abs(illegal_square_score)));
    }
}
<|endoftext|>


<commit_before>#include "Genes/Sphere_of_Influence_Gene.h"

#include <algorithm>
#include <array>
#include <memory>

#include "Genes/Gene.h"
#include "Game/Board.h"
#include "Game/Square.h"
#include "Moves/Move.h"

#include "Utility.h"

Sphere_of_Influence_Gene::Sphere_of_Influence_Gene() :
    legal_bonus(1.0),
    king_target_factor(0.0)
{
}

void Sphere_of_Influence_Gene::reset_properties() const
{
    Gene::reset_properties();
    properties["Legal Bonus"] = legal_bonus;
    properties["King Target Factor"] = king_target_factor;
}

void Sphere_of_Influence_Gene::load_properties()
{
    Gene::load_properties();
    legal_bonus = properties["Legal Bonus"];
    king_target_factor = properties["King Target Factor"];
}

std::unique_ptr<Gene> Sphere_of_Influence_Gene::duplicate() const
{
    return std::make_unique<Sphere_of_Influence_Gene>(*this);
}

std::string Sphere_of_Influence_Gene::name() const
{
    return "Sphere of Influence Gene";
}

// Count all squares potentially attacked by all pieces with bonus points if
// the attacking move is legal.
double Sphere_of_Influence_Gene::score_board(const Board& board) const
{
    std::array<double, 64> square_score{};
    std::array<size_t, 64> distance_to_king{};
    auto opponent_king_square = board.find_king(opposite(board.whose_turn()));
    for(char file = 'a'; file <= 'h'; ++file)
    {
        for(int rank = 1; rank <= 8; ++rank)
        {
            distance_to_king[Board::board_index(file, rank)] =
                king_distance({file, rank}, opponent_king_square);
        }
    }

    double score_to_add = 1.0;
    for(const auto& move_list : {board.other_moves(), board.legal_moves()})
    {
        for(const auto& move : move_list)
        {
            // Only potentially capturing moves are counted
            if( ! move->can_capture())
            {
                continue;
            }

            char final_file = move->end_file();
            int  final_rank = move->end_rank();

            if(move->is_en_passant())
            {
                if(board.is_en_passant_targetable(final_file, final_rank))
                {
                    final_rank += (board.whose_turn() == WHITE ? -1 : 1);
                }
                else
                {
                    continue;
                }
            }

            square_score[Board::board_index(final_file, final_rank)] = score_to_add;
        }

        score_to_add = legal_bonus; // now on legal move list
    }

    double score = 0;
    for(size_t i = 0; i < square_score.size(); ++i)
    {
        auto king_bonus = king_target_factor/(1 + distance_to_king[i]);
        score += square_score[i]*(1 + king_bonus);
    }

    // normalizing to make maximum score near 1
    return score/64.0;
}

void Sphere_of_Influence_Gene::gene_specific_mutation()
{
    if(Random::coin_flip())
    {
        legal_bonus += Random::random_normal(0.05);
    }
    else
    {
        king_target_factor += Random::random_normal(0.05);
    }
}
<commit_msg>Simplify en passant target adjustment<commit_after>#include "Genes/Sphere_of_Influence_Gene.h"

#include <algorithm>
#include <array>
#include <memory>

#include "Genes/Gene.h"
#include "Game/Board.h"
#include "Game/Square.h"
#include "Moves/Move.h"

#include "Utility.h"

Sphere_of_Influence_Gene::Sphere_of_Influence_Gene() :
    legal_bonus(1.0),
    king_target_factor(0.0)
{
}

void Sphere_of_Influence_Gene::reset_properties() const
{
    Gene::reset_properties();
    properties["Legal Bonus"] = legal_bonus;
    properties["King Target Factor"] = king_target_factor;
}

void Sphere_of_Influence_Gene::load_properties()
{
    Gene::load_properties();
    legal_bonus = properties["Legal Bonus"];
    king_target_factor = properties["King Target Factor"];
}

std::unique_ptr<Gene> Sphere_of_Influence_Gene::duplicate() const
{
    return std::make_unique<Sphere_of_Influence_Gene>(*this);
}

std::string Sphere_of_Influence_Gene::name() const
{
    return "Sphere of Influence Gene";
}

// Count all squares potentially attacked by all pieces with bonus points if
// the attacking move is legal.
double Sphere_of_Influence_Gene::score_board(const Board& board) const
{
    std::array<double, 64> square_score{};
    std::array<size_t, 64> distance_to_king{};
    auto opponent_king_square = board.find_king(opposite(board.whose_turn()));
    for(char file = 'a'; file <= 'h'; ++file)
    {
        for(int rank = 1; rank <= 8; ++rank)
        {
            distance_to_king[Board::board_index(file, rank)] =
                king_distance({file, rank}, opponent_king_square);
        }
    }

    double score_to_add = 1.0;
    for(const auto& move_list : {board.other_moves(), board.legal_moves()})
    {
        for(const auto& move : move_list)
        {
            // Only potentially capturing moves are counted
            if( ! move->can_capture())
            {
                continue;
            }

            char final_file = move->end_file();
            int  final_rank = move->end_rank();

            if(move->is_en_passant())
            {
                if(board.is_en_passant_targetable(final_file, final_rank))
                {
                    final_rank -= move->rank_change();
                }
                else
                {
                    continue;
                }
            }

            square_score[Board::board_index(final_file, final_rank)] = score_to_add;
        }

        score_to_add = legal_bonus; // now on legal move list
    }

    double score = 0;
    for(size_t i = 0; i < square_score.size(); ++i)
    {
        auto king_bonus = king_target_factor/(1 + distance_to_king[i]);
        score += square_score[i]*(1 + king_bonus);
    }

    // normalizing to make maximum score near 1
    return score/64.0;
}

void Sphere_of_Influence_Gene::gene_specific_mutation()
{
    if(Random::coin_flip())
    {
        legal_bonus += Random::random_normal(0.05);
    }
    else
    {
        king_target_factor += Random::random_normal(0.05);
    }
}
<|endoftext|>


<commit_before>#include "About.h"

#include "../resource.h"
#include "../Updater/Updater.h"
#include "../Updater/Version.h"

void About::Initialize() {
    INIT_CONTROL(LBL_TITLE, Label, _title);

    std::wstring version = Updater::MainAppVersionString();
    _title.Text(L"3RVX " + version);
}

void About::LoadSettings() {

}

void About::SaveSettings() {

}
<commit_msg>Use new version ToString method<commit_after>#include "About.h"

#include "../resource.h"
#include "../Updater/Updater.h"
#include "../Updater/Version.h"

void About::Initialize() {
    INIT_CONTROL(LBL_TITLE, Label, _title);

    std::wstring version = Updater::MainAppVersion().ToString();
    _title.Text(L"3RVX " + version);
}

void About::LoadSettings() {

}

void About::SaveSettings() {

}
<|endoftext|>


<commit_before>#include "perf_precomp.hpp"

using namespace std;
using namespace testing;

namespace {

///////////////////////////////////////////////////////////////
// HOG

DEF_PARAM_TEST_1(Image, string);

PERF_TEST_P(Image, ObjDetect_HOG, Values<string>("gpu/hog/road.png"))
{
    cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    std::vector<cv::Rect> found_locations;

    if (PERF_RUN_GPU())
    {
        cv::gpu::GpuMat d_img(img);

        cv::gpu::HOGDescriptor d_hog;
        d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        d_hog.detectMultiScale(d_img, found_locations);

        TEST_CYCLE()
        {
            d_hog.detectMultiScale(d_img, found_locations);
        }
    }
    else
    {
        cv::HOGDescriptor hog;
        hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        hog.detectMultiScale(img, found_locations);

        TEST_CYCLE()
        {
            hog.detectMultiScale(img, found_locations);
        }
    }

    SANITY_CHECK(found_locations);
}

//===========test for CalTech data =============//
DEF_PARAM_TEST_1(HOG, string);

PERF_TEST_P(HOG, CalTech, Values<string>("gpu/caltech/image_00000009_0.png", "gpu/caltech/image_00000032_0.png",
    "gpu/caltech/image_00000165_0.png", "gpu/caltech/image_00000261_0.png", "gpu/caltech/image_00000469_0.png",
    "gpu/caltech/image_00000527_0.png", "gpu/caltech/image_00000574_0.png"))
{
    cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    std::vector<cv::Rect> found_locations;

    if (PERF_RUN_GPU())
    {
        cv::gpu::GpuMat d_img(img);

        cv::gpu::HOGDescriptor d_hog;
        d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        d_hog.detectMultiScale(d_img, found_locations);

        TEST_CYCLE()
        {
            d_hog.detectMultiScale(d_img, found_locations);
        }
    }
    else
    {
        cv::HOGDescriptor hog;
        hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        hog.detectMultiScale(img, found_locations);

        TEST_CYCLE()
        {
            hog.detectMultiScale(img, found_locations);
        }
    }

    SANITY_CHECK(found_locations);
}

///////////////////////////////////////////////////////////////
// HaarClassifier

typedef pair<string, string> pair_string;
DEF_PARAM_TEST_1(ImageAndCascade, pair_string);

PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier,
    Values<pair_string>(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/perf/haarcascade_frontalface_alt.xml")))
{
    cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    if (PERF_RUN_GPU())
    {
        cv::gpu::CascadeClassifier_GPU d_cascade;
        ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second)));

        cv::gpu::GpuMat d_img(img);
        cv::gpu::GpuMat d_objects_buffer;

        d_cascade.detectMultiScale(d_img, d_objects_buffer);

        TEST_CYCLE()
        {
            d_cascade.detectMultiScale(d_img, d_objects_buffer);
        }

        GPU_SANITY_CHECK(d_objects_buffer);
    }
    else
    {
        cv::CascadeClassifier cascade;
        ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/perf/haarcascade_frontalface_alt.xml")));

        std::vector<cv::Rect> rects;

        cascade.detectMultiScale(img, rects);

        TEST_CYCLE()
        {
            cascade.detectMultiScale(img, rects);
        }

        CPU_SANITY_CHECK(rects);
    }
}

///////////////////////////////////////////////////////////////
// LBP cascade

PERF_TEST_P(ImageAndCascade, ObjDetect_LBPClassifier,
    Values<pair_string>(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/lbpcascade/lbpcascade_frontalface.xml")))
{
    cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    if (PERF_RUN_GPU())
    {
        cv::gpu::CascadeClassifier_GPU d_cascade;
        ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second)));

        cv::gpu::GpuMat d_img(img);
        cv::gpu::GpuMat d_gpu_rects;

        d_cascade.detectMultiScale(d_img, d_gpu_rects);

        TEST_CYCLE()
        {
            d_cascade.detectMultiScale(d_img, d_gpu_rects);
        }

        GPU_SANITY_CHECK(d_gpu_rects);
    }
    else
    {
        cv::CascadeClassifier cascade;
        ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/lbpcascade/lbpcascade_frontalface.xml")));

        std::vector<cv::Rect> rects;

        cascade.detectMultiScale(img, rects);

        TEST_CYCLE()
        {
            cascade.detectMultiScale(img, rects);
        }

        CPU_SANITY_CHECK(rects);
    }
}

} // namespace
<commit_msg>add performance test for GPU soft cascade<commit_after>#include "perf_precomp.hpp"

using namespace std;
using namespace testing;

namespace {

///////////////////////////////////////////////////////////////
// HOG

DEF_PARAM_TEST_1(Image, string);

PERF_TEST_P(Image, ObjDetect_HOG, Values<string>("gpu/hog/road.png"))
{
    cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    std::vector<cv::Rect> found_locations;

    if (PERF_RUN_GPU())
    {
        cv::gpu::GpuMat d_img(img);

        cv::gpu::HOGDescriptor d_hog;
        d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        d_hog.detectMultiScale(d_img, found_locations);

        TEST_CYCLE()
        {
            d_hog.detectMultiScale(d_img, found_locations);
        }
    }
    else
    {
        cv::HOGDescriptor hog;
        hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        hog.detectMultiScale(img, found_locations);

        TEST_CYCLE()
        {
            hog.detectMultiScale(img, found_locations);
        }
    }

    SANITY_CHECK(found_locations);
}

//===========test for CalTech data =============//
DEF_PARAM_TEST_1(HOG, string);

PERF_TEST_P(HOG, CalTech, Values<string>("gpu/caltech/image_00000009_0.png", "gpu/caltech/image_00000032_0.png",
    "gpu/caltech/image_00000165_0.png", "gpu/caltech/image_00000261_0.png", "gpu/caltech/image_00000469_0.png",
    "gpu/caltech/image_00000527_0.png", "gpu/caltech/image_00000574_0.png"))
{
    cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    std::vector<cv::Rect> found_locations;

    if (PERF_RUN_GPU())
    {
        cv::gpu::GpuMat d_img(img);

        cv::gpu::HOGDescriptor d_hog;
        d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        d_hog.detectMultiScale(d_img, found_locations);

        TEST_CYCLE()
        {
            d_hog.detectMultiScale(d_img, found_locations);
        }
    }
    else
    {
        cv::HOGDescriptor hog;
        hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector());

        hog.detectMultiScale(img, found_locations);

        TEST_CYCLE()
        {
            hog.detectMultiScale(img, found_locations);
        }
    }

    SANITY_CHECK(found_locations);
}

typedef pair<string, string> pair_string;
DEF_PARAM_TEST_1(SoftCascade, pair_string);

PERF_TEST_P(SoftCascade, detect, Values<pair_string>(make_pair("cv/cascadeandhog/sc_cvpr_2012_to_opencv.xml",
                                                              "cv/cascadeandhog/bahnhof/image_00000000_0.png")))
{
    if (runOnGpu)
    {
        cv::Mat cpu = readImage(GetParam().second);
        ASSERT_FALSE(cpu.empty());
        cv::gpu::GpuMat colored(cpu);

        cv::gpu::SoftCascade cascade;
        ASSERT_TRUE(cascade.load(GetParam().first));

        cv::gpu::GpuMat rois, objectBoxes;
        cascade.detectMultiScale(colored, rois, objectBoxes);

        TEST_CYCLE()
        {
            cascade.detectMultiScale(colored, rois, objectBoxes);
        }
    } else
    {
        cv::Mat colored = readImage(GetParam().second);
        ASSERT_FALSE(colored.empty());

        cv::SoftCascade cascade;
        ASSERT_TRUE(cascade.load(GetParam().first));

        std::vector<cv::Rect> rois, objectBoxes;
        cascade.detectMultiScale(colored, rois, objectBoxes);

        TEST_CYCLE()
        {
            cascade.detectMultiScale(colored, rois, objectBoxes);
        }
    }
}

///////////////////////////////////////////////////////////////
// HaarClassifier

typedef pair<string, string> pair_string;
DEF_PARAM_TEST_1(ImageAndCascade, pair_string);

PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier,
    Values<pair_string>(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/perf/haarcascade_frontalface_alt.xml")))
{
    cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    if (PERF_RUN_GPU())
    {
        cv::gpu::CascadeClassifier_GPU d_cascade;
        ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second)));

        cv::gpu::GpuMat d_img(img);
        cv::gpu::GpuMat d_objects_buffer;

        d_cascade.detectMultiScale(d_img, d_objects_buffer);

        TEST_CYCLE()
        {
            d_cascade.detectMultiScale(d_img, d_objects_buffer);
        }

        GPU_SANITY_CHECK(d_objects_buffer);
    }
    else
    {
        cv::CascadeClassifier cascade;
        ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/perf/haarcascade_frontalface_alt.xml")));

        std::vector<cv::Rect> rects;

        cascade.detectMultiScale(img, rects);

        TEST_CYCLE()
        {
            cascade.detectMultiScale(img, rects);
        }

        CPU_SANITY_CHECK(rects);
    }
}

///////////////////////////////////////////////////////////////
// LBP cascade

PERF_TEST_P(ImageAndCascade, ObjDetect_LBPClassifier,
    Values<pair_string>(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/lbpcascade/lbpcascade_frontalface.xml")))
{
    cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE);
    ASSERT_FALSE(img.empty());

    if (PERF_RUN_GPU())
    {
        cv::gpu::CascadeClassifier_GPU d_cascade;
        ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second)));

        cv::gpu::GpuMat d_img(img);
        cv::gpu::GpuMat d_gpu_rects;

        d_cascade.detectMultiScale(d_img, d_gpu_rects);

        TEST_CYCLE()
        {
            d_cascade.detectMultiScale(d_img, d_gpu_rects);
        }

        GPU_SANITY_CHECK(d_gpu_rects);
    }
    else
    {
        cv::CascadeClassifier cascade;
        ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/lbpcascade/lbpcascade_frontalface.xml")));

        std::vector<cv::Rect> rects;

        cascade.detectMultiScale(img, rects);

        TEST_CYCLE()
        {
            cascade.detectMultiScale(img, rects);
        }

        CPU_SANITY_CHECK(rects);
    }
}

} // namespace
<|endoftext|>


<commit_before>/*
 * Vulkan
 *
 * Copyright (C) 2015 LunarG, Inc.
 *
 * 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.
 */
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <unordered_map>
#include "loader_platform.h"
#include "vk_dispatch_table_helper.h"
#include "vkLayer.h"
// The following is #included again to catch certain OS-specific functions
// being used:
#include "loader_platform.h"

#include "SPIRV/spirv.h"

static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;

static VkLayerDispatchTable * initLayerTable(const VkBaseLayerObject *gpuw)
{
    VkLayerDispatchTable *pTable;

    assert(gpuw);
    std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap.find((void *) gpuw->baseObject);
    if (it == tableMap.end())
    {
        pTable =  new VkLayerDispatchTable;
        tableMap[(void *) gpuw->baseObject] = pTable;
    } else
    {
        return it->second;
    }

    layer_initialize_dispatch_table(pTable, gpuw->pGPA, (VkPhysicalGpu) gpuw->nextObject);

    return pTable;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalGpu gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
{
    VkLayerDispatchTable* pTable = tableMap[gpu];
    VkResult result = pTable->CreateDevice(gpu, pCreateInfo, pDevice);
    // create a mapping for the device object into the dispatch table
    tableMap.emplace(*pDevice, pTable);
    return result;
}

VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
{
    if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
        return VK_ERROR_INVALID_POINTER;

    if (maxLayerCount < 1)
        return VK_ERROR_INITIALIZATION_FAILED;
    *pOutLayerCount = 1;
    strncpy((char *) pOutLayers[0], "ShaderChecker", maxStringSize);
    return VK_SUCCESS;
}

struct extProps {
    uint32_t version;
    const char * const name;
};
#define SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE 1
static const struct extProps shaderCheckerExts[SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
    // TODO what is the version?
    0x10, "ShaderChecker",
};

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
                                               VkExtensionInfoType infoType,
                                               uint32_t extensionIndex,
                                               size_t*  pDataSize,
                                               void*    pData)
{
    VkResult result;

    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
    VkExtensionProperties *ext_props;
    uint32_t *count;

    if (pDataSize == NULL)
        return VK_ERROR_INVALID_POINTER;

    switch (infoType) {
        case VK_EXTENSION_INFO_TYPE_COUNT:
            *pDataSize = sizeof(uint32_t);
            if (pData == NULL)
                return VK_SUCCESS;
            count = (uint32_t *) pData;
            *count = SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE;
            break;
        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
            *pDataSize = sizeof(VkExtensionProperties);
            if (pData == NULL)
                return VK_SUCCESS;
            if (extensionIndex >= SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE)
                return VK_ERROR_INVALID_VALUE;
            ext_props = (VkExtensionProperties *) pData;
            ext_props->version = shaderCheckerExts[extensionIndex].version;
            strncpy(ext_props->extName, shaderCheckerExts[extensionIndex].name,
                                        VK_MAX_EXTENSION_NAME);
            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
            break;
        default:
            return VK_ERROR_INVALID_VALUE;
    };

    return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(VkDevice device, const VkShaderCreateInfo *pCreateInfo,
                                                   VkShader *pShader)
{
    VkLayerDispatchTable* pTable = tableMap[(VkBaseLayerObject *)device];
    VkResult res = pTable->CreateShader(device, pCreateInfo, pShader);
    return res;
}

VK_LAYER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char* pName)
{
    if (gpu == NULL)
        return NULL;

    initLayerTable((const VkBaseLayerObject *) gpu);

#define ADD_HOOK(fn)    \
    if (!strncmp(#fn, pName, sizeof(#fn))) \
        return (void *) fn

    ADD_HOOK(vkGetProcAddr);
    ADD_HOOK(vkEnumerateLayers);
    ADD_HOOK(vkCreateDevice);
    ADD_HOOK(vkCreateShader);

    VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
    if (gpuw->pGPA == NULL)
        return NULL;
    return gpuw->pGPA((VkPhysicalGpu) gpuw->nextObject, pName);
}
<commit_msg>shader_checker: capture spir-v for every shader at vkCreateShader time<commit_after>/*
 * Vulkan
 *
 * Copyright (C) 2015 LunarG, Inc.
 *
 * 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.
 */
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <unordered_map>
#include <vector>
#include "loader_platform.h"
#include "vk_dispatch_table_helper.h"
#include "vkLayer.h"
// The following is #included again to catch certain OS-specific functions
// being used:
#include "loader_platform.h"

#include "SPIRV/spirv.h"

static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;

struct shader_source {
    std::vector<uint32_t> words;

    shader_source(VkShaderCreateInfo const *pCreateInfo) :
        words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)) {
    }
};

static std::unordered_map<void *, shader_source *> shader_map;

static VkLayerDispatchTable * initLayerTable(const VkBaseLayerObject *gpuw)
{
    VkLayerDispatchTable *pTable;

    assert(gpuw);
    std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap.find((void *) gpuw->baseObject);
    if (it == tableMap.end())
    {
        pTable =  new VkLayerDispatchTable;
        tableMap[(void *) gpuw->baseObject] = pTable;
    } else
    {
        return it->second;
    }

    layer_initialize_dispatch_table(pTable, gpuw->pGPA, (VkPhysicalGpu) gpuw->nextObject);

    return pTable;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalGpu gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
{
    VkLayerDispatchTable* pTable = tableMap[gpu];
    VkResult result = pTable->CreateDevice(gpu, pCreateInfo, pDevice);
    // create a mapping for the device object into the dispatch table
    tableMap.emplace(*pDevice, pTable);
    return result;
}

VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
{
    if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
        return VK_ERROR_INVALID_POINTER;

    if (maxLayerCount < 1)
        return VK_ERROR_INITIALIZATION_FAILED;
    *pOutLayerCount = 1;
    strncpy((char *) pOutLayers[0], "ShaderChecker", maxStringSize);
    return VK_SUCCESS;
}

struct extProps {
    uint32_t version;
    const char * const name;
};
#define SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE 1
static const struct extProps shaderCheckerExts[SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
    // TODO what is the version?
    0x10, "ShaderChecker",
};

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
                                               VkExtensionInfoType infoType,
                                               uint32_t extensionIndex,
                                               size_t*  pDataSize,
                                               void*    pData)
{
    VkResult result;

    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
    VkExtensionProperties *ext_props;
    uint32_t *count;

    if (pDataSize == NULL)
        return VK_ERROR_INVALID_POINTER;

    switch (infoType) {
        case VK_EXTENSION_INFO_TYPE_COUNT:
            *pDataSize = sizeof(uint32_t);
            if (pData == NULL)
                return VK_SUCCESS;
            count = (uint32_t *) pData;
            *count = SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE;
            break;
        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
            *pDataSize = sizeof(VkExtensionProperties);
            if (pData == NULL)
                return VK_SUCCESS;
            if (extensionIndex >= SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE)
                return VK_ERROR_INVALID_VALUE;
            ext_props = (VkExtensionProperties *) pData;
            ext_props->version = shaderCheckerExts[extensionIndex].version;
            strncpy(ext_props->extName, shaderCheckerExts[extensionIndex].name,
                                        VK_MAX_EXTENSION_NAME);
            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
            break;
        default:
            return VK_ERROR_INVALID_VALUE;
    };

    return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(VkDevice device, const VkShaderCreateInfo *pCreateInfo,
                                                   VkShader *pShader)
{
    VkLayerDispatchTable* pTable = tableMap[(VkBaseLayerObject *)device];
    VkResult res = pTable->CreateShader(device, pCreateInfo, pShader);

    shader_map[(VkBaseLayerObject *) *pShader] = new shader_source(pCreateInfo);
    return res;
}

VK_LAYER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char* pName)
{
    if (gpu == NULL)
        return NULL;

    initLayerTable((const VkBaseLayerObject *) gpu);

#define ADD_HOOK(fn)    \
    if (!strncmp(#fn, pName, sizeof(#fn))) \
        return (void *) fn

    ADD_HOOK(vkGetProcAddr);
    ADD_HOOK(vkEnumerateLayers);
    ADD_HOOK(vkCreateDevice);
    ADD_HOOK(vkCreateShader);

    VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
    if (gpuw->pGPA == NULL)
        return NULL;
    return gpuw->pGPA((VkPhysicalGpu) gpuw->nextObject, pName);
}
<|endoftext|>


<commit_before>/*
The Jinx library is distributed under the MIT License (MIT)
https://opensource.org/licenses/MIT
See LICENSE.TXT or Jinx.h for license details.
Copyright (c) 2016 James Boer
*/

#include "JxInternal.h"

namespace Jinx::Impl
{

	struct ConvTable
	{
		static inline uint8_t valueTypeToByte[] =
		{
			0,  // Null,
			1,  // Number,
			2,  // Integer,
			3,  // Boolean,
			4,  // String,
			5,  // Collection,
			6,  // CollectionItr,
			7,  // UserData,
			8,  // Buffer,
			9,  // Guid,
			10, // ValType,
			11, // Any
		};

		static_assert(countof(valueTypeToByte) == (static_cast<size_t>(ValueType::NumValueTypes) + 1), "ValueType names don't match enum count");

		static inline ValueType byteToValueType[] =
		{
			ValueType::Null,
			ValueType::Number,
			ValueType::Integer,
			ValueType::Boolean,
			ValueType::String,
			ValueType::Collection,
			ValueType::CollectionItr,
			ValueType::UserObject,
			ValueType::Buffer,
			ValueType::Guid,
			ValueType::ValType,
			ValueType::Any,
		};

		static_assert(countof(byteToValueType) == (static_cast<size_t>(ValueType::NumValueTypes) + 1), "ValueType names don't match enum count");
	};

	inline_t ValueType ByteToValueType(uint8_t byte)
	{
		assert(byte <= static_cast<size_t>(ValueType::NumValueTypes));
		return ConvTable::byteToValueType[byte];
	}

	inline_t uint8_t ValueTypeToByte(ValueType type)
	{
		assert(static_cast<size_t>(type) <= static_cast<size_t>(ValueType::NumValueTypes));
		return ConvTable::valueTypeToByte[static_cast<size_t>(type)];
	}

	inline_t bool StringToBoolean(const String & inValue, bool * outValue)
	{
		assert(outValue);
		if (strcmp(inValue.c_str(), "true") == 0)
		{
			*outValue = true;
			return true;
		}
		else if (strcmp(inValue.c_str(), "false") == 0)
		{
			*outValue = false;
			return true;
		}
		return false;
	}

	inline_t bool StringToNumber(const String & value, double * outValue, NumericFormat format)
	{
		assert(outValue);
#ifdef JINX_USE_FROM_CHARS
		// In case contintental format is used, replace commas with decimal point
		if (format == NumericFormat::Continental)
		{
			String s = value;
			std::replace(s.begin(), s.end(), ',', '.');
			auto result = std::from_chars(s.data(), s.data() + s.size(), *outValue);
			if (result.ptr == s.data() + s.size())
				return true;
		}
		else
		{
			auto result = std::from_chars(value.data(), value.data() + value.size(), *outValue);
			if (result.ptr == value.data() + value.size())
				return true;
		}
		return false;
#else
		// In case contintental format is used, replace commas with decimal point
		if (format == NumericFormat::Continental)
		{
			std::istringstream istr(value.c_str());
			// We arbitrarily pick German locale since it is known to use commas
			// as numeric decimal points.
			istr.imbue(std::locale("de_DE.UTF-8"));
			istr >> *outValue;
			if (istr.fail())
				return false;
		}
		else
		{
			std::istringstream istr(value.c_str());
			istr.imbue(std::locale::classic());
			istr >> *outValue;
			if (istr.fail())
				return false;
		}
		return true;
#endif
	}

	inline_t bool StringToInteger(const String & value, int64_t * outValue)
	{
		assert(outValue);
#ifdef JINX_USE_FROM_CHARS
		auto result = std::from_chars(value.data(), value.data() + value.size(), *outValue);
		if (result.ptr == value.data() + value.size())
			return true;
		return false;
#else
		char * endPtr;
		*outValue = strtoll(value.data(), &endPtr, 10);
		if (endPtr != (value.data() + value.size()))
			return false;
		return true;
#endif
	}

	inline_t bool StringToValueType(const String & value, ValueType * outValue)
	{
		if (value == "null")
		{
			*outValue = ValueType::Null;
			return true;
		}
		else if (value == "number")
		{
			*outValue = ValueType::Number;
			return true;
		}
		else if (value == "integer")
		{
			*outValue = ValueType::Integer;
			return true;
		}
		else if (value == "boolean")
		{
			*outValue = ValueType::Boolean;
			return true;
		}
		else if (value == "string")
		{
			*outValue = ValueType::String;
			return true;
		}
		else if (value == "collection")
		{
			*outValue = ValueType::Collection;
			return true;
		}
		else if (value == "collectionitr")
		{
			*outValue = ValueType::CollectionItr;
			return true;
		}
		else if (value == "buffer")
		{
			*outValue = ValueType::Buffer;
			return true;
		}
		else if (value == "guid")
		{
			*outValue = ValueType::Guid;
			return true;
		}
		else if (value == "valtype")
		{
			*outValue = ValueType::ValType;
			return true;
		}
		return false;
	}

	inline_t bool StringToGuid(const String & value, Guid * outValue)
	{
		assert(outValue);
		Guid guid;
		unsigned long p0;
		unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
#ifdef JINX_WINDOWS
		int err = sscanf_s(value.c_str(), "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
			&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
#else
		int err = sscanf(value.c_str(), "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
			&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
#endif
		if (err != 11)
			return false;
		guid.data1 = static_cast<uint32_t>(p0);
		guid.data2 = static_cast<uint16_t>(p1);
		guid.data3 = static_cast<uint16_t>(p2);
		guid.data4[0] = static_cast<uint8_t>(p3);
		guid.data4[1] = static_cast<uint8_t>(p4);
		guid.data4[2] = static_cast<uint8_t>(p5);
		guid.data4[3] = static_cast<uint8_t>(p6);
		guid.data4[4] = static_cast<uint8_t>(p7);
		guid.data4[5] = static_cast<uint8_t>(p8);
		guid.data4[6] = static_cast<uint8_t>(p9);
		guid.data4[7] = static_cast<uint8_t>(p10);
		*outValue = guid;
		return true;
	}

	inline_t bool GetDelimiterAndFormat(const String & value, char & delimiter, NumericFormat & format)
	{
		size_t tabCount = 0;
		size_t commaCount = 0;
		size_t semicolonCount = 0;
		for (size_t i = 0; i < value.size(); ++i)
		{
			char c = value[i];
			if (c == '\t')
				++tabCount;
			else if (c == ',')
				++commaCount;
			else if (c == ';')
				++semicolonCount;
			else if (c == '\n' && i != 0)
				break;
		}
		if (tabCount == 0 && commaCount == 0 && semicolonCount == 0)
			return false;
		delimiter = (commaCount >= tabCount) ? ((commaCount > semicolonCount) ? ',' : ';') : '\t';
		format = delimiter == ';' ? NumericFormat::Continental : NumericFormat::International;
		return true;
	}

	inline bool IsLineEnd(const char current)
	{
		return current == '\n' || current == '\r';
	}

	inline_t void ParseWhitespace(const char ** current, const char * end)
	{
		while (**current != *end)
		{
			char c = **current;
			if (c != '\t' && c != ' ' && c != '\r' && c != '\n')
				break;
			++(*current);
		}
	}

	inline_t Variant ParseValue(const String & value, NumericFormat format)
	{
		Guid guid;
		if (StringToGuid(value, &guid))
			return guid;
		int64_t integer;
		if (StringToInteger(value, &integer))
			return integer;
		double number;
		if (StringToNumber(value, &number, format))
			return number;
		bool boolean;
		if (StringToBoolean(value, &boolean))
			return boolean;
		return value;
	}

	inline_t String ParseCell(char delimiter, const char ** current, const char * end)
	{
		if (*current == end)
			return String();
		bool isQuoted = false;
		if (**current == '"')
		{
			isQuoted = true;
			++(*current);
		}
		String value;
		while (*current != end)
		{
			const char c = **current;
			if (isQuoted)
			{
				// Since this cell is double-quote delimited, proceed without checking delimiters until
				// we see another double quote character.
				if (c == '"')
				{
					// Advance the iterator and check to see if it's followed by the end of file or
					// delimiters.  If so, we're done parsing.  If not, a second double-quote should
					// follow.
					++(*current);
					if (*current == end || **current == delimiter || IsLineEnd(**current))
						break;
					// If this assert hits, your data is malformed, since an interior double-quote was not
					// followed by a second quote
					assert(**current == '"');
				}
			}
			else
			{
				// This isn't a quote-escaped cell, so check for normal delimiters
				if (c == delimiter || IsLineEnd(c))
					break;
			}
			value += c;
			++(*current);
		}
		return value;
	}

	inline_t std::vector<Variant, Jinx::Allocator<Variant>> ParseRow(char delimiter, NumericFormat format, const char ** current, const char * end)
	{
		std::vector<Variant, Jinx::Allocator<Variant>> variants;

		while (*current != end)
		{
			auto str = ParseCell(delimiter, current, end);
			auto val = ParseValue(str, format);
			variants.push_back(val);
			if (*current != end)
			{
				if (**current == delimiter)
				{
					++(*current);
				}
				else if (IsLineEnd(**current))
				{
					if (*current != end)
					{
						const char nc = *((*current) + 1);
						if (IsLineEnd(nc))
							++(*current);
					}
					++(*current);
					break;
				}
			}
		}

		return variants;
	}

	inline_t bool StringToCollection(const String & value, CollectionPtr * outValue)
	{

		// First check what type of delimiter is used, tabs or semicolons
		char delimiter;
		NumericFormat format;
		if (!GetDelimiterAndFormat(value, delimiter, format))
			return false;

		// Parse first row, which we'll uses as index values into each subsequent row
		const char * current = value.data();
		const char * end = current + value.size();
		ParseWhitespace(&current, end);
		auto header = ParseRow(delimiter, format, &current, end);
		if (header.empty())
			return false;

		*outValue = CreateCollection();
		CollectionPtr coll = *outValue;

		// Parse and create a collection for each row, and assign column ids from header
		while (true)
		{
			const auto & row = ParseRow(delimiter, format, &current, end);
			if (row.empty())
				break;
			if (row.size() != header.size())
			{
				*outValue = nullptr;
				return false;
			}
			const auto & rowName = row[0];
			auto rowColl = CreateCollection();
			coll->insert({rowName, rowColl });
			for (size_t i = 0; i < row.size(); ++i)
			{
				const auto & headerName = header[i];
				const auto & rowVal = row[i];
				rowColl->insert({ headerName, rowVal });
			}
		}

		return true;
	}

	inline_t String GuidToString(const Guid & value)
	{
		char buffer[64];
		snprintf(
			buffer,
			countof(buffer),
			"%.*X-%.*X-%.*X-%.*X%.*X-%.*X%.*X%.*X%.*X%.*X%.*X",
			8, value.data1,
			4, value.data2,
			4, value.data3,
			2, value.data4[0],
			2, value.data4[1],
			2, value.data4[2],
			2, value.data4[3],
			2, value.data4[4],
			2, value.data4[5],
			2, value.data4[6],
			2, value.data4[7]
		);
		return String(buffer);
	}

} // namespace Jinx::Impl

<commit_msg>Fix Linux runtime error based on locale<commit_after>/*
The Jinx library is distributed under the MIT License (MIT)
https://opensource.org/licenses/MIT
See LICENSE.TXT or Jinx.h for license details.
Copyright (c) 2016 James Boer
*/

#include "JxInternal.h"

namespace Jinx::Impl
{

	struct ConvTable
	{
		static inline uint8_t valueTypeToByte[] =
		{
			0,  // Null,
			1,  // Number,
			2,  // Integer,
			3,  // Boolean,
			4,  // String,
			5,  // Collection,
			6,  // CollectionItr,
			7,  // UserData,
			8,  // Buffer,
			9,  // Guid,
			10, // ValType,
			11, // Any
		};

		static_assert(countof(valueTypeToByte) == (static_cast<size_t>(ValueType::NumValueTypes) + 1), "ValueType names don't match enum count");

		static inline ValueType byteToValueType[] =
		{
			ValueType::Null,
			ValueType::Number,
			ValueType::Integer,
			ValueType::Boolean,
			ValueType::String,
			ValueType::Collection,
			ValueType::CollectionItr,
			ValueType::UserObject,
			ValueType::Buffer,
			ValueType::Guid,
			ValueType::ValType,
			ValueType::Any,
		};

		static_assert(countof(byteToValueType) == (static_cast<size_t>(ValueType::NumValueTypes) + 1), "ValueType names don't match enum count");
	};

	inline_t ValueType ByteToValueType(uint8_t byte)
	{
		assert(byte <= static_cast<size_t>(ValueType::NumValueTypes));
		return ConvTable::byteToValueType[byte];
	}

	inline_t uint8_t ValueTypeToByte(ValueType type)
	{
		assert(static_cast<size_t>(type) <= static_cast<size_t>(ValueType::NumValueTypes));
		return ConvTable::valueTypeToByte[static_cast<size_t>(type)];
	}

	inline_t bool StringToBoolean(const String & inValue, bool * outValue)
	{
		assert(outValue);
		if (strcmp(inValue.c_str(), "true") == 0)
		{
			*outValue = true;
			return true;
		}
		else if (strcmp(inValue.c_str(), "false") == 0)
		{
			*outValue = false;
			return true;
		}
		return false;
	}

	inline_t bool StringToNumber(const String & value, double * outValue, NumericFormat format)
	{
		assert(outValue);
#ifdef JINX_USE_FROM_CHARS
		// In case contintental format is used, replace commas with decimal point
		if (format == NumericFormat::Continental)
		{
			String s = value;
			std::replace(s.begin(), s.end(), ',', '.');
			auto result = std::from_chars(s.data(), s.data() + s.size(), *outValue);
			if (result.ptr == s.data() + s.size())
				return true;
		}
		else
		{
			auto result = std::from_chars(value.data(), value.data() + value.size(), *outValue);
			if (result.ptr == value.data() + value.size())
				return true;
		}
		return false;
#else
		// In case contintental format is used, replace commas with decimal point
		if (format == NumericFormat::Continental)
		{
			String s = value;
			std::replace(s.begin(), s.end(), ',', '.');
			std::istringstream istr(s.c_str());
			istr.imbue(std::locale::classic());
			istr >> *outValue;
			if (istr.fail())
				return false;
		}
		else
		{
			std::istringstream istr(value.c_str());
			istr.imbue(std::locale::classic());
			istr >> *outValue;
			if (istr.fail())
				return false;
		}
		return true;
#endif
	}

	inline_t bool StringToInteger(const String & value, int64_t * outValue)
	{
		assert(outValue);
#ifdef JINX_USE_FROM_CHARS
		auto result = std::from_chars(value.data(), value.data() + value.size(), *outValue);
		if (result.ptr == value.data() + value.size())
			return true;
		return false;
#else
		char * endPtr;
		*outValue = strtoll(value.data(), &endPtr, 10);
		if (endPtr != (value.data() + value.size()))
			return false;
		return true;
#endif
	}

	inline_t bool StringToValueType(const String & value, ValueType * outValue)
	{
		if (value == "null")
		{
			*outValue = ValueType::Null;
			return true;
		}
		else if (value == "number")
		{
			*outValue = ValueType::Number;
			return true;
		}
		else if (value == "integer")
		{
			*outValue = ValueType::Integer;
			return true;
		}
		else if (value == "boolean")
		{
			*outValue = ValueType::Boolean;
			return true;
		}
		else if (value == "string")
		{
			*outValue = ValueType::String;
			return true;
		}
		else if (value == "collection")
		{
			*outValue = ValueType::Collection;
			return true;
		}
		else if (value == "collectionitr")
		{
			*outValue = ValueType::CollectionItr;
			return true;
		}
		else if (value == "buffer")
		{
			*outValue = ValueType::Buffer;
			return true;
		}
		else if (value == "guid")
		{
			*outValue = ValueType::Guid;
			return true;
		}
		else if (value == "valtype")
		{
			*outValue = ValueType::ValType;
			return true;
		}
		return false;
	}

	inline_t bool StringToGuid(const String & value, Guid * outValue)
	{
		assert(outValue);
		Guid guid;
		unsigned long p0;
		unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
#ifdef JINX_WINDOWS
		int err = sscanf_s(value.c_str(), "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
			&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
#else
		int err = sscanf(value.c_str(), "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
			&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
#endif
		if (err != 11)
			return false;
		guid.data1 = static_cast<uint32_t>(p0);
		guid.data2 = static_cast<uint16_t>(p1);
		guid.data3 = static_cast<uint16_t>(p2);
		guid.data4[0] = static_cast<uint8_t>(p3);
		guid.data4[1] = static_cast<uint8_t>(p4);
		guid.data4[2] = static_cast<uint8_t>(p5);
		guid.data4[3] = static_cast<uint8_t>(p6);
		guid.data4[4] = static_cast<uint8_t>(p7);
		guid.data4[5] = static_cast<uint8_t>(p8);
		guid.data4[6] = static_cast<uint8_t>(p9);
		guid.data4[7] = static_cast<uint8_t>(p10);
		*outValue = guid;
		return true;
	}

	inline_t bool GetDelimiterAndFormat(const String & value, char & delimiter, NumericFormat & format)
	{
		size_t tabCount = 0;
		size_t commaCount = 0;
		size_t semicolonCount = 0;
		for (size_t i = 0; i < value.size(); ++i)
		{
			char c = value[i];
			if (c == '\t')
				++tabCount;
			else if (c == ',')
				++commaCount;
			else if (c == ';')
				++semicolonCount;
			else if (c == '\n' && i != 0)
				break;
		}
		if (tabCount == 0 && commaCount == 0 && semicolonCount == 0)
			return false;
		delimiter = (commaCount >= tabCount) ? ((commaCount > semicolonCount) ? ',' : ';') : '\t';
		format = delimiter == ';' ? NumericFormat::Continental : NumericFormat::International;
		return true;
	}

	inline bool IsLineEnd(const char current)
	{
		return current == '\n' || current == '\r';
	}

	inline_t void ParseWhitespace(const char ** current, const char * end)
	{
		while (**current != *end)
		{
			char c = **current;
			if (c != '\t' && c != ' ' && c != '\r' && c != '\n')
				break;
			++(*current);
		}
	}

	inline_t Variant ParseValue(const String & value, NumericFormat format)
	{
		Guid guid;
		if (StringToGuid(value, &guid))
			return guid;
		int64_t integer;
		if (StringToInteger(value, &integer))
			return integer;
		double number;
		if (StringToNumber(value, &number, format))
			return number;
		bool boolean;
		if (StringToBoolean(value, &boolean))
			return boolean;
		return value;
	}

	inline_t String ParseCell(char delimiter, const char ** current, const char * end)
	{
		if (*current == end)
			return String();
		bool isQuoted = false;
		if (**current == '"')
		{
			isQuoted = true;
			++(*current);
		}
		String value;
		while (*current != end)
		{
			const char c = **current;
			if (isQuoted)
			{
				// Since this cell is double-quote delimited, proceed without checking delimiters until
				// we see another double quote character.
				if (c == '"')
				{
					// Advance the iterator and check to see if it's followed by the end of file or
					// delimiters.  If so, we're done parsing.  If not, a second double-quote should
					// follow.
					++(*current);
					if (*current == end || **current == delimiter || IsLineEnd(**current))
						break;
					// If this assert hits, your data is malformed, since an interior double-quote was not
					// followed by a second quote
					assert(**current == '"');
				}
			}
			else
			{
				// This isn't a quote-escaped cell, so check for normal delimiters
				if (c == delimiter || IsLineEnd(c))
					break;
			}
			value += c;
			++(*current);
		}
		return value;
	}

	inline_t std::vector<Variant, Jinx::Allocator<Variant>> ParseRow(char delimiter, NumericFormat format, const char ** current, const char * end)
	{
		std::vector<Variant, Jinx::Allocator<Variant>> variants;

		while (*current != end)
		{
			auto str = ParseCell(delimiter, current, end);
			auto val = ParseValue(str, format);
			variants.push_back(val);
			if (*current != end)
			{
				if (**current == delimiter)
				{
					++(*current);
				}
				else if (IsLineEnd(**current))
				{
					if (*current != end)
					{
						const char nc = *((*current) + 1);
						if (IsLineEnd(nc))
							++(*current);
					}
					++(*current);
					break;
				}
			}
		}

		return variants;
	}

	inline_t bool StringToCollection(const String & value, CollectionPtr * outValue)
	{

		// First check what type of delimiter is used, tabs or semicolons
		char delimiter;
		NumericFormat format;
		if (!GetDelimiterAndFormat(value, delimiter, format))
			return false;

		// Parse first row, which we'll uses as index values into each subsequent row
		const char * current = value.data();
		const char * end = current + value.size();
		ParseWhitespace(&current, end);
		auto header = ParseRow(delimiter, format, &current, end);
		if (header.empty())
			return false;

		*outValue = CreateCollection();
		CollectionPtr coll = *outValue;

		// Parse and create a collection for each row, and assign column ids from header
		while (true)
		{
			const auto & row = ParseRow(delimiter, format, &current, end);
			if (row.empty())
				break;
			if (row.size() != header.size())
			{
				*outValue = nullptr;
				return false;
			}
			const auto & rowName = row[0];
			auto rowColl = CreateCollection();
			coll->insert({rowName, rowColl });
			for (size_t i = 0; i < row.size(); ++i)
			{
				const auto & headerName = header[i];
				const auto & rowVal = row[i];
				rowColl->insert({ headerName, rowVal });
			}
		}

		return true;
	}

	inline_t String GuidToString(const Guid & value)
	{
		char buffer[64];
		snprintf(
			buffer,
			countof(buffer),
			"%.*X-%.*X-%.*X-%.*X%.*X-%.*X%.*X%.*X%.*X%.*X%.*X",
			8, value.data1,
			4, value.data2,
			4, value.data3,
			2, value.data4[0],
			2, value.data4[1],
			2, value.data4[2],
			2, value.data4[3],
			2, value.data4[4],
			2, value.data4[5],
			2, value.data4[6],
			2, value.data4[7]
		);
		return String(buffer);
	}

} // namespace Jinx::Impl

<|endoftext|>