<commit_before>/*
  Copyright (c) 2014, Intel Corporation
  All rights reserved.

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

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

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

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

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

#define DBG(x)
#include <omp.h>
#include <malloc.h>

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <algorithm>

// Signature of ispc-generated 'task' functions
typedef void (*TaskFuncType)(void *data, int threadIndex, int threadCount,
                             int taskIndex, int taskCount,
                             int taskIndex0, int taskIndex1, int taskIndex2,
                             int taskCount0, int taskCount1, int taskCount2);

// Small structure used to hold the data for each task
#ifdef _MSC_VER
__declspec(align(16))
#endif
struct TaskInfo {
    TaskFuncType func;
    void *data;
    int taskIndex;
    int taskCount3d[3];
#if defined(ISPC_IS_WINDOWS)
    event taskEvent;
#endif
    int taskCount() const { return taskCount3d[0]*taskCount3d[1]*taskCount3d[2]; }
    int taskIndex0() const
    {
      return taskIndex % taskCount3d[0];
    }
    int taskIndex1() const
    {
      return ( taskIndex / taskCount3d[0] ) % taskCount3d[1];
    }
    int taskIndex2() const
    {
      return taskIndex / ( taskCount3d[0]*taskCount3d[1] );
    }
    int taskCount0() const { return taskCount3d[0]; }
    int taskCount1() const { return taskCount3d[1]; }
    int taskCount2() const { return taskCount3d[2]; }
    TaskInfo() { assert(sizeof(TaskInfo) % 32 == 0); }
}
#ifndef _MSC_VER
__attribute__((aligned(32)));
#endif
;

// ispc expects these functions to have C linkage / not be mangled
extern "C" {
    void ISPCLaunch(void **handlePtr, void *f, void *data, int countx, int county, int countz);
    void *ISPCAlloc(void **handlePtr, int64_t size, int32_t alignment);
    void ISPCSync(void *handle);
}

///////////////////////////////////////////////////////////////////////////
// TaskGroupBase

#define LOG_TASK_QUEUE_CHUNK_SIZE 14
#define MAX_TASK_QUEUE_CHUNKS 8
#define TASK_QUEUE_CHUNK_SIZE (1<<LOG_TASK_QUEUE_CHUNK_SIZE)

#define MAX_LAUNCHED_TASKS (MAX_TASK_QUEUE_CHUNKS * TASK_QUEUE_CHUNK_SIZE)

#define NUM_MEM_BUFFERS 16

class TaskGroup;

/** The TaskGroupBase structure provides common functionality for "task
    groups"; a task group is the set of tasks launched from within a single
    ispc function.  When the function is ready to return, it waits for all
    of the tasks in its task group to finish before it actually returns.
 */
class TaskGroupBase {
public:
    void Reset();

    int AllocTaskInfo(int count);
    TaskInfo *GetTaskInfo(int index);

    void *AllocMemory(int64_t size, int32_t alignment);

protected:
    TaskGroupBase();
    ~TaskGroupBase();

    int nextTaskInfoIndex;

private:
    /* We allocate blocks of TASK_QUEUE_CHUNK_SIZE TaskInfo structures as
       needed by the calling function.  We hold up to MAX_TASK_QUEUE_CHUNKS
       of these (and then exit at runtime if more than this many tasks are
       launched.)
     */
    TaskInfo *taskInfo[MAX_TASK_QUEUE_CHUNKS];

    /* We also allocate chunks of memory to service ISPCAlloc() calls.  The
       memBuffers[] array holds pointers to this memory.  The first element
       of this array is initialized to point to mem and then any subsequent
       elements required are initialized with dynamic allocation.
     */
    int curMemBuffer, curMemBufferOffset;
    int memBufferSize[NUM_MEM_BUFFERS];
    char *memBuffers[NUM_MEM_BUFFERS];
    char mem[256];
};

inline TaskGroupBase::TaskGroupBase() {
    nextTaskInfoIndex = 0;

    curMemBuffer = 0;
    curMemBufferOffset = 0;
    memBuffers[0] = mem;
    memBufferSize[0] = sizeof(mem) / sizeof(mem[0]);
    for (int i = 1; i < NUM_MEM_BUFFERS; ++i) {
        memBuffers[i] = NULL;
        memBufferSize[i] = 0;
    }

    for (int i = 0; i < MAX_TASK_QUEUE_CHUNKS; ++i)
        taskInfo[i] = NULL;
}

inline TaskGroupBase::~TaskGroupBase() {
    // Note: don't delete memBuffers[0], since it points to the start of
    // the "mem" member!
    for (int i = 1; i < NUM_MEM_BUFFERS; ++i)
        delete[](memBuffers[i]);
}

inline void
TaskGroupBase::Reset() {
    nextTaskInfoIndex = 0;
    curMemBuffer = 0;
    curMemBufferOffset = 0;
}

inline int
TaskGroupBase::AllocTaskInfo(int count) {
    int ret = nextTaskInfoIndex;
    nextTaskInfoIndex += count;
    return ret;
}

inline TaskInfo *
TaskGroupBase::GetTaskInfo(int index) {
    int chunk = (index >> LOG_TASK_QUEUE_CHUNK_SIZE);
    int offset = index & (TASK_QUEUE_CHUNK_SIZE-1);

    if (chunk == MAX_TASK_QUEUE_CHUNKS) {
        fprintf(stderr, "A total of %d tasks have been launched from the "
                "current function--the simple built-in task system can handle "
                "no more. You can increase the values of TASK_QUEUE_CHUNK_SIZE "
                "and LOG_TASK_QUEUE_CHUNK_SIZE to work around this limitation.  "
                "Sorry!  Exiting.\n", index);
        exit(1);
    }

    if (taskInfo[chunk] == NULL)
        taskInfo[chunk] = new TaskInfo[TASK_QUEUE_CHUNK_SIZE];
    return &taskInfo[chunk][offset];
}

inline void *
TaskGroupBase::AllocMemory(int64_t size, int32_t alignment) {
    char *basePtr = memBuffers[curMemBuffer];
    intptr_t iptr = (intptr_t)(basePtr + curMemBufferOffset);
    iptr = (iptr + (alignment-1)) & ~(alignment-1);

    int newOffset = int(iptr - (intptr_t)basePtr + size);
    if (newOffset < memBufferSize[curMemBuffer]) {
        curMemBufferOffset = newOffset;
        return (char *)iptr;
    }

    ++curMemBuffer;
    curMemBufferOffset = 0;
    assert(curMemBuffer < NUM_MEM_BUFFERS);

    int allocSize = 1 << (12 + curMemBuffer);
    allocSize = std::max(int(size+alignment), allocSize);
    char *newBuf = new char[allocSize];
    memBufferSize[curMemBuffer] = allocSize;
    memBuffers[curMemBuffer] = newBuf;
    return AllocMemory(size, alignment);
}

///////////////////////////////////////////////////////////////////////////
// Atomics and the like

static inline void
lMemFence() {
    // Windows atomic functions already contain the fence
    // KNC doesn't need the memory barrier
#if !defined ISPC_IS_KNC && !defined ISPC_IS_WINDOWS
    __sync_synchronize();
#endif
}

static void *
lAtomicCompareAndSwapPointer(void **v, void *newValue, void *oldValue) {
#ifdef ISPC_IS_WINDOWS
    return InterlockedCompareExchangePointer(v, newValue, oldValue);
#else
    void *result = __sync_val_compare_and_swap(v, oldValue, newValue);
    lMemFence();
    return result;
#endif // ISPC_IS_WINDOWS
}

#if 0
static int32_t
lAtomicCompareAndSwap32(volatile int32_t *v, int32_t newValue, int32_t oldValue) {
#ifdef ISPC_IS_WINDOWS
    return InterlockedCompareExchange((volatile LONG *)v, newValue, oldValue);
#else
    int32_t result = __sync_val_compare_and_swap(v, oldValue, newValue);
    lMemFence();
    return result;
#endif // ISPC_IS_WINDOWS
}
#endif

static inline int32_t
lAtomicAdd(volatile int32_t *v, int32_t delta) {
#ifdef ISPC_IS_WINDOWS
    return InterlockedExchangeAdd((volatile LONG *)v, delta)+delta;
#else
    return __sync_fetch_and_add(v, delta);
#endif
}

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

class TaskGroup : public TaskGroupBase {
public:
    void Launch(int baseIndex, int count);
    void Sync();

};

///////////////////////////////////////////////////////////////////////////
// OpenMP

static void
InitTaskSystem() {
        // No initialization needed
}

inline void
TaskGroup::Launch(int baseIndex, int count) {
#pragma omp parallel
  {
    const int threadIndex = omp_get_thread_num();
    const int threadCount = omp_get_num_threads();

    TaskInfo ti = *GetTaskInfo(baseIndex);
#pragma omp for schedule(runtime)
    for(int i = 0; i < count; i++)
    {
        ti.taskIndex = i;

        // Actually run the task.
        ti.func(ti.data, threadIndex, threadCount, ti.taskIndex, ti.taskCount(),
            ti.taskIndex0(), ti.taskIndex1(), ti.taskIndex2(),
            ti.taskCount0(), ti.taskCount1(), ti.taskCount2());
    }
  }
}

inline void
TaskGroup::Sync() {
}

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

#define MAX_FREE_TASK_GROUPS 64
static TaskGroup *freeTaskGroups[MAX_FREE_TASK_GROUPS];

  static inline TaskGroup *
AllocTaskGroup()
{
  for (int i = 0; i < MAX_FREE_TASK_GROUPS; ++i) {
    TaskGroup *tg = freeTaskGroups[i];
    if (tg != NULL) {
      void *ptr = lAtomicCompareAndSwapPointer((void **)(&freeTaskGroups[i]), NULL, tg);
      if (ptr != NULL) {
        return (TaskGroup *)ptr;
      }
    }
  }

  return new TaskGroup;
}

  static inline void
FreeTaskGroup(TaskGroup *tg)
{
  tg->Reset();

  for (int i = 0; i < MAX_FREE_TASK_GROUPS; ++i) {
    if (freeTaskGroups[i] == NULL) {
      void *ptr = lAtomicCompareAndSwapPointer((void **)&freeTaskGroups[i], tg, NULL);
      if (ptr == NULL)
        return;
    }
  }

  delete tg;
}

  void
ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count0, int count1, int count2)
{
  const int count = count0*count1*count2;
  TaskGroup *taskGroup;
  if (*taskGroupPtr == NULL) {
    InitTaskSystem();
    taskGroup = AllocTaskGroup();
    *taskGroupPtr = taskGroup;
  }
  else
    taskGroup = (TaskGroup *)(*taskGroupPtr);

  int baseIndex = taskGroup->AllocTaskInfo(count);
  for (int i = 0; i < 1; ++i) {
    TaskInfo *ti = taskGroup->GetTaskInfo(baseIndex+i);
    ti->func = (TaskFuncType)func;
    ti->data = data;
    ti->taskIndex = i;
    ti->taskCount3d[0] = count0;
    ti->taskCount3d[1] = count1;
    ti->taskCount3d[2] = count2;
  }
  taskGroup->Launch(baseIndex, count);
}

  void
ISPCSync(void *h)
{
  TaskGroup *taskGroup = (TaskGroup *)h;
  if (taskGroup != NULL) {
    taskGroup->Sync();
    FreeTaskGroup(taskGroup);
  }
}

  void *
ISPCAlloc(void **taskGroupPtr, int64_t size, int32_t alignment)
{
  TaskGroup *taskGroup;
  if (*taskGroupPtr == NULL) {
    InitTaskSystem();
    taskGroup = AllocTaskGroup();
    *taskGroupPtr = taskGroup;
  }
  else
    taskGroup = (TaskGroup *)(*taskGroupPtr);

  return taskGroup->AllocMemory(size, alignment);
}

<commit_msg>fix OSX compilation<commit_after>/*
  Copyright (c) 2014, Intel Corporation
  All rights reserved.

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

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

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

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

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

#define DBG(x)
#include <omp.h>
//#include <malloc.h>

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <algorithm>

// Signature of ispc-generated 'task' functions
typedef void (*TaskFuncType)(void *data, int threadIndex, int threadCount,
                             int taskIndex, int taskCount,
                             int taskIndex0, int taskIndex1, int taskIndex2,
                             int taskCount0, int taskCount1, int taskCount2);

// Small structure used to hold the data for each task
#ifdef _MSC_VER
__declspec(align(16))
#endif
struct TaskInfo {
    TaskFuncType func;
    void *data;
    int taskIndex;
    int taskCount3d[3];
#if defined(ISPC_IS_WINDOWS)
    event taskEvent;
#endif
    int taskCount() const { return taskCount3d[0]*taskCount3d[1]*taskCount3d[2]; }
    int taskIndex0() const
    {
      return taskIndex % taskCount3d[0];
    }
    int taskIndex1() const
    {
      return ( taskIndex / taskCount3d[0] ) % taskCount3d[1];
    }
    int taskIndex2() const
    {
      return taskIndex / ( taskCount3d[0]*taskCount3d[1] );
    }
    int taskCount0() const { return taskCount3d[0]; }
    int taskCount1() const { return taskCount3d[1]; }
    int taskCount2() const { return taskCount3d[2]; }
    TaskInfo() { assert(sizeof(TaskInfo) % 32 == 0); }
}
#ifndef _MSC_VER
__attribute__((aligned(32)));
#endif
;

// ispc expects these functions to have C linkage / not be mangled
extern "C" {
    void ISPCLaunch(void **handlePtr, void *f, void *data, int countx, int county, int countz);
    void *ISPCAlloc(void **handlePtr, int64_t size, int32_t alignment);
    void ISPCSync(void *handle);
}

///////////////////////////////////////////////////////////////////////////
// TaskGroupBase

#define LOG_TASK_QUEUE_CHUNK_SIZE 14
#define MAX_TASK_QUEUE_CHUNKS 8
#define TASK_QUEUE_CHUNK_SIZE (1<<LOG_TASK_QUEUE_CHUNK_SIZE)

#define MAX_LAUNCHED_TASKS (MAX_TASK_QUEUE_CHUNKS * TASK_QUEUE_CHUNK_SIZE)

#define NUM_MEM_BUFFERS 16

class TaskGroup;

/** The TaskGroupBase structure provides common functionality for "task
    groups"; a task group is the set of tasks launched from within a single
    ispc function.  When the function is ready to return, it waits for all
    of the tasks in its task group to finish before it actually returns.
 */
class TaskGroupBase {
public:
    void Reset();

    int AllocTaskInfo(int count);
    TaskInfo *GetTaskInfo(int index);

    void *AllocMemory(int64_t size, int32_t alignment);

protected:
    TaskGroupBase();
    ~TaskGroupBase();

    int nextTaskInfoIndex;

private:
    /* We allocate blocks of TASK_QUEUE_CHUNK_SIZE TaskInfo structures as
       needed by the calling function.  We hold up to MAX_TASK_QUEUE_CHUNKS
       of these (and then exit at runtime if more than this many tasks are
       launched.)
     */
    TaskInfo *taskInfo[MAX_TASK_QUEUE_CHUNKS];

    /* We also allocate chunks of memory to service ISPCAlloc() calls.  The
       memBuffers[] array holds pointers to this memory.  The first element
       of this array is initialized to point to mem and then any subsequent
       elements required are initialized with dynamic allocation.
     */
    int curMemBuffer, curMemBufferOffset;
    int memBufferSize[NUM_MEM_BUFFERS];
    char *memBuffers[NUM_MEM_BUFFERS];
    char mem[256];
};

inline TaskGroupBase::TaskGroupBase() {
    nextTaskInfoIndex = 0;

    curMemBuffer = 0;
    curMemBufferOffset = 0;
    memBuffers[0] = mem;
    memBufferSize[0] = sizeof(mem) / sizeof(mem[0]);
    for (int i = 1; i < NUM_MEM_BUFFERS; ++i) {
        memBuffers[i] = NULL;
        memBufferSize[i] = 0;
    }

    for (int i = 0; i < MAX_TASK_QUEUE_CHUNKS; ++i)
        taskInfo[i] = NULL;
}

inline TaskGroupBase::~TaskGroupBase() {
    // Note: don't delete memBuffers[0], since it points to the start of
    // the "mem" member!
    for (int i = 1; i < NUM_MEM_BUFFERS; ++i)
        delete[](memBuffers[i]);
}

inline void
TaskGroupBase::Reset() {
    nextTaskInfoIndex = 0;
    curMemBuffer = 0;
    curMemBufferOffset = 0;
}

inline int
TaskGroupBase::AllocTaskInfo(int count) {
    int ret = nextTaskInfoIndex;
    nextTaskInfoIndex += count;
    return ret;
}

inline TaskInfo *
TaskGroupBase::GetTaskInfo(int index) {
    int chunk = (index >> LOG_TASK_QUEUE_CHUNK_SIZE);
    int offset = index & (TASK_QUEUE_CHUNK_SIZE-1);

    if (chunk == MAX_TASK_QUEUE_CHUNKS) {
        fprintf(stderr, "A total of %d tasks have been launched from the "
                "current function--the simple built-in task system can handle "
                "no more. You can increase the values of TASK_QUEUE_CHUNK_SIZE "
                "and LOG_TASK_QUEUE_CHUNK_SIZE to work around this limitation.  "
                "Sorry!  Exiting.\n", index);
        exit(1);
    }

    if (taskInfo[chunk] == NULL)
        taskInfo[chunk] = new TaskInfo[TASK_QUEUE_CHUNK_SIZE];
    return &taskInfo[chunk][offset];
}

inline void *
TaskGroupBase::AllocMemory(int64_t size, int32_t alignment) {
    char *basePtr = memBuffers[curMemBuffer];
    intptr_t iptr = (intptr_t)(basePtr + curMemBufferOffset);
    iptr = (iptr + (alignment-1)) & ~(alignment-1);

    int newOffset = int(iptr - (intptr_t)basePtr + size);
    if (newOffset < memBufferSize[curMemBuffer]) {
        curMemBufferOffset = newOffset;
        return (char *)iptr;
    }

    ++curMemBuffer;
    curMemBufferOffset = 0;
    assert(curMemBuffer < NUM_MEM_BUFFERS);

    int allocSize = 1 << (12 + curMemBuffer);
    allocSize = std::max(int(size+alignment), allocSize);
    char *newBuf = new char[allocSize];
    memBufferSize[curMemBuffer] = allocSize;
    memBuffers[curMemBuffer] = newBuf;
    return AllocMemory(size, alignment);
}

///////////////////////////////////////////////////////////////////////////
// Atomics and the like

static inline void
lMemFence() {
    // Windows atomic functions already contain the fence
    // KNC doesn't need the memory barrier
#if !defined ISPC_IS_KNC && !defined ISPC_IS_WINDOWS
    __sync_synchronize();
#endif
}

static void *
lAtomicCompareAndSwapPointer(void **v, void *newValue, void *oldValue) {
#ifdef ISPC_IS_WINDOWS
    return InterlockedCompareExchangePointer(v, newValue, oldValue);
#else
    void *result = __sync_val_compare_and_swap(v, oldValue, newValue);
    lMemFence();
    return result;
#endif // ISPC_IS_WINDOWS
}

#if 0
static int32_t
lAtomicCompareAndSwap32(volatile int32_t *v, int32_t newValue, int32_t oldValue) {
#ifdef ISPC_IS_WINDOWS
    return InterlockedCompareExchange((volatile LONG *)v, newValue, oldValue);
#else
    int32_t result = __sync_val_compare_and_swap(v, oldValue, newValue);
    lMemFence();
    return result;
#endif // ISPC_IS_WINDOWS
}
#endif

static inline int32_t
lAtomicAdd(volatile int32_t *v, int32_t delta) {
#ifdef ISPC_IS_WINDOWS
    return InterlockedExchangeAdd((volatile LONG *)v, delta)+delta;
#else
    return __sync_fetch_and_add(v, delta);
#endif
}

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

class TaskGroup : public TaskGroupBase {
public:
    void Launch(int baseIndex, int count);
    void Sync();

};

///////////////////////////////////////////////////////////////////////////
// OpenMP

static void
InitTaskSystem() {
        // No initialization needed
}

inline void
TaskGroup::Launch(int baseIndex, int count) {
#pragma omp parallel
  {
    const int threadIndex = omp_get_thread_num();
    const int threadCount = omp_get_num_threads();

    TaskInfo ti = *GetTaskInfo(baseIndex);
#pragma omp for schedule(runtime)
    for(int i = 0; i < count; i++)
    {
        ti.taskIndex = i;

        // Actually run the task.
        ti.func(ti.data, threadIndex, threadCount, ti.taskIndex, ti.taskCount(),
            ti.taskIndex0(), ti.taskIndex1(), ti.taskIndex2(),
            ti.taskCount0(), ti.taskCount1(), ti.taskCount2());
    }
  }
}

inline void
TaskGroup::Sync() {
}

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

#define MAX_FREE_TASK_GROUPS 64
static TaskGroup *freeTaskGroups[MAX_FREE_TASK_GROUPS];

  static inline TaskGroup *
AllocTaskGroup()
{
  for (int i = 0; i < MAX_FREE_TASK_GROUPS; ++i) {
    TaskGroup *tg = freeTaskGroups[i];
    if (tg != NULL) {
      void *ptr = lAtomicCompareAndSwapPointer((void **)(&freeTaskGroups[i]), NULL, tg);
      if (ptr != NULL) {
        return (TaskGroup *)ptr;
      }
    }
  }

  return new TaskGroup;
}

  static inline void
FreeTaskGroup(TaskGroup *tg)
{
  tg->Reset();

  for (int i = 0; i < MAX_FREE_TASK_GROUPS; ++i) {
    if (freeTaskGroups[i] == NULL) {
      void *ptr = lAtomicCompareAndSwapPointer((void **)&freeTaskGroups[i], tg, NULL);
      if (ptr == NULL)
        return;
    }
  }

  delete tg;
}

  void
ISPCLaunch(void **taskGroupPtr, void *func, void *data, int count0, int count1, int count2)
{
  const int count = count0*count1*count2;
  TaskGroup *taskGroup;
  if (*taskGroupPtr == NULL) {
    InitTaskSystem();
    taskGroup = AllocTaskGroup();
    *taskGroupPtr = taskGroup;
  }
  else
    taskGroup = (TaskGroup *)(*taskGroupPtr);

  int baseIndex = taskGroup->AllocTaskInfo(count);
  for (int i = 0; i < 1; ++i) {
    TaskInfo *ti = taskGroup->GetTaskInfo(baseIndex+i);
    ti->func = (TaskFuncType)func;
    ti->data = data;
    ti->taskIndex = i;
    ti->taskCount3d[0] = count0;
    ti->taskCount3d[1] = count1;
    ti->taskCount3d[2] = count2;
  }
  taskGroup->Launch(baseIndex, count);
}

  void
ISPCSync(void *h)
{
  TaskGroup *taskGroup = (TaskGroup *)h;
  if (taskGroup != NULL) {
    taskGroup->Sync();
    FreeTaskGroup(taskGroup);
  }
}

  void *
ISPCAlloc(void **taskGroupPtr, int64_t size, int32_t alignment)
{
  TaskGroup *taskGroup;
  if (*taskGroupPtr == NULL) {
    InitTaskSystem();
    taskGroup = AllocTaskGroup();
    *taskGroupPtr = taskGroup;
  }
  else
    taskGroup = (TaskGroup *)(*taskGroupPtr);

  return taskGroup->AllocMemory(size, alignment);
}

<|endoftext|>


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

#include "ssbase_type.h"

void InitLinkList(LinkList* pList)
{
	pList->pHead = NULL;
	pList->pTail = NULL;
}

void FreeLinkList(LinkList* pList)
{
	if (!pList)
		return;

	if (pList->iNodeCount)
	{
		LinkListNode* pCurrentNode;
		LinkListNode* pNextNode;

		pCurrentNode = pList->pHead;

		while (TRUE)
		{
			pNextNode = pCurrentNode->pNext;

			//free the data of current node
			if (pCurrentNode->pData)
				free(pCurrentNode->pData);

			//free the current node
			if (pCurrentNode)
				free(pCurrentNode);

			//if pNextNode is NULL, then the list is at the end. If not, set it to currnet node
			if (pNextNode)
				pCurrentNode = pNextNode;
			else
				break;
		}
	}
}

int  AddNode(LinkList* pList, void* pData)
{
	LinkListNode* pNewNode = (LinkListNode*)malloc(sizeof(LinkListNode));

	pNewNode->pData = pData;
	pNewNode->pNext = NULL;

	if (!pList->iNodeCount)
	{
		pList->pHead = pNewNode;
		pList->pTail = pNewNode;
	}
	else
	{
		pList->pTail->pNext = pNewNode;
		pList->pTail        = pNewNode;
	}
	pList->iNodeCount++;

	//return NewNode's index
	return pList->iNodeCount - 1;
}

int  AddString(LinkList* pList, char* str)
{
	LinkListNode* pNode = pList->pHead;
	for (int i = 0; i < pList->iNodeCount; i++)
	{
		if (strcmp((char*)pNode->pData, str) == 0)
			return i;
		pNode = pNode->pNext;
	}
	char* newStr =(char*) malloc(strlen(str) + 1);
	strcpy(newStr, str);

	return AddNode(pList, newStr);
}

<commit_msg>doxygen comment<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "ssbase_type.h"
#include "sstype.h"

/*
 * @author  Yang Kaidi
 * @version 1.0
 * @date    2015-02-16
 * @{
 */

extern LinkList g_FunctionTable;
extern LinkList g_StringTable;
extern LinkList g_LabelTable;
extern LinkList g_SymbolTable;

/*
 * @defgroup
 * @{
 */

/*
 *  Add string into linklist
 *  @param [out] pList the linklist which will be inserted into
 *  @param [in] str a string to be inserted
 *  @return if str has bean already in the linklist, return the index of the string in the list.
 *  Otherwise, insert the string and return the new index;
 */
int AddString(LinkList* pList, char* str)
{
	//Look through the linklist to find whether the string has been already in the list.
	LinkListNode* pNode = pList->pHead;
	for (int i = 0; i < pList->iNodeCount; i++)
	{
		if (strcmp((char*)pNode->pData, str) == 0)
			return i;
		pNode = pNode->pNext;
	}
	//Not in the list, so allocate space and add string into the list.
	char* newStr =(char*) malloc(strlen(str) + 1);
	strcpy(newStr, str);

	return AddNode(pList, newStr);
}

/*
 *  Get a function's name according to its name
 *  @param [in] name function's name
 *  @return function node represented by the name
 */
FuncNode* GetFunctionByName(char* name)
{
	if (g_FunctionTable.iNodeCount == 0)
		return NULL;

	//Look through the function table to find the specific function
	LinkListNode* pCurrentNode = g_FunctionTable.pHead;
	for (int i = 0; i < g_FunctionTable.iNodeCount; i++)
	{
		FuncNode* pCurrentFunc = (FuncNode*)pCurrentNode->pNext;
		if (strcpy(pCurrentFunc->strName, name) == 0)
			return pCurrentFunc;
		//Move to next node in table
		pCurrentNode = pCurrentNode->pNext;
	}
	//Can not find the specific function
	return NULL;
}

/*
 *  Add Function into the global function table
 *  @param [in] name function's name
 *  @param [in] entryPoint function's entryPoint
 *  @return if the function has bean already in the table, return -1.
 *  Otherwise, insert a new function according to the name and entryPoint,
 *  and return the new index;
 */
int AddFunction(char* name, int entryPoint)
{
	//if the function already exists in table, return -1
	if (GetFunctionByName(name))
		return -1;
	//create a new function according to the name and entryPoint;
	FuncNode* newFunc = (FuncNode*) malloc(sizeof(FuncNode));
	strcpy(newFunc->strName, name);
	newFunc->iEntryPoint = entryPoint;

	//Get the index of the function in the global function table;
	int index = AddNode(&g_FunctionTable, newFunc);
	newFunc->iIndex = index;

	return index;
}

/*
 *  Set the other info of a function node
 *  @param [in] name function's name
 *  @param [in] paramNum number of the function's parameter
 *  @param [in] function's data size
 *  @return void
 */
void SetFunctionInfo(char* name, int paramNum, int localDataSize)
{
	//Get the function according to the name;
	FuncNode* funcNode       = GetFunctionByName(name);
	funcNode->iParamCount    = paramNum;
	funcNode->iLocalDataSize = localDataSize;
}

/** @}*/ // Function Definition

/** @}*/ // File Type End

<|endoftext|>


<commit_before>#include "scope.h"
#include "details/grammar/nany.h"
#include "details/ir/emit.h"

using namespace Yuni;

namespace ny::ir::Producer {

bool Scope::visitASTExprTypeDecl(AST::Node& node, uint32_t& localvar) {
	assert(node.rule == AST::rgTypeDecl);
	localvar = 0;
	if (node.children.size() == 1) {
		auto& identifier = node.children[0];
		if (identifier.children.empty()) {
			if (identifier.text == "any") { // no real information, already 'any'
				localvar = uint32_t(-1);
				return true;
			}
			if (identifier.text == "void") {
				localvar = 0;
				return true;
			}
		}
		else {
			// anonymous / inline class definitnio
			if (identifier.rule == AST::rgClass) {
				//error(identifier) << "anonymous classes are not supported yet";
				//return false;
				return visitASTClass(identifier, &localvar);
			}
		}
	}
	ir::Producer::Scope scope{*this};
	ir::emit::CodegenLocker codegenDisabler{ircode()};
	return scope.visitASTExpr(node, localvar);
}

bool Scope::visitASTType(AST::Node& node, uint32_t& localvar) {
	assert(node.rule == AST::rgType);
	assert(not node.children.empty());
	bool success = true;
	bool reallyVoid = false;
	bool isRef = false;
	bool isConst = false;
	localvar = 0; // reset
	for (auto& child : node.children) {
		switch (child.rule) {
			case AST::rgTypeDecl: {
				if (unlikely(localvar != 0))
					return unexpectedNode(child, "[ir/new/several calls]");
				bool status = visitASTExprTypeDecl(child, localvar);
				success &= status;
				if (status and localvar == 0)
					reallyVoid = true;
				break;
			}
			case AST::rgTypeQualifier: {
				for (auto& qualifier : child.children) {
					switch (qualifier.rule) {
						case AST::rgRef:
							isRef   = true;
							break;
						case AST::rgConst:
							isConst = true;
							break;
						case AST::rgCref:
							isRef   = true;
							isConst = true;
							break;
						default:
							success = unexpectedNode(child, "[ir/type-qualifier]");
					}
				}
				break;
			}
			case AST::rgClass: {
				break;
			}
			default:
				success = unexpectedNode(child, "[ir/type]");
		}
	}
	emitDebugpos(node);
	auto& irout = ircode();
	// create a value even if nothing to always have an attached value
	if (localvar == 0 and not reallyVoid /*any*/)
		localvar = ir::emit::alloc(irout, nextvar());
	if (0 != localvar) {
		if (localvar == (uint32_t) - 1)
			localvar = ir::emit::alloc(irout, reserveLocalVariable());
		ir::emit::type::qualifierRef(irout, localvar, isRef);
		ir::emit::type::qualifierConst(irout, localvar, isConst);
	}
	return success;
}

} // ny::ir::Producer
<commit_msg>ast2ir: type: convert if to switch (for future additions)<commit_after>#include "scope.h"
#include "details/grammar/nany.h"
#include "details/ir/emit.h"

using namespace Yuni;

namespace ny::ir::Producer {

bool Scope::visitASTExprTypeDecl(AST::Node& node, uint32_t& localvar) {
	assert(node.rule == AST::rgTypeDecl);
	localvar = 0;
	if (node.children.size() == 1) {
		auto& identifier = node.children[0];
		if (identifier.children.empty()) {
			if (identifier.text == "any") { // no real information, already 'any'
				localvar = uint32_t(-1);
				return true;
			}
			if (identifier.text == "void") {
				localvar = 0;
				return true;
			}
		}
		else {
			switch (identifier.rule) {
				case AST::rgClass: { // anonymous / inline class definitnio
					//error(identifier) << "anonymous classes are not supported yet";
					//return false;
					return visitASTClass(identifier, &localvar);
				}
				default:
					break;
			}
		}
	}
	ir::Producer::Scope scope{*this};
	ir::emit::CodegenLocker codegenDisabler{ircode()};
	return scope.visitASTExpr(node, localvar);
}

bool Scope::visitASTType(AST::Node& node, uint32_t& localvar) {
	assert(node.rule == AST::rgType);
	assert(not node.children.empty());
	bool success = true;
	bool reallyVoid = false;
	bool isRef = false;
	bool isConst = false;
	localvar = 0; // reset
	for (auto& child : node.children) {
		switch (child.rule) {
			case AST::rgTypeDecl: {
				if (unlikely(localvar != 0))
					return unexpectedNode(child, "[ir/new/several calls]");
				bool status = visitASTExprTypeDecl(child, localvar);
				success &= status;
				if (status and localvar == 0)
					reallyVoid = true;
				break;
			}
			case AST::rgTypeQualifier: {
				for (auto& qualifier : child.children) {
					switch (qualifier.rule) {
						case AST::rgRef:
							isRef   = true;
							break;
						case AST::rgConst:
							isConst = true;
							break;
						case AST::rgCref:
							isRef   = true;
							isConst = true;
							break;
						default:
							success = unexpectedNode(child, "[ir/type-qualifier]");
					}
				}
				break;
			}
			case AST::rgClass: {
				break;
			}
			default:
				success = unexpectedNode(child, "[ir/type]");
		}
	}
	emitDebugpos(node);
	auto& irout = ircode();
	// create a value even if nothing to always have an attached value
	if (localvar == 0 and not reallyVoid /*any*/)
		localvar = ir::emit::alloc(irout, nextvar());
	if (0 != localvar) {
		if (localvar == (uint32_t) - 1)
			localvar = ir::emit::alloc(irout, reserveLocalVariable());
		ir::emit::type::qualifierRef(irout, localvar, isRef);
		ir::emit::type::qualifierConst(irout, localvar, isConst);
	}
	return success;
}

} // ny::ir::Producer
<|endoftext|>


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

#include "api-loader.h"

#include "pointers.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <cstdlib>
#include <cassert>

#ifdef USE_DETOURS
#include "detours/detours.h"
#endif

#ifdef USE_MHOOK
#include "mhook/mhook-lib/mhook.h"
#endif

#include "gl-wrappers.h"

#include <DGLCommon/os.h>

#ifndef _WIN32
#include "dl-intercept.h"
#endif

#ifdef _WIN32
#define LIBGL_NAME     "opengl32.dll"
#define LIBGLES1_NAME  "libGLESv1_CM.dll"
#define LIBGLES2_NAME  "libGLESv2.dll"
#define LIBEGL_NAME    "libEGL.dll"
#define STRIP_VERSION(X) X
#elif defined(__ANDROID__)
//on Android libraries are not opened by SONAME
#define LIBGL_NAME    "libGL.so"
#define LIBGLES1_NAME "libGLESv1_CM.so"
#define LIBGLES2_NAME "libGLESv2.so"
#define LIBEGL_NAME   "libEGL.so"
#define STRIP_VERSION(X) X
#else
#define LIBGL_NAME    "libGL.so.1"
#define LIBGLES1_NAME "libGLESv1_CM.so.1"
#define LIBGLES2_NAME "libGLESv2.so.1"
#define LIBEGL_NAME   "libEGL.so.1"
#define STRIP_VERSION(X) std::string(X).substr(0, std::string(X).length() - strlen(".1"))
#endif

//here direct pointers are kept (pointers to entrypoints exposed by underlying OpenGL32 implementation
//use DIRECT_CALL(name) to call one of these pointers
LoadedPointer g_DirectPointers[Entrypoints_NUM] = {
#define FUNC_LIST_ELEM_SUPPORTED(name, type, library) { NULL, library},
#define FUNC_LIST_ELEM_NOT_SUPPORTED(name, type, library) FUNC_LIST_ELEM_SUPPORTED(name, type, library)
    #include "codegen/functionList.inl"
#undef FUNC_LIST_ELEM_SUPPORTED
#undef FUNC_LIST_ELEM_NOT_SUPPORTED
};

APILoader::APILoader():m_LoadedApiLibraries(LIBRARY_NONE),m_GlueLibrary(LIBRARY_NONE) {}

FUNC_PTR APILoader::loadGLPointer(LoadedLib library, Entrypoint entryp) {
#ifdef _WIN32
    return reinterpret_cast<FUNC_PTR>(GetProcAddress((HINSTANCE)library, GetEntryPointName(entryp)));
#else
    //(int) -> see http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
    return reinterpret_cast<FUNC_PTR>((ptrdiff_t)dlsym(library, GetEntryPointName(entryp)));
#endif
}

bool APILoader::loadExtPointer(Entrypoint entryp) {
    if (!g_DirectPointers[entryp].ptr) {

        if (!m_GlueLibrary) {
            throw std::runtime_error("Trying to call *GetProcAdress, but no glue library loaded");
        }

        FUNC_PTR ptr = NULL;

        switch (m_GlueLibrary) {
#ifdef HAVE_LIBRARY_WGL
        case LIBRARY_WGL:
            ptr  = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(wglGetProcAddress)(GetEntryPointName(entryp)));
            break;
#endif
#ifdef HAVE_LIBRARY_GLX
        case LIBRARY_GLX:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(glXGetProcAddress)(
                        reinterpret_cast<const GLubyte*>(GetEntryPointName(entryp))));
            break;
#endif
        case LIBRARY_EGL:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(eglGetProcAddress)(GetEntryPointName(entryp)));
            break;
        default:
            assert(!"unknown glue library");
        }
        g_DirectPointers[entryp].ptr = ptr;
    }
    return g_DirectPointers[entryp].ptr != NULL;
}

std::string APILoader::getLibraryName(ApiLibrary apiLibrary) {
    switch (apiLibrary) {
        case LIBRARY_EGL:
            return LIBEGL_NAME;
        case LIBRARY_GL:
        case LIBRARY_WGL:
        case LIBRARY_GLX:
            return LIBGL_NAME;
        case LIBRARY_ES1:
            return LIBGLES1_NAME;
        case LIBRARY_ES2:
        case LIBRARY_ES3:
            return LIBGLES2_NAME;
        default:
            assert(!"unknown library");
            throw std::runtime_error("Unknown GL library name");
    }
}

bool APILoader::isLibGL(const char* name) {
    std::string nameStr(name);
    bool ret = nameStr.find(STRIP_VERSION(LIBGL_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES1_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES2_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBEGL_NAME)) != std::string::npos;

    return ret;

}

void APILoader::setPointer(Entrypoint entryp, FUNC_PTR direct) {
    if (entryp < NO_ENTRYPOINT) {
         g_DirectPointers[entryp].ptr = direct;
    }
}

void APILoader::loadLibrary(ApiLibrary apiLibrary) {

    std::string libraryName = getLibraryName(apiLibrary);

    if (m_LoadedLibraries.find(libraryName) == m_LoadedLibraries.end()) {

        std::vector<std::string> libSearchPath;

        LoadedLib openGLLibraryHandle = NULL;

        libSearchPath.push_back("");
#ifdef _WIN32
        char buffer[1000];
#ifndef _WIN64
        if (GetSystemWow64Directory(buffer, sizeof(buffer)) > 0) {
            //we are running 32bit app on 64 bit windows
            libSearchPath.push_back(buffer + std::string("\\"));
        }
#endif
        if (!openGLLibraryHandle) {
            if (GetSystemDirectory(buffer, sizeof(buffer)) > 0) {
                //we are running on native system (32 on 32 or 64 on 64)
                libSearchPath.push_back(buffer + std::string("\\"));
            }
        }
#ifndef _WIN64
        libSearchPath.push_back("C:\\Windows\\SysWOW64\\");
#endif
        libSearchPath.push_back("C:\\Windows\\System32\\");
        libSearchPath.push_back(".");
#endif

        for (size_t i = 0; i < libSearchPath.size() && !openGLLibraryHandle; i++) {
#ifdef _WIN32
            openGLLibraryHandle = (LoadedLib)LoadLibrary((libSearchPath[i] + libraryName).c_str());
#else
            openGLLibraryHandle = dlopen((libSearchPath[i] + libraryName).c_str(), RTLD_NOW);
#endif
        }

        if (!openGLLibraryHandle) {
            std::string msg = std::string("Cannot load ") + libraryName + "  system library";
            Os::fatal(msg.c_str());
        } else {
            m_LoadedLibraries[libraryName] = openGLLibraryHandle;
        }
    }

    LoadedLib library = m_LoadedLibraries[libraryName];

    //we use MS Detours only on win32, on x64 mHook is used
#ifdef USE_DETOURS
    DetourRestoreAfterWith();
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
#endif
    //g_DirectPointers is now filled with opengl32.dll pointers
    // we will now detour (hook) them all, so g_DirectPointers will still lead to original opengl32.dll, but
    //application will always call us.
    for (int i = 0; i < Entrypoints_NUM; i++) {
        if (!(g_DirectPointers[i].libraryMask & apiLibrary)) {
            //Do not load - entrypoint does not belong to currently loaded API
            continue;
        }

        if (m_LoadedApiLibraries & g_DirectPointers[i].libraryMask) {
            //Do not load - entrypoint belongs to already loaded API
            continue;
        }

        //this sets g_DirectPointers[i].ptr
        setPointer(i, loadGLPointer(library, i));

        if (g_DirectPointers[i].ptr) {
            //this entrypoint was loaded from OpenGL32.dll, detour it!
#if defined(USE_DETOURS) || defined(USE_MHOOK)
            FUNC_PTR hookPtr = getWrapperPointer(i);
#endif
#ifdef USE_DETOURS
            DetourAttach(&(PVOID&)g_DirectPointers[i].ptr, hookPtr);
#endif
#ifdef USE_MHOOK
            if (!Mhook_SetHook(&(PVOID&)g_DirectPointers[i].ptr, hookPtr)) {
                Os::fatal("Cannot hook %s() function.", GetEntryPointName(i));
            }
#endif
        }
    }
#ifdef USE_DETOURS
    DetourTransactionCommit();
#endif
    if (apiLibrary == LIBRARY_EGL || apiLibrary == LIBRARY_WGL || apiLibrary == LIBRARY_GLX)
        m_GlueLibrary = apiLibrary;

    m_LoadedApiLibraries |= apiLibrary;
}

FUNC_PTR APILoader::ensurePointer(Entrypoint entryp) {
    if (g_DirectPointers[entryp].ptr || loadExtPointer(entryp)) {
        return g_DirectPointers[entryp].ptr;
    } else {
        std::string error = "Operation aborted, because the ";
        error += GetEntryPointName(entryp);
        error += " function is not available on current context. Try updating GPU drivers.";
        throw std::runtime_error(error);
    }
}

APILoader g_ApiLoader;
<commit_msg>Correct libGLESv2.so SONAME: it is .2, not .1<commit_after>/* Copyright (C) 2013 Slawomir Cygan <slawomir.cygan@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "api-loader.h"

#include "pointers.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <cstdlib>
#include <cassert>

#ifdef USE_DETOURS
#include "detours/detours.h"
#endif

#ifdef USE_MHOOK
#include "mhook/mhook-lib/mhook.h"
#endif

#include "gl-wrappers.h"

#include <DGLCommon/os.h>

#ifndef _WIN32
#include "dl-intercept.h"
#endif

#ifdef _WIN32
#define LIBGL_NAME     "opengl32.dll"
#define LIBGLES1_NAME  "libGLESv1_CM.dll"
#define LIBGLES2_NAME  "libGLESv2.dll"
#define LIBEGL_NAME    "libEGL.dll"
#define STRIP_VERSION(X) X
#elif defined(__ANDROID__)
//on Android libraries are not opened by SONAME
#define LIBGL_NAME    "libGL.so"
#define LIBGLES1_NAME "libGLESv1_CM.so"
#define LIBGLES2_NAME "libGLESv2.so"
#define LIBEGL_NAME   "libEGL.so"
#define STRIP_VERSION(X) X
#else
#define LIBGL_NAME    "libGL.so.1"
#define LIBGLES1_NAME "libGLESv1_CM.so.1"
#define LIBGLES2_NAME "libGLESv2.so.2"
#define LIBEGL_NAME   "libEGL.so.1"
#define STRIP_VERSION(X) std::string(X).substr(0, std::string(X).length() - strlen(".1"))
#endif

//here direct pointers are kept (pointers to entrypoints exposed by underlying OpenGL32 implementation
//use DIRECT_CALL(name) to call one of these pointers
LoadedPointer g_DirectPointers[Entrypoints_NUM] = {
#define FUNC_LIST_ELEM_SUPPORTED(name, type, library) { NULL, library},
#define FUNC_LIST_ELEM_NOT_SUPPORTED(name, type, library) FUNC_LIST_ELEM_SUPPORTED(name, type, library)
    #include "codegen/functionList.inl"
#undef FUNC_LIST_ELEM_SUPPORTED
#undef FUNC_LIST_ELEM_NOT_SUPPORTED
};

APILoader::APILoader():m_LoadedApiLibraries(LIBRARY_NONE),m_GlueLibrary(LIBRARY_NONE) {}

FUNC_PTR APILoader::loadGLPointer(LoadedLib library, Entrypoint entryp) {
#ifdef _WIN32
    return reinterpret_cast<FUNC_PTR>(GetProcAddress((HINSTANCE)library, GetEntryPointName(entryp)));
#else
    //(int) -> see http://www.trilithium.com/johan/2004/12/problem-with-dlsym/
    return reinterpret_cast<FUNC_PTR>((ptrdiff_t)dlsym(library, GetEntryPointName(entryp)));
#endif
}

bool APILoader::loadExtPointer(Entrypoint entryp) {
    if (!g_DirectPointers[entryp].ptr) {

        if (!m_GlueLibrary) {
            throw std::runtime_error("Trying to call *GetProcAdress, but no glue library loaded");
        }

        FUNC_PTR ptr = NULL;

        switch (m_GlueLibrary) {
#ifdef HAVE_LIBRARY_WGL
        case LIBRARY_WGL:
            ptr  = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(wglGetProcAddress)(GetEntryPointName(entryp)));
            break;
#endif
#ifdef HAVE_LIBRARY_GLX
        case LIBRARY_GLX:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(glXGetProcAddress)(
                        reinterpret_cast<const GLubyte*>(GetEntryPointName(entryp))));
            break;
#endif
        case LIBRARY_EGL:
            ptr = reinterpret_cast<FUNC_PTR>(DIRECT_CALL(eglGetProcAddress)(GetEntryPointName(entryp)));
            break;
        default:
            assert(!"unknown glue library");
        }
        g_DirectPointers[entryp].ptr = ptr;
    }
    return g_DirectPointers[entryp].ptr != NULL;
}

std::string APILoader::getLibraryName(ApiLibrary apiLibrary) {
    switch (apiLibrary) {
        case LIBRARY_EGL:
            return LIBEGL_NAME;
        case LIBRARY_GL:
        case LIBRARY_WGL:
        case LIBRARY_GLX:
            return LIBGL_NAME;
        case LIBRARY_ES1:
            return LIBGLES1_NAME;
        case LIBRARY_ES2:
        case LIBRARY_ES3:
            return LIBGLES2_NAME;
        default:
            assert(!"unknown library");
            throw std::runtime_error("Unknown GL library name");
    }
}

bool APILoader::isLibGL(const char* name) {
    std::string nameStr(name);
    bool ret = nameStr.find(STRIP_VERSION(LIBGL_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES1_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBGLES2_NAME)) != std::string::npos ||
        nameStr.find(STRIP_VERSION(LIBEGL_NAME)) != std::string::npos;

    return ret;

}

void APILoader::setPointer(Entrypoint entryp, FUNC_PTR direct) {
    if (entryp < NO_ENTRYPOINT) {
         g_DirectPointers[entryp].ptr = direct;
    }
}

void APILoader::loadLibrary(ApiLibrary apiLibrary) {

    std::string libraryName = getLibraryName(apiLibrary);

    if (m_LoadedLibraries.find(libraryName) == m_LoadedLibraries.end()) {

        std::vector<std::string> libSearchPath;

        LoadedLib openGLLibraryHandle = NULL;

        libSearchPath.push_back("");
#ifdef _WIN32
        char buffer[1000];
#ifndef _WIN64
        if (GetSystemWow64Directory(buffer, sizeof(buffer)) > 0) {
            //we are running 32bit app on 64 bit windows
            libSearchPath.push_back(buffer + std::string("\\"));
        }
#endif
        if (!openGLLibraryHandle) {
            if (GetSystemDirectory(buffer, sizeof(buffer)) > 0) {
                //we are running on native system (32 on 32 or 64 on 64)
                libSearchPath.push_back(buffer + std::string("\\"));
            }
        }
#ifndef _WIN64
        libSearchPath.push_back("C:\\Windows\\SysWOW64\\");
#endif
        libSearchPath.push_back("C:\\Windows\\System32\\");
        libSearchPath.push_back(".");
#endif

        for (size_t i = 0; i < libSearchPath.size() && !openGLLibraryHandle; i++) {
#ifdef _WIN32
            openGLLibraryHandle = (LoadedLib)LoadLibrary((libSearchPath[i] + libraryName).c_str());
#else
            openGLLibraryHandle = dlopen((libSearchPath[i] + libraryName).c_str(), RTLD_NOW);
#endif
        }

        if (!openGLLibraryHandle) {
            std::string msg = std::string("Cannot load ") + libraryName + "  system library";
            Os::fatal(msg.c_str());
        } else {
            m_LoadedLibraries[libraryName] = openGLLibraryHandle;
        }
    }

    LoadedLib library = m_LoadedLibraries[libraryName];

    //we use MS Detours only on win32, on x64 mHook is used
#ifdef USE_DETOURS
    DetourRestoreAfterWith();
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
#endif
    //g_DirectPointers is now filled with opengl32.dll pointers
    // we will now detour (hook) them all, so g_DirectPointers will still lead to original opengl32.dll, but
    //application will always call us.
    for (int i = 0; i < Entrypoints_NUM; i++) {
        if (!(g_DirectPointers[i].libraryMask & apiLibrary)) {
            //Do not load - entrypoint does not belong to currently loaded API
            continue;
        }

        if (m_LoadedApiLibraries & g_DirectPointers[i].libraryMask) {
            //Do not load - entrypoint belongs to already loaded API
            continue;
        }

        //this sets g_DirectPointers[i].ptr
        setPointer(i, loadGLPointer(library, i));

        if (g_DirectPointers[i].ptr) {
            //this entrypoint was loaded from OpenGL32.dll, detour it!
#if defined(USE_DETOURS) || defined(USE_MHOOK)
            FUNC_PTR hookPtr = getWrapperPointer(i);
#endif
#ifdef USE_DETOURS
            DetourAttach(&(PVOID&)g_DirectPointers[i].ptr, hookPtr);
#endif
#ifdef USE_MHOOK
            if (!Mhook_SetHook(&(PVOID&)g_DirectPointers[i].ptr, hookPtr)) {
                Os::fatal("Cannot hook %s() function.", GetEntryPointName(i));
            }
#endif
        }
    }
#ifdef USE_DETOURS
    DetourTransactionCommit();
#endif
    if (apiLibrary == LIBRARY_EGL || apiLibrary == LIBRARY_WGL || apiLibrary == LIBRARY_GLX)
        m_GlueLibrary = apiLibrary;

    m_LoadedApiLibraries |= apiLibrary;
}

FUNC_PTR APILoader::ensurePointer(Entrypoint entryp) {
    if (g_DirectPointers[entryp].ptr || loadExtPointer(entryp)) {
        return g_DirectPointers[entryp].ptr;
    } else {
        std::string error = "Operation aborted, because the ";
        error += GetEntryPointName(entryp);
        error += " function is not available on current context. Try updating GPU drivers.";
        throw std::runtime_error(error);
    }
}

APILoader g_ApiLoader;
<|endoftext|>


<commit_before>#include "nlt_store.hpp"

namespace nark { namespace db { namespace dfadb {

NARK_DB_REGISTER_STORE("nlt", NestLoudsTrieStore);

NestLoudsTrieStore::NestLoudsTrieStore() {
}
NestLoudsTrieStore::~NestLoudsTrieStore() {
}

llong NestLoudsTrieStore::dataStorageSize() const {
	return m_store->mem_size();
}

llong NestLoudsTrieStore::numDataRows() const {
	return m_store->num_records();
}

void NestLoudsTrieStore::getValueAppend(llong id, valvec<byte>* val, DbContext* ctx) const {
	m_store->get_record_append(size_t(id), val);
}

StoreIterator* NestLoudsTrieStore::createStoreIterForward(DbContext*) const {
	return nullptr; // not needed
}

StoreIterator* NestLoudsTrieStore::createStoreIterBackward(DbContext*) const {
	return nullptr; // not needed
}

void NestLoudsTrieStore::build(SortableStrVec& strVec) {
	NestLoudsTrieConfig conf;
//	conf.maxFragLen = 512;
	conf.initFromEnv();
	m_store.reset(new NestLoudsTrieDataStore_SE_512());
	m_store->build_from(strVec, conf);
}

void NestLoudsTrieStore::load(PathRef path) {
	std::string fpath = fstring(path.string()).endsWith(".nlt")
					  ? path.string()
					  : path.string() + ".nlt";
	std::unique_ptr<BaseDFA> dfa(BaseDFA::load_mmap(fpath.c_str()));
	m_store.reset(dynamic_cast<NestLoudsTrieDataStore_SE_512*>(dfa.get()));
	if (m_store) {
		dfa.release();
	}
}

void NestLoudsTrieStore::save(PathRef path) const {
	std::string fpath = fstring(path.string()).endsWith(".nlt")
					  ? path.string()
					  : path.string() + ".nlt";
	m_store->save_mmap(fpath.c_str());
}

}}} // namespace nark::db::dfadb
<commit_msg>Minor fix src/nark/db/dfadb/nlt_store.cpp<commit_after>#include "nlt_store.hpp"
#include <typeinfo>

namespace nark { namespace db { namespace dfadb {

NARK_DB_REGISTER_STORE("nlt", NestLoudsTrieStore);

NestLoudsTrieStore::NestLoudsTrieStore() {
}
NestLoudsTrieStore::~NestLoudsTrieStore() {
}

llong NestLoudsTrieStore::dataStorageSize() const {
	return m_store->mem_size();
}

llong NestLoudsTrieStore::numDataRows() const {
	return m_store->num_records();
}

void NestLoudsTrieStore::getValueAppend(llong id, valvec<byte>* val, DbContext* ctx) const {
	m_store->get_record_append(size_t(id), val);
}

StoreIterator* NestLoudsTrieStore::createStoreIterForward(DbContext*) const {
	return nullptr; // not needed
}

StoreIterator* NestLoudsTrieStore::createStoreIterBackward(DbContext*) const {
	return nullptr; // not needed
}

void NestLoudsTrieStore::build(SortableStrVec& strVec) {
	NestLoudsTrieConfig conf;
//	conf.maxFragLen = 512;
	conf.initFromEnv();
	m_store.reset(new NestLoudsTrieDataStore_SE_512());
	m_store->build_from(strVec, conf);
}

void NestLoudsTrieStore::load(PathRef path) {
	std::string fpath = fstring(path.string()).endsWith(".nlt")
					  ? path.string()
					  : path.string() + ".nlt";
	std::unique_ptr<BaseDFA> dfa(BaseDFA::load_mmap(fpath.c_str()));
	m_store.reset(dynamic_cast<NestLoudsTrieDataStore_SE_512*>(dfa.get()));
	if (m_store) {
		dfa.release();
	}
	else {
		THROW_STD(invalid_argument
			, "FATAL: file: %s is %s, not a NestLoudsTrieDataStore_SE_512"
			, typeid(*dfa).name(), fpath.c_str());
	}
}

void NestLoudsTrieStore::save(PathRef path) const {
	std::string fpath = fstring(path.string()).endsWith(".nlt")
					  ? path.string()
					  : path.string() + ".nlt";
	m_store->save_mmap(fpath.c_str());
}

}}} // namespace nark::db::dfadb
<|endoftext|>


<commit_before>#include "oddlib/compressiontype2.hpp"
#include "oddlib/stream.hpp"
#include "logger.hpp"

namespace Oddlib
{
    static bool ExpandElement(Sint32& remainingCount, Uint8*& src, Uint32*& dst)
    {
        if (!remainingCount)
        {
            return false;
        }
        const Sint32 src_word = *src | (*(Uint16 *)(src + 1) << 8);
        ++dst;
        src += 3;
        remainingCount--;
        *(dst - 1) = 4 * (Uint16)src_word & 0x3F00 | src_word & 0x3F | 16 * src_word & 0x3F0000 | 4 * (16 * src_word & 0xFC00000);

        return true;
    }

    // Function 0x0040AA50 in AE
    std::vector<Uint8> CompressionType2::Decompress(IStream& stream, Uint32 finalW, Uint32 /*w*/, Uint32 h, Uint32 dataSize)
    {
        std::vector<Uint8> ret(finalW*h);

        std::vector<Uint8> s(dataSize);
        stream.ReadBytes(s.data(), s.size());

        Sint32 dwords_left = dataSize / 4;
        Sint32 remainder = dataSize % 4;

        Uint32 *dst = (Uint32*)ret.data();
        Uint8 *src = s.data();

        if (dwords_left > 0)
        {
            dst = (Uint32*)ret.data();
            src = s.data();
            do
            {
                for (int i = 0; i < 4; i++)
                {
                    if (!ExpandElement(dwords_left, src, dst))
                    {
                        break;
                    }
                }
            } while (dwords_left);
        }

        while (remainder)
        {
            remainder--;
            *(Uint8 *)dst = *src;
            dst = (Uint32 *)((char *)dst + 1);
            ++src;
        }

        return ret;
    }
}
<commit_msg>refactor for bounds saftey<commit_after>#include "oddlib/compressiontype2.hpp"
#include "oddlib/stream.hpp"
#include "logger.hpp"

namespace Oddlib
{
    static bool Expand3To4Bytes(Sint32& remainingCount, IStream& stream, std::vector<Uint8>& ret, Uint32& dstPos)
    {
        if (!remainingCount)
        {
            return false;
        }
        const Sint32 src3Bytes = ReadUInt8(stream) | (ReadUint16(stream) << 8);
        remainingCount--;

        // TODO: Should write each byte by itself
        const Uint32 value = 4 * (Uint16)src3Bytes & 0x3F00 | src3Bytes & 0x3F | 16 * src3Bytes & 0x3F0000 | 4 * (16 * src3Bytes & 0xFC00000);
        *reinterpret_cast<Uint32*>(&ret[dstPos]) = value;
        dstPos += 4;

        return true;
    }

    // Function 0x0040AA50 in AE
    std::vector<Uint8> CompressionType2::Decompress(IStream& stream, Uint32 finalW, Uint32 /*w*/, Uint32 h, Uint32 dataSize)
    {
        std::vector<Uint8> ret(finalW*h);

        Sint32 dwords_left = dataSize / 4;
        Sint32 remainder = dataSize % 4;

        Uint32 dstPos = 0;
        if (dwords_left > 0)
        {
            do
            {
                for (int i = 0; i < 4; i++)
                {
                    if (!Expand3To4Bytes(dwords_left, stream, ret, dstPos))
                    {
                        break;
                    }
                }
            } while (dwords_left);
        }

        // TODO: Branch not tested
        while (remainder)
        {
            remainder--;
            ret[dstPos++] = ReadUInt8(stream);
        }

        return ret;
    }
}
<|endoftext|>


<commit_before>
#include <vector>
#include <string>

using namespace std;

namespace L10ns {

enum class ActionKind {
    None,
    Init,
    Update,
    Log,
    Set,
};

enum class FlagKind {
    None,
    Help,
    Version,
    Language,
    Key,
    Value,
};

struct Argument {
    string * name;
    string * description;

    Argument(string * pname, string * pdescription) {
        name = pname;
        description = pdescription;
    }
};

struct Flag : Argument {
    string * alias;
    bool hasValue;
    FlagKind kind;
    string value;

    Flag(FlagKind pkind, const char pname[], const char palias[], const char pdescription[], bool phasValue)
        : kind(pkind), Argument(new string(pname), new string(pdescription)), alias(new string(palias)) {

        hasValue = phasValue;
        value = "";
    }
};

struct Action : Argument {
    vector<Flag> * flags;
    ActionKind kind;

    Action(ActionKind pkind, const char pname[], const char pdescription[], vector<Flag> * pflags)
        : kind(pkind), Argument(new string(pname), new string(pdescription)) {

        if (pflags != NULL) {
            flags = pflags;
        }
    }
};

static Flag helpFlag = Flag(FlagKind::Help, "--help", "-h", "Print help description.", /*hasValue*/ false);
static Flag languageFlag = Flag(FlagKind::Language, "--language", "-l", "Specify language.", false);

static vector<Flag> defaultFlags = {
    helpFlag,
    Flag(FlagKind::Version, "--version", "-v", "Print current version.", /*hasValue*/ false),
};

static vector<Flag> helpFlags = {
    helpFlag,
};

static vector<Flag> setFlags = {
    Flag(FlagKind::Key, "--key", "-k", "Specify localization key.", /*hasValue*/ true),
    Flag(FlagKind::Value, "--value", "-v", "Specify localization value.", /*hasValue*/ true),
    languageFlag,
    helpFlag,
};

static vector<Flag> logFlags = {
    languageFlag,
    helpFlag,
};

static vector<Action> actions = {
    Action(ActionKind::Init, "init", "Initialize project.", &helpFlags),
    Action(ActionKind::Update, "update", "Update localization keys.", &helpFlags),
    Action(ActionKind::Log, "log", "Show latest added localizations.", &logFlags),
    Action(ActionKind::Set, "set", "Set localization.", &setFlags),
};

struct Command {
    bool isRequestingHelp;
    bool isRequestingVersion;
    ActionKind action;
    vector<Flag> * flags;

    Command()
        : isRequestingHelp(false)
        , isRequestingVersion(false)
        , action(ActionKind::None)
        , flags(&defaultFlags) {

    }
};

void setCommandFlag(Command *command, const Flag *flag, char *value = NULL) {
    switch (flag->kind) {
        case FlagKind::Help:
            command->isRequestingHelp = true;
            return;
        case FlagKind::Version:
            command->isRequestingVersion = true;
            return;
        default:
            return;
    }
}

Command* parseCommandArguments(int argc, char* argv[]) {
    Command * command = new Command();

    // Flag to optimize has action parsing.
    bool hasAction = false;

    // The option flag that is pending for a value.
    const Flag * flagWhichAwaitsValue = NULL;

    for (int argIndex = 1; argIndex < argc; argIndex++) {
        auto arg = argv[argIndex];
        if (!hasAction) {
            for (auto const& a : actions) {
                if (strcmp(a.name->c_str(), arg) == 0) {
                    command->action = a.kind;
                    hasAction = true;
                    command->flags = a.flags;
                    break;
                }
            }
        }

        if (flagWhichAwaitsValue == NULL) {
            for (auto const& flag : *command->flags) {
                if (strcmp(flag.name->c_str(), arg) == 0 || (flag.alias->length() != 0 && strcmp(flag.name->c_str(), arg) == 0)) {
                    if (flag.hasValue) {
                        flagWhichAwaitsValue = &flag;
                    }
                    setCommandFlag(command, &flag);
                    break;
                }
            }
        }
        else {
            setCommandFlag(command, flagWhichAwaitsValue, arg);
            flagWhichAwaitsValue = NULL;
            continue;
        }
    }

    return command;
}

} // L10ns
<commit_msg>Removes short alias of version<commit_after>
#include <vector>
#include <string>

using namespace std;

namespace L10ns {

enum class ActionKind {
    None,
    Init,
    Update,
    Log,
    Set,
};

enum class FlagKind {
    None,
    Help,
    Version,
    Language,
    Key,
    Value,
};

struct Argument {
    string * name;
    string * description;

    Argument(string * pname, string * pdescription) {
        name = pname;
        description = pdescription;
    }
};

struct Flag : Argument {
    string * alias;
    bool hasValue;
    FlagKind kind;
    string value;

    Flag(FlagKind pkind, const char pname[], const char palias[], const char pdescription[], bool phasValue)
        : kind(pkind), Argument(new string(pname), new string(pdescription)), alias(new string(palias)) {

        hasValue = phasValue;
        value = "";
    }
};

struct Action : Argument {
    vector<Flag> * flags;
    ActionKind kind;

    Action(ActionKind pkind, const char pname[], const char pdescription[], vector<Flag> * pflags)
        : kind(pkind), Argument(new string(pname), new string(pdescription)) {

        if (pflags != NULL) {
            flags = pflags;
        }
    }
};

static Flag helpFlag = Flag(FlagKind::Help, "--help", "-h", "Print help description.", /*hasValue*/ false);
static Flag languageFlag = Flag(FlagKind::Language, "--language", "-l", "Specify language.", false);

static vector<Flag> defaultFlags = {
    helpFlag,
    Flag(FlagKind::Version, "--version", "", "Print current version.", /*hasValue*/ false),
};

static vector<Flag> helpFlags = {
    helpFlag,
};

static vector<Flag> setFlags = {
    Flag(FlagKind::Key, "--key", "-k", "Specify localization key.", /*hasValue*/ true),
    Flag(FlagKind::Value, "--value", "-v", "Specify localization value.", /*hasValue*/ true),
    languageFlag,
    helpFlag,
};

static vector<Flag> logFlags = {
    languageFlag,
    helpFlag,
};

static vector<Action> actions = {
    Action(ActionKind::Init, "init", "Initialize project.", &helpFlags),
    Action(ActionKind::Update, "update", "Update localization keys.", &helpFlags),
    Action(ActionKind::Log, "log", "Show latest added localizations.", &logFlags),
    Action(ActionKind::Set, "set", "Set localization.", &setFlags),
};

struct Command {
    bool isRequestingHelp;
    bool isRequestingVersion;
    ActionKind action;
    vector<Flag> * flags;

    Command()
        : isRequestingHelp(false)
        , isRequestingVersion(false)
        , action(ActionKind::None)
        , flags(&defaultFlags) {

    }
};

void setCommandFlag(Command *command, const Flag *flag, char *value = NULL) {
    switch (flag->kind) {
        case FlagKind::Help:
            command->isRequestingHelp = true;
            return;
        case FlagKind::Version:
            command->isRequestingVersion = true;
            return;
        default:
            return;
    }
}

Command* parseCommandArguments(int argc, char* argv[]) {
    Command * command = new Command();

    // Flag to optimize has action parsing.
    bool hasAction = false;

    // The option flag that is pending for a value.
    const Flag * flagWhichAwaitsValue = NULL;

    for (int argIndex = 1; argIndex < argc; argIndex++) {
        auto arg = argv[argIndex];
        if (!hasAction) {
            for (auto const& a : actions) {
                if (strcmp(a.name->c_str(), arg) == 0) {
                    command->action = a.kind;
                    hasAction = true;
                    command->flags = a.flags;
                    break;
                }
            }
        }

        if (flagWhichAwaitsValue == NULL) {
            for (auto const& flag : *command->flags) {
                if (strcmp(flag.name->c_str(), arg) == 0 || (flag.alias->length() != 0 && strcmp(flag.name->c_str(), arg) == 0)) {
                    if (flag.hasValue) {
                        flagWhichAwaitsValue = &flag;
                    }
                    setCommandFlag(command, &flag);
                    break;
                }
            }
        }
        else {
            setCommandFlag(command, flagWhichAwaitsValue, arg);
            flagWhichAwaitsValue = NULL;
            continue;
        }
    }

    return command;
}

} // L10ns
<|endoftext|>


<commit_before>
#include <vector>
#include <string>

using namespace std;

namespace L10ns {

enum class ActionKind {
    None,
    Init,
    Update,
    Log,
    Set,
};

enum class FlagKind {
    None,
    Help,
    Version,
    Language,
    Key,
    Value,
};

struct Argument {
    string * name;
    string * description;

    Argument(string * pname, string * pdescription) {
        name = pname;
        description = pdescription;
    }
};

struct Flag : Argument {
    string * alias;
    bool hasValue;
    FlagKind kind;
    string value;

    Flag(FlagKind pkind, const char pname[], const char palias[], const char pdescription[], bool phasValue)
        : kind(pkind), Argument(new string(pname), new string(pdescription)), alias(new string(palias)) {

        hasValue = phasValue;
        value = "";
    }
};

struct Action : Argument {
    vector<Flag> * flags;
    ActionKind kind;
    string * info;

    Action(ActionKind pkind, const char pname[], const char pdescription[], const char pinfo[],vector<Flag> * pflags)
        : kind(pkind), Argument(new string(pname), new string(pdescription)), info(new string(pinfo)) {

        if (pflags != NULL) {
            flags = pflags;
        }
    }
};

static Flag helpFlag = Flag(FlagKind::Help, "--help", "-h", "Print help description.", /*hasValue*/ false);
static Flag languageFlag = Flag(FlagKind::Language, "--language", "-l", "Specify language.", false);

static vector<Flag> defaultFlags = {
    helpFlag,
    Flag(FlagKind::Version, "--version", "", "Print current version.", /*hasValue*/ false),
};

static vector<Flag> helpFlags = {
    helpFlag,
};

static vector<Flag> setFlags = {
    Flag(FlagKind::Key, "--key", "-k", "Specify localization key.", /*hasValue*/ true),
    Flag(FlagKind::Value, "--value", "-v", "Specify localization value.", /*hasValue*/ true),
    languageFlag,
    helpFlag,
};

static vector<Flag> logFlags = {
    languageFlag,
    helpFlag,
};

static const char * initInfo =
  "Initialize a L10ns project. This command creates on 'l10ns.json' "
  "file, with sane default options applied.";

static const char * updateInfo =
  "Initialize a L10ns project. This command creates on 'l10ns.json' "
  "file, with sane default options applied.";

static const char * logInfo =
  "Initialize a L10ns project. This command creates on 'l10ns.json' "
  "file, with sane default options applied.";

static const char * setInfo =
  "Initialize a L10ns project. This command creates on 'l10ns.json' "
  "file, with sane default options applied.";

static vector<Action> actions = {
    Action(ActionKind::Init, "init", "Initialize project.", initInfo, &helpFlags),
    Action(ActionKind::Update, "update", "Update localization keys.", updateInfo, &helpFlags),
    Action(ActionKind::Log, "log", "Show latest added localizations.", logInfo, &logFlags),
    Action(ActionKind::Set, "set", "Set localization.", setInfo, &setFlags),
};

struct Command {
    bool isRequestingHelp;
    bool isRequestingVersion;
    ActionKind action;
    vector<Flag> * flags;

    Command()
        : isRequestingHelp(false)
        , isRequestingVersion(false)
        , action(ActionKind::None)
        , flags(&defaultFlags) {

    }
};

void setCommandFlag(Command *command, const Flag *flag, char *value = NULL) {
    switch (flag->kind) {
        case FlagKind::Help:
            command->isRequestingHelp = true;
            return;
        case FlagKind::Version:
            command->isRequestingVersion = true;
            return;
        default:
            return;
    }
}

Command* parseCommandArguments(int argc, char* argv[]) {
    Command * command = new Command();

    // Flag to optimize has action parsing.
    bool hasAction = false;

    // The option flag that is pending for a value.
    const Flag * flagWhichAwaitsValue = NULL;

    for (int argIndex = 1; argIndex < argc; argIndex++) {
        auto arg = argv[argIndex];
        if (!hasAction) {
            for (auto const& a : actions) {
                if (strcmp(a.name->c_str(), arg) == 0) {
                    command->action = a.kind;
                    hasAction = true;
                    command->flags = a.flags;
                    break;
                }
            }
        }

        if (flagWhichAwaitsValue == NULL) {
            for (auto const& flag : *command->flags) {
                if (strcmp(flag.name->c_str(), arg) == 0 || (flag.alias->length() != 0 && strcmp(flag.name->c_str(), arg) == 0)) {
                    if (flag.hasValue) {
                        flagWhichAwaitsValue = &flag;
                    }
                    setCommandFlag(command, &flag);
                    break;
                }
            }
        }
        else {
            setCommandFlag(command, flagWhichAwaitsValue, arg);
            flagWhichAwaitsValue = NULL;
            continue;
        }
    }

    return command;
}

} // L10ns
<commit_msg>Fixes info<commit_after>
#include <vector>
#include <string>

using namespace std;

namespace L10ns {

enum class ActionKind {
    None,
    Init,
    Update,
    Log,
    Set,
};

enum class FlagKind {
    None,
    Help,
    Version,
    Language,
    Key,
    Value,
};

struct Argument {
    string * name;
    string * description;

    Argument(string * pname, string * pdescription) {
        name = pname;
        description = pdescription;
    }
};

struct Flag : Argument {
    string * alias;
    bool hasValue;
    FlagKind kind;
    string value;

    Flag(FlagKind pkind, const char pname[], const char palias[], const char pdescription[], bool phasValue)
        : kind(pkind), Argument(new string(pname), new string(pdescription)), alias(new string(palias)) {

        hasValue = phasValue;
        value = "";
    }
};

struct Action : Argument {
    vector<Flag> * flags;
    ActionKind kind;
    string * info;

    Action(ActionKind pkind, const char pname[], const char pdescription[], const char pinfo[],vector<Flag> * pflags)
        : kind(pkind), Argument(new string(pname), new string(pdescription)), info(new string(pinfo)) {

        if (pflags != NULL) {
            flags = pflags;
        }
    }
};

static Flag helpFlag = Flag(FlagKind::Help, "--help", "-h", "Print help description.", /*hasValue*/ false);
static Flag languageFlag = Flag(FlagKind::Language, "--language", "-l", "Specify language.", false);

static vector<Flag> defaultFlags = {
    helpFlag,
    Flag(FlagKind::Version, "--version", "", "Print current version.", /*hasValue*/ false),
};

static vector<Flag> helpFlags = {
    helpFlag,
};

static vector<Flag> setFlags = {
    Flag(FlagKind::Key, "--key", "-k", "Specify localization key.", /*hasValue*/ true),
    Flag(FlagKind::Value, "--value", "-v", "Specify localization value.", /*hasValue*/ true),
    languageFlag,
    helpFlag,
};

static vector<Flag> logFlags = {
    languageFlag,
    helpFlag,
};

static const char * initInfo =
  "Initialize a L10ns project. This command creates on 'l10ns.json' "
  "file, with sane default options applied.";

static const char * updateInfo =
  "Synchronize your keys between source code and storage.";

static const char * logInfo =
  "Show latest localizations.";

static const char * setInfo =
  "Set new localizations.";

static vector<Action> actions = {
    Action(ActionKind::Init, "init", "Initialize project.", initInfo, &helpFlags),
    Action(ActionKind::Update, "update", "Update localization keys.", updateInfo, &helpFlags),
    Action(ActionKind::Log, "log", "Show latest added localizations.", logInfo, &logFlags),
    Action(ActionKind::Set, "set", "Set localization.", setInfo, &setFlags),
};

struct Command {
    bool isRequestingHelp;
    bool isRequestingVersion;
    ActionKind action;
    vector<Flag> * flags;

    Command()
        : isRequestingHelp(false)
        , isRequestingVersion(false)
        , action(ActionKind::None)
        , flags(&defaultFlags) {

    }
};

void setCommandFlag(Command *command, const Flag *flag, char *value = NULL) {
    switch (flag->kind) {
        case FlagKind::Help:
            command->isRequestingHelp = true;
            return;
        case FlagKind::Version:
            command->isRequestingVersion = true;
            return;
        default:
            return;
    }
}

Command* parseCommandArguments(int argc, char* argv[]) {
    Command * command = new Command();

    // Flag to optimize has action parsing.
    bool hasAction = false;

    // The option flag that is pending for a value.
    const Flag * flagWhichAwaitsValue = NULL;

    for (int argIndex = 1; argIndex < argc; argIndex++) {
        auto arg = argv[argIndex];
        if (!hasAction) {
            for (auto const& a : actions) {
                if (strcmp(a.name->c_str(), arg) == 0) {
                    command->action = a.kind;
                    hasAction = true;
                    command->flags = a.flags;
                    break;
                }
            }
        }

        if (flagWhichAwaitsValue == NULL) {
            for (auto const& flag : *command->flags) {
                if (strcmp(flag.name->c_str(), arg) == 0 || (flag.alias->length() != 0 && strcmp(flag.name->c_str(), arg) == 0)) {
                    if (flag.hasValue) {
                        flagWhichAwaitsValue = &flag;
                    }
                    setCommandFlag(command, &flag);
                    break;
                }
            }
        }
        else {
            setCommandFlag(command, flagWhichAwaitsValue, arg);
            flagWhichAwaitsValue = NULL;
            continue;
        }
    }

    return command;
}

} // L10ns
<|endoftext|>


<commit_before>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>
#include <cstdlib>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "kernel/userver.hh"

#include "object/urbi-exception.hh"

#include "scheduler/scheduler.hh"
#include "scheduler/job.hh"

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job (void* job)
  {
    static_cast<Job*>(job)->run();
  }

  void
  Scheduler::add_job (Job* job)
  {
    assert (job);
    assert (!libport::has (jobs_, job));
    assert (!libport::has (jobs_to_start_, job));
    jobs_to_start_.push_back (job);
  }

  libport::utime_t
  Scheduler::work ()
  {
#ifdef ENABLE_DEBUG_TRACES
    static int cycle = 0;
#endif
    ECHO ("======================================================== cycle "
	  << ++cycle);

    // Start new jobs. You may note that to_kill_ is reset at the beginning
    // of each loop and one final time at the end. This is to ensure that
    // we are not trying to clear the job on which we are iterating (it
    // may only be set to a reference onto the latest scheduled job).
    to_start_.clear ();
    std::swap (to_start_, jobs_to_start_);
    foreach (Job* job, to_start_)
    {
      to_kill_ = 0;
      assert (job);
      ECHO ("will start job " << *job);
      // Job will start for a very short time and do a yield_front() to
      // be restarted below in the course of the regular cycle.
      assert (!current_job_);
      current_job_ = job;
      Coro_startCoro_ (self_, job->coro_get(), job, run_job);
      // We have to assume that a new job may have had side-effects.
      possible_side_effect_ = true;
    }

    // Start deferred jobs
    for (libport::utime_t current_time = ::urbiserver->getTime ();
	 !deferred_jobs_.empty();
	 deferred_jobs_.pop ())
    {
      deferred_job j = deferred_jobs_.top ();
      if (current_time < j.get<0>())
	break;
      jobs_.push_back (j.get<1> ());
    }

    // If something is going to happen, or if we have just started a
    // new job, add the list of jobs waiting for something to happen
    // on the pending jobs queue.
    if (!if_change_jobs_.empty() && (possible_side_effect_ || !jobs_.empty()))
    {
      foreach (Job* job, if_change_jobs_)
	jobs_.push_back (job);
      if_change_jobs_.clear ();
    }

    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    possible_side_effect_ = false;
    pending_.clear ();
    std::swap (pending_, jobs_);

    ECHO (pending_.size() << " jobs in the queue for this cycle");
    foreach (Job* job, pending_)
    {
      // Kill a job if needed. See explanation in job.hh.
      to_kill_ = 0;

      assert (job);
      assert (!job->terminated ());
      ECHO ("will resume job " << *job << (job->side_effect_free_get() ? " (side-effect free)" : ""));
      possible_side_effect_ |= !job->side_effect_free_get ();
      assert (!current_job_);
      Coro_switchTo_ (self_, job->coro_get ());
      assert (!current_job_);
      possible_side_effect_ |= !job->side_effect_free_get ();
      ECHO ("back from job " << *job << (job->side_effect_free_get() ? " (side-effect free)" : ""));
    }
    // Kill a job if needed. See explanation in job.hh.
    to_kill_ = 0;

    // Do we have some work to do now?
    if (!jobs_.empty () || !jobs_to_start_.empty())
    {
      ECHO ("scheduler: asking to be recalled ASAP, " << jobs_.size() << " jobs ready and " << jobs_to_start_.size()
	    << " to start");
      return 0;
    }

    // Do we have deferred jobs?
    if (!deferred_jobs_.empty ())
    {
      ECHO ("scheduler: asking to be recalled later");
      return deferred_jobs_.top ().get<0> ();
    }

    // Ok, let's say, we'll be called again in one hour.
    ECHO ("scheduler: asking to be recalled in a long time");
    return ::urbiserver->getTime() + 3600000000LL;
  }

  void
  Scheduler::switch_back (Job* job)
  {
    // Switch back to the scheduler.
    assert (current_job_ == job);
    current_job_ = 0;
    Coro_switchTo_ (job->coro_get (), self_);
    // We regained control, we are again in the context of the job.
    assert (!current_job_);
    current_job_ = job;
    ECHO ("job " << *job << " resumed");
    // Check that we are not near exhausting the stack space.
    job->check_stack_space ();
    // Execute a deferred exception if any
    job->check_for_pending_exception ();
  }

  void
  Scheduler::resume_scheduler (Job* job)
  {
    // If the job has not terminated, put it at the back of the run queue
    // so that the run queue order is preserved between work cycles.
    if (!job->terminated ())
      jobs_.push_back (job);
    ECHO (*job << " has " << (job->terminated () ? "" : "not ") << "terminated");
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_front (Job* job)
  {
    // Put the job in front of the queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    jobs_.push_front (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_until (Job* job, libport::utime_t deadline)
  {
    // Put the job in the deferred queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    deferred_jobs_.push (boost::make_tuple (deadline, job));
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_suspend (Job* job)
  {
    suspended_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_things_changed (Job* job)
  {
    if_change_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_job (Job* job)
  {
    // Suspended job may have been killed externally, in which case it
    // will not appear in the list of suspended jobs.

    if (libport::has (suspended_jobs_, job))
    {
      jobs_.push_back (job);
      suspended_jobs_.remove (job);
    }
  }

  void
  Scheduler::killall_jobs ()
  {
    ECHO ("killing all jobs!");

    // This implementation is quite inefficient because it will call
    // kill_job() for each job. But who cares? We are killing everyone
    // anyway.

    while (!jobs_to_start_.empty ())
      jobs_to_start_.pop_front ();

    while (!suspended_jobs_.empty ())
      kill_job (suspended_jobs_.front ());

    while (!if_change_jobs_.empty ())
      kill_job (if_change_jobs_.front ());

    while (!jobs_.empty ())
      kill_job (jobs_.front ());

    while (!deferred_jobs_.empty ())
      kill_job (deferred_jobs_.top ().get<1>());
  }

  void
  Scheduler::unschedule_job (Job* job)
  {
    assert (job);
    assert (job != current_job_);

    ECHO ("unscheduling job " << *job);

    // Remove the job from the queues where it could be stored.
    jobs_to_start_.remove (job);
    jobs_.remove (job);
    suspended_jobs_.remove (job);
    if_change_jobs_.remove (job);

    // Remove it from live queues as well if the job is destroyed.
    to_start_.remove (job);
    pending_.remove (job);

    // We have no remove() on a priority queue, regenerate a queue without
    // this job.
    {
      deferred_jobs old_deferred;
      std::swap (old_deferred, deferred_jobs_);
      while (!old_deferred.empty ())
      {
	deferred_job j = old_deferred.top ();
	old_deferred.pop ();
	if (j.get<1>() != job)
	  deferred_jobs_.push (j);
      }
    }
  }

  void
  Scheduler::kill_job (Job* job)
  {
    assert (job != current_job_);

    ECHO ("deleting job " << *job);
    delete job;
  }

  bool operator> (const deferred_job& left, const deferred_job& right)
  {
    return left.get<0>() > right.get<0>();
  }

} // namespace scheduler
<commit_msg>Do not yield() on side-effect-free jobs<commit_after>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>
#include <cstdlib>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "kernel/userver.hh"

#include "object/urbi-exception.hh"

#include "scheduler/scheduler.hh"
#include "scheduler/job.hh"

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job (void* job)
  {
    static_cast<Job*>(job)->run();
  }

  void
  Scheduler::add_job (Job* job)
  {
    assert (job);
    assert (!libport::has (jobs_, job));
    assert (!libport::has (jobs_to_start_, job));
    jobs_to_start_.push_back (job);
  }

  libport::utime_t
  Scheduler::work ()
  {
#ifdef ENABLE_DEBUG_TRACES
    static int cycle = 0;
#endif
    ECHO ("======================================================== cycle "
	  << ++cycle);

    // Start new jobs. You may note that to_kill_ is reset at the beginning
    // of each loop and one final time at the end. This is to ensure that
    // we are not trying to clear the job on which we are iterating (it
    // may only be set to a reference onto the latest scheduled job).
    to_start_.clear ();
    std::swap (to_start_, jobs_to_start_);
    foreach (Job* job, to_start_)
    {
      to_kill_ = 0;
      assert (job);
      ECHO ("will start job " << *job);
      // Job will start for a very short time and do a yield_front() to
      // be restarted below in the course of the regular cycle.
      assert (!current_job_);
      current_job_ = job;
      Coro_startCoro_ (self_, job->coro_get(), job, run_job);
      // We have to assume that a new job may have had side-effects.
      possible_side_effect_ = true;
    }

    // Start deferred jobs
    for (libport::utime_t current_time = ::urbiserver->getTime ();
	 !deferred_jobs_.empty();
	 deferred_jobs_.pop ())
    {
      deferred_job j = deferred_jobs_.top ();
      if (current_time < j.get<0>())
	break;
      jobs_.push_back (j.get<1> ());
    }

    // If something is going to happen, or if we have just started a
    // new job, add the list of jobs waiting for something to happen
    // on the pending jobs queue.
    if (!if_change_jobs_.empty() && (possible_side_effect_ || !jobs_.empty()))
    {
      foreach (Job* job, if_change_jobs_)
	jobs_.push_back (job);
      if_change_jobs_.clear ();
    }

    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    possible_side_effect_ = false;
    pending_.clear ();
    std::swap (pending_, jobs_);

    ECHO (pending_.size() << " jobs in the queue for this cycle");
    foreach (Job* job, pending_)
    {
      // Kill a job if needed. See explanation in job.hh.
      to_kill_ = 0;

      assert (job);
      assert (!job->terminated ());
      ECHO ("will resume job " << *job << (job->side_effect_free_get() ? " (side-effect free)" : ""));
      possible_side_effect_ |= !job->side_effect_free_get ();
      assert (!current_job_);
      Coro_switchTo_ (self_, job->coro_get ());
      assert (!current_job_);
      possible_side_effect_ |= !job->side_effect_free_get ();
      ECHO ("back from job " << *job << (job->side_effect_free_get() ? " (side-effect free)" : ""));
    }
    // Kill a job if needed. See explanation in job.hh.
    to_kill_ = 0;

    // Do we have some work to do now?
    if (!jobs_.empty () || !jobs_to_start_.empty())
    {
      ECHO ("scheduler: asking to be recalled ASAP, " << jobs_.size() << " jobs ready and " << jobs_to_start_.size()
	    << " to start");
      return 0;
    }

    // Do we have deferred jobs?
    if (!deferred_jobs_.empty ())
    {
      ECHO ("scheduler: asking to be recalled later");
      return deferred_jobs_.top ().get<0> ();
    }

    // Ok, let's say, we'll be called again in one hour.
    ECHO ("scheduler: asking to be recalled in a long time");
    return ::urbiserver->getTime() + 3600000000LL;
  }

  void
  Scheduler::switch_back (Job* job)
  {
    // Switch back to the scheduler.
    assert (current_job_ == job);
    current_job_ = 0;
    Coro_switchTo_ (job->coro_get (), self_);
    // We regained control, we are again in the context of the job.
    assert (!current_job_);
    current_job_ = job;
    ECHO ("job " << *job << " resumed");
    // Check that we are not near exhausting the stack space.
    job->check_stack_space ();
    // Execute a deferred exception if any
    job->check_for_pending_exception ();
  }

  void
  Scheduler::resume_scheduler (Job* job)
  {
    // If the job has not terminated and is side-effect free, then we
    // assume it will not take a long time as we are probably evaluating
    // a condition. In order to reduce the number of cycles spent to evaluate
    // the condition, continue until it asks to be suspended in another
    // way or until it is no longer side-effect free.

    if (!job->terminated () && job->side_effect_free_get ())
      return;

    // If the job has not terminated, put it at the back of the run queue
    // so that the run queue order is preserved between work cycles.
    if (!job->terminated ())
      jobs_.push_back (job);
    ECHO (*job << " has " << (job->terminated () ? "" : "not ") << "terminated");
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_front (Job* job)
  {
    // Put the job in front of the queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    jobs_.push_front (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_until (Job* job, libport::utime_t deadline)
  {
    // Put the job in the deferred queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    deferred_jobs_.push (boost::make_tuple (deadline, job));
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_suspend (Job* job)
  {
    suspended_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_things_changed (Job* job)
  {
    if_change_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_job (Job* job)
  {
    // Suspended job may have been killed externally, in which case it
    // will not appear in the list of suspended jobs.

    if (libport::has (suspended_jobs_, job))
    {
      jobs_.push_back (job);
      suspended_jobs_.remove (job);
    }
  }

  void
  Scheduler::killall_jobs ()
  {
    ECHO ("killing all jobs!");

    // This implementation is quite inefficient because it will call
    // kill_job() for each job. But who cares? We are killing everyone
    // anyway.

    while (!jobs_to_start_.empty ())
      jobs_to_start_.pop_front ();

    while (!suspended_jobs_.empty ())
      kill_job (suspended_jobs_.front ());

    while (!if_change_jobs_.empty ())
      kill_job (if_change_jobs_.front ());

    while (!jobs_.empty ())
      kill_job (jobs_.front ());

    while (!deferred_jobs_.empty ())
      kill_job (deferred_jobs_.top ().get<1>());
  }

  void
  Scheduler::unschedule_job (Job* job)
  {
    assert (job);
    assert (job != current_job_);

    ECHO ("unscheduling job " << *job);

    // Remove the job from the queues where it could be stored.
    jobs_to_start_.remove (job);
    jobs_.remove (job);
    suspended_jobs_.remove (job);
    if_change_jobs_.remove (job);

    // Remove it from live queues as well if the job is destroyed.
    to_start_.remove (job);
    pending_.remove (job);

    // We have no remove() on a priority queue, regenerate a queue without
    // this job.
    {
      deferred_jobs old_deferred;
      std::swap (old_deferred, deferred_jobs_);
      while (!old_deferred.empty ())
      {
	deferred_job j = old_deferred.top ();
	old_deferred.pop ();
	if (j.get<1>() != job)
	  deferred_jobs_.push (j);
      }
    }
  }

  void
  Scheduler::kill_job (Job* job)
  {
    assert (job != current_job_);

    ECHO ("deleting job " << *job);
    delete job;
  }

  bool operator> (const deferred_job& left, const deferred_job& right)
  {
    return left.get<0>() > right.get<0>();
  }

} // namespace scheduler
<|endoftext|>