<commit_before>//===-- asan_linux.cc -----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Linux-specific details.
//===----------------------------------------------------------------------===//
#ifdef __linux__

#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_lock.h"
#include "asan_procmaps.h"
#include "asan_thread.h"

#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <unwind.h>

#ifndef ANDROID
// FIXME: where to get ucontext on Android?
#include <sys/ucontext.h>
#endif

extern "C" void* _DYNAMIC;

namespace __asan {

const size_t kMaxThreadStackSize = 256 * (1 << 20);  // 256M

void *AsanDoesNotSupportStaticLinkage() {
  // This will fail to link with -static.
  return &_DYNAMIC;  // defined in link.h
}

bool AsanShadowRangeIsAvailable() {
  // FIXME: shall we need anything here on Linux?
  return true;
}

void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) {
#ifdef ANDROID
  *pc = *sp = *bp = 0;
#elif defined(__arm__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.arm_pc;
  *bp = ucontext->uc_mcontext.arm_fp;
  *sp = ucontext->uc_mcontext.arm_sp;
# elif defined(__x86_64__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
# elif defined(__i386__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
#else
# error "Unsupported arch"
#endif
}

bool AsanInterceptsSignal(int signum) {
  return signum == SIGSEGV && FLAG_handle_segv;
}

static void *asan_mmap(void *addr, size_t length, int prot, int flags,
                int fd, uint64_t offset) {
# if __WORDSIZE == 64
  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
# else
  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
# endif
}

void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
  size = RoundUpTo(size, kPageSize);
  void *res = asan_mmap(0, size,
                        PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANON, -1, 0);
  if (res == (void*)-1) {
    OutOfMemoryMessageAndDie(mem_type, size);
  }
  return res;
}

void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
  return asan_mmap((void*)fixed_addr, size,
                   PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
                   0, 0);
}

void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
  return asan_mmap((void*)fixed_addr, size,
                   PROT_NONE,
                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
                   0, 0);
}

void AsanUnmapOrDie(void *addr, size_t size) {
  if (!addr || !size) return;
  int res = syscall(__NR_munmap, addr, size);
  if (res != 0) {
    Report("Failed to unmap\n");
    AsanDie();
  }
}

size_t AsanWrite(int fd, const void *buf, size_t count) {
  return (size_t)syscall(__NR_write, fd, buf, count);
}

int AsanOpenReadonly(const char* filename) {
  return syscall(__NR_open, filename, O_RDONLY);
}

// Like getenv, but reads env directly from /proc and does not use libc.
// This function should be called first inside __asan_init.
const char* AsanGetEnv(const char* name) {
  static char *environ;
  static size_t len;
  static bool inited;
  if (!inited) {
    inited = true;
    size_t environ_size;
    len = ReadFileToBuffer("/proc/self/environ",
                           &environ, &environ_size, 1 << 26);
  }
  if (!environ || len == 0) return NULL;
  size_t namelen = internal_strlen(name);
  const char *p = environ;
  while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    const char* endp =
        (char*)internal_memchr(p, '\0', len - (p - environ));
    if (endp == NULL)  // this entry isn't NUL terminated
      return NULL;
    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
      return p + namelen + 1;  // point after =
    p = endp + 1;
  }
  return NULL;  // Not found.
}

size_t AsanRead(int fd, void *buf, size_t count) {
  return (size_t)syscall(__NR_read, fd, buf, count);
}

int AsanClose(int fd) {
  return syscall(__NR_close, fd);
}

AsanProcMaps::AsanProcMaps() {
  proc_self_maps_buff_len_ =
      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
                       &proc_self_maps_buff_mmaped_size_, 1 << 26);
  CHECK(proc_self_maps_buff_len_ > 0);
  // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
  Reset();
}

AsanProcMaps::~AsanProcMaps() {
  AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
}

void AsanProcMaps::Reset() {
  current_ = proc_self_maps_buff_;
}

bool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end,
                        uintptr_t *offset, char filename[],
                        size_t filename_size) {
  char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
  if (current_ >= last) return false;
  int consumed = 0;
  char flags[10];
  int major, minor;
  uintptr_t inode;
  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
  if (next_line == NULL)
    next_line = last;
  if (SScanf(current_,
             "%lx-%lx %4s %lx %x:%x %ld %n",
             start, end, flags, offset, &major, &minor,
             &inode, &consumed) != 7)
    return false;
  current_ += consumed;
  // Skip spaces.
  while (current_ < next_line && *current_ == ' ')
    current_++;
  // Fill in the filename.
  size_t i = 0;
  while (current_ < next_line) {
    if (filename && i < filename_size - 1)
      filename[i++] = *current_;
    current_++;
  }
  if (filename && i < filename_size)
    filename[i] = 0;
  current_ = next_line + 1;
  return true;
}

// Gets the object name and the offset by walking AsanProcMaps.
bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
                                          char filename[],
                                          size_t filename_size) {
  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
}

void AsanThread::SetThreadStackTopAndBottom() {
  if (tid() == 0) {
    // This is the main thread. Libpthread may not be initialized yet.
    struct rlimit rl;
    CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);

    // Find the mapping that contains a stack variable.
    AsanProcMaps proc_maps;
    uintptr_t start, end, offset;
    uintptr_t prev_end = 0;
    while (proc_maps.Next(&start, &end, &offset, NULL, 0)) {
      if ((uintptr_t)&rl < end)
        break;
      prev_end = end;
    }
    CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end);

    // Get stacksize from rlimit, but clip it so that it does not overlap
    // with other mappings.
    size_t stacksize = rl.rlim_cur;
    if (stacksize > end - prev_end)
      stacksize = end - prev_end;
    // When running with unlimited stack size, we still want to set some limit.
    // The unlimited stack size is caused by 'ulimit -s unlimited'.
    // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
    if (stacksize > kMaxThreadStackSize)
      stacksize = kMaxThreadStackSize;
    stack_top_ = end;
    stack_bottom_ = end - stacksize;
    CHECK(AddrIsInStack((uintptr_t)&rl));
    return;
  }
  pthread_attr_t attr;
  CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
  size_t stacksize = 0;
  void *stackaddr = NULL;
  pthread_attr_getstack(&attr, &stackaddr, &stacksize);
  pthread_attr_destroy(&attr);

  stack_top_ = (uintptr_t)stackaddr + stacksize;
  stack_bottom_ = (uintptr_t)stackaddr;
  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
  CHECK(AddrIsInStack((uintptr_t)&attr));
}

AsanLock::AsanLock(LinkerInitialized) {
  // We assume that pthread_mutex_t initialized to all zeroes is a valid
  // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
  // a gcc warning:
  // extended initializer lists only available with -std=c++0x or -std=gnu++0x
}

void AsanLock::Lock() {
  CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_));
  pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_);
  CHECK(!owner_);
  owner_ = (uintptr_t)pthread_self();
}

void AsanLock::Unlock() {
  CHECK(owner_ == (uintptr_t)pthread_self());
  owner_ = 0;
  pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
}

#ifdef __arm__
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif

uintptr_t Unwind_GetIP(struct _Unwind_Context *ctx) {
#ifdef __arm__
  uintptr_t val;
  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
      15 /* r15 = PC */, _UVRSD_UINT32, &val);
  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
  // Clear the Thumb bit.
  return val & ~(uintptr_t)1;
#else
  return _Unwind_GetIP(ctx);
#endif
}

_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
    void *param) {
  AsanStackTrace *b = (AsanStackTrace*)param;
  CHECK(b->size < b->max_size);
  uintptr_t pc = Unwind_GetIP(ctx);
  b->trace[b->size++] = pc;
  if (b->size == b->max_size) return UNWIND_STOP;
  return UNWIND_CONTINUE;
}

void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
  size = 0;
  trace[0] = pc;
  if ((max_s) > 1) {
    max_size = max_s;
#ifdef __arm__
    _Unwind_Backtrace(Unwind_Trace, this);
#else
     FastUnwindStack(pc, bp);
#endif
  }
}

}  // namespace __asan

#endif  // __linux__
<commit_msg>asan: fix typo in comment<commit_after>//===-- asan_linux.cc -----------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// Linux-specific details.
//===----------------------------------------------------------------------===//
#ifdef __linux__

#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_lock.h"
#include "asan_procmaps.h"
#include "asan_thread.h"

#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <unwind.h>

#ifndef ANDROID
// FIXME: where to get ucontext on Android?
#include <sys/ucontext.h>
#endif

extern "C" void* _DYNAMIC;

namespace __asan {

const size_t kMaxThreadStackSize = 256 * (1 << 20);  // 256M

void *AsanDoesNotSupportStaticLinkage() {
  // This will fail to link with -static.
  return &_DYNAMIC;  // defined in link.h
}

bool AsanShadowRangeIsAvailable() {
  // FIXME: shall we need anything here on Linux?
  return true;
}

void GetPcSpBp(void *context, uintptr_t *pc, uintptr_t *sp, uintptr_t *bp) {
#ifdef ANDROID
  *pc = *sp = *bp = 0;
#elif defined(__arm__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.arm_pc;
  *bp = ucontext->uc_mcontext.arm_fp;
  *sp = ucontext->uc_mcontext.arm_sp;
# elif defined(__x86_64__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
# elif defined(__i386__)
  ucontext_t *ucontext = (ucontext_t*)context;
  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
#else
# error "Unsupported arch"
#endif
}

bool AsanInterceptsSignal(int signum) {
  return signum == SIGSEGV && FLAG_handle_segv;
}

static void *asan_mmap(void *addr, size_t length, int prot, int flags,
                int fd, uint64_t offset) {
# if __WORDSIZE == 64
  return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
# else
  return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
# endif
}

void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
  size = RoundUpTo(size, kPageSize);
  void *res = asan_mmap(0, size,
                        PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANON, -1, 0);
  if (res == (void*)-1) {
    OutOfMemoryMessageAndDie(mem_type, size);
  }
  return res;
}

void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
  return asan_mmap((void*)fixed_addr, size,
                   PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
                   0, 0);
}

void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
  return asan_mmap((void*)fixed_addr, size,
                   PROT_NONE,
                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
                   0, 0);
}

void AsanUnmapOrDie(void *addr, size_t size) {
  if (!addr || !size) return;
  int res = syscall(__NR_munmap, addr, size);
  if (res != 0) {
    Report("Failed to unmap\n");
    AsanDie();
  }
}

size_t AsanWrite(int fd, const void *buf, size_t count) {
  return (size_t)syscall(__NR_write, fd, buf, count);
}

int AsanOpenReadonly(const char* filename) {
  return syscall(__NR_open, filename, O_RDONLY);
}

// Like getenv, but reads env directly from /proc and does not use libc.
// This function should be called first inside __asan_init.
const char* AsanGetEnv(const char* name) {
  static char *environ;
  static size_t len;
  static bool inited;
  if (!inited) {
    inited = true;
    size_t environ_size;
    len = ReadFileToBuffer("/proc/self/environ",
                           &environ, &environ_size, 1 << 26);
  }
  if (!environ || len == 0) return NULL;
  size_t namelen = internal_strlen(name);
  const char *p = environ;
  while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    const char* endp =
        (char*)internal_memchr(p, '\0', len - (p - environ));
    if (endp == NULL)  // this entry isn't NUL terminated
      return NULL;
    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
      return p + namelen + 1;  // point after =
    p = endp + 1;
  }
  return NULL;  // Not found.
}

size_t AsanRead(int fd, void *buf, size_t count) {
  return (size_t)syscall(__NR_read, fd, buf, count);
}

int AsanClose(int fd) {
  return syscall(__NR_close, fd);
}

AsanProcMaps::AsanProcMaps() {
  proc_self_maps_buff_len_ =
      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
                       &proc_self_maps_buff_mmaped_size_, 1 << 26);
  CHECK(proc_self_maps_buff_len_ > 0);
  // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
  Reset();
}

AsanProcMaps::~AsanProcMaps() {
  AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
}

void AsanProcMaps::Reset() {
  current_ = proc_self_maps_buff_;
}

bool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end,
                        uintptr_t *offset, char filename[],
                        size_t filename_size) {
  char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
  if (current_ >= last) return false;
  int consumed = 0;
  char flags[10];
  int major, minor;
  uintptr_t inode;
  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
  if (next_line == NULL)
    next_line = last;
  if (SScanf(current_,
             "%lx-%lx %4s %lx %x:%x %ld %n",
             start, end, flags, offset, &major, &minor,
             &inode, &consumed) != 7)
    return false;
  current_ += consumed;
  // Skip spaces.
  while (current_ < next_line && *current_ == ' ')
    current_++;
  // Fill in the filename.
  size_t i = 0;
  while (current_ < next_line) {
    if (filename && i < filename_size - 1)
      filename[i++] = *current_;
    current_++;
  }
  if (filename && i < filename_size)
    filename[i] = 0;
  current_ = next_line + 1;
  return true;
}

// Gets the object name and the offset by walking AsanProcMaps.
bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
                                          char filename[],
                                          size_t filename_size) {
  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
}

void AsanThread::SetThreadStackTopAndBottom() {
  if (tid() == 0) {
    // This is the main thread. Libpthread may not be initialized yet.
    struct rlimit rl;
    CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);

    // Find the mapping that contains a stack variable.
    AsanProcMaps proc_maps;
    uintptr_t start, end, offset;
    uintptr_t prev_end = 0;
    while (proc_maps.Next(&start, &end, &offset, NULL, 0)) {
      if ((uintptr_t)&rl < end)
        break;
      prev_end = end;
    }
    CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end);

    // Get stacksize from rlimit, but clip it so that it does not overlap
    // with other mappings.
    size_t stacksize = rl.rlim_cur;
    if (stacksize > end - prev_end)
      stacksize = end - prev_end;
    // When running with unlimited stack size, we still want to set some limit.
    // The unlimited stack size is caused by 'ulimit -s unlimited'.
    // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
    if (stacksize > kMaxThreadStackSize)
      stacksize = kMaxThreadStackSize;
    stack_top_ = end;
    stack_bottom_ = end - stacksize;
    CHECK(AddrIsInStack((uintptr_t)&rl));
    return;
  }
  pthread_attr_t attr;
  CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
  size_t stacksize = 0;
  void *stackaddr = NULL;
  pthread_attr_getstack(&attr, &stackaddr, &stacksize);
  pthread_attr_destroy(&attr);

  stack_top_ = (uintptr_t)stackaddr + stacksize;
  stack_bottom_ = (uintptr_t)stackaddr;
  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
  CHECK(AddrIsInStack((uintptr_t)&attr));
}

AsanLock::AsanLock(LinkerInitialized) {
  // We assume that pthread_mutex_t initialized to all zeroes is a valid
  // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
  // a gcc warning:
  // extended initializer lists only available with -std=c++0x or -std=gnu++0x
}

void AsanLock::Lock() {
  CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_));
  pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_);
  CHECK(!owner_);
  owner_ = (uintptr_t)pthread_self();
}

void AsanLock::Unlock() {
  CHECK(owner_ == (uintptr_t)pthread_self());
  owner_ = 0;
  pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
}

#ifdef __arm__
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
#define UNWIND_STOP _URC_NORMAL_STOP
#define UNWIND_CONTINUE _URC_NO_REASON
#endif

uintptr_t Unwind_GetIP(struct _Unwind_Context *ctx) {
#ifdef __arm__
  uintptr_t val;
  _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
      15 /* r15 = PC */, _UVRSD_UINT32, &val);
  CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
  // Clear the Thumb bit.
  return val & ~(uintptr_t)1;
#else
  return _Unwind_GetIP(ctx);
#endif
}

_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
    void *param) {
  AsanStackTrace *b = (AsanStackTrace*)param;
  CHECK(b->size < b->max_size);
  uintptr_t pc = Unwind_GetIP(ctx);
  b->trace[b->size++] = pc;
  if (b->size == b->max_size) return UNWIND_STOP;
  return UNWIND_CONTINUE;
}

void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
  size = 0;
  trace[0] = pc;
  if ((max_s) > 1) {
    max_size = max_s;
#ifdef __arm__
    _Unwind_Backtrace(Unwind_Trace, this);
#else
     FastUnwindStack(pc, bp);
#endif
  }
}

}  // namespace __asan

#endif  // __linux__
<|endoftext|>


<commit_before>// Copyright (C) 2015 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Window.h"
#include "Engine.h"
#include "InputWin.h"

using namespace ouzel;

static KeyboardKey winKeyToEngineCode(WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
        case VK_CANCEL: return KeyboardKey::CANCEL;
        case VK_BACK: return KeyboardKey::BACKSPACE;
        case VK_TAB: return KeyboardKey::TAB;
        case VK_CLEAR: return KeyboardKey::CLEAR;
        case VK_RETURN: return KeyboardKey::RETURN;
        case VK_SHIFT: return KeyboardKey::SHIFT;
        case VK_CONTROL: return KeyboardKey::CONTROL;
        case VK_MENU: return KeyboardKey::MENU;
        case VK_PAUSE: return KeyboardKey::PAUSE;
        case VK_CAPITAL: return KeyboardKey::CAPITAL;

            // ... Japanese ...

        case VK_ESCAPE: return KeyboardKey::ESCAPE;

            // ... IME ...

        case VK_SPACE: return KeyboardKey::SPACE;
        case VK_PRIOR: return KeyboardKey::PRIOR;
        case VK_NEXT: return KeyboardKey::NEXT;
        case VK_END: return KeyboardKey::END;
        case VK_HOME: return KeyboardKey::HOME;
        case VK_LEFT: return KeyboardKey::LEFT;
        case VK_UP: return KeyboardKey::UP;
        case VK_RIGHT: return KeyboardKey::RIGHT;
        case VK_DOWN: return KeyboardKey::DOWN;

        case VK_SELECT: return KeyboardKey::SELECT;
        case VK_PRINT: return KeyboardKey::PRINT;
        case VK_EXECUTE: return KeyboardKey::EXECUT;

        case VK_SNAPSHOT: return KeyboardKey::SNAPSHOT;
        case VK_INSERT: return KeyboardKey::INSERT;
        case VK_DELETE: return KeyboardKey::DEL;
        case VK_HELP: return KeyboardKey::HELP;

        case '0': return KeyboardKey::KEY_0;
        case '1': return KeyboardKey::KEY_1;
        case '2': return KeyboardKey::KEY_2;
        case '3': return KeyboardKey::KEY_3;
        case '4': return KeyboardKey::KEY_4;
        case '5': return KeyboardKey::KEY_5;
        case '6': return KeyboardKey::KEY_6;
        case '7': return KeyboardKey::KEY_7;
        case '8': return KeyboardKey::KEY_8;
        case '9': return KeyboardKey::KEY_9;

        case 'A': return KeyboardKey::KEY_A;
        case 'B': return KeyboardKey::KEY_B;
        case 'C': return KeyboardKey::KEY_C;
        case 'D': return KeyboardKey::KEY_D;
        case 'E': return KeyboardKey::KEY_E;
        case 'F': return KeyboardKey::KEY_F;
        case 'G': return KeyboardKey::KEY_G;
        case 'H': return KeyboardKey::KEY_H;
        case 'I': return KeyboardKey::KEY_I;
        case 'J': return KeyboardKey::KEY_J;
        case 'K': return KeyboardKey::KEY_K;
        case 'L': return KeyboardKey::KEY_L;
        case 'M': return KeyboardKey::KEY_M;
        case 'N': return KeyboardKey::KEY_N;
        case 'O': return KeyboardKey::KEY_O;
        case 'P': return KeyboardKey::KEY_P;
        case 'Q': return KeyboardKey::KEY_Q;
        case 'R': return KeyboardKey::KEY_R;
        case 'S': return KeyboardKey::KEY_S;
        case 'T': return KeyboardKey::KEY_T;
        case 'U': return KeyboardKey::KEY_U;
        case 'V': return KeyboardKey::KEY_V;
        case 'W': return KeyboardKey::KEY_W;
        case 'X': return KeyboardKey::KEY_X;
        case 'Y': return KeyboardKey::KEY_Y;
        case 'Z': return KeyboardKey::KEY_Z;

        case VK_LWIN: return KeyboardKey::LWIN;
        case VK_RWIN: return KeyboardKey::RWIN;
        case VK_APPS: return KeyboardKey::MENU;
        case VK_SLEEP: return KeyboardKey::SLEEP;

        case VK_NUMPAD0: return KeyboardKey::NUMPAD0;
        case VK_NUMPAD1: return KeyboardKey::NUMPAD1;
        case VK_NUMPAD2: return KeyboardKey::NUMPAD2;
        case VK_NUMPAD3: return KeyboardKey::NUMPAD3;
        case VK_NUMPAD4: return KeyboardKey::NUMPAD4;
        case VK_NUMPAD5: return KeyboardKey::NUMPAD5;
        case VK_NUMPAD6: return KeyboardKey::NUMPAD6;
        case VK_NUMPAD7: return KeyboardKey::NUMPAD7;
        case VK_NUMPAD8: return KeyboardKey::NUMPAD8;
        case VK_NUMPAD9: return KeyboardKey::NUMPAD9;

        case VK_MULTIPLY: return KeyboardKey::MULTIPLY;
        case VK_ADD: return KeyboardKey::ADD;
        case VK_SEPARATOR: return KeyboardKey::SEPARATOR;
        case VK_SUBTRACT: return KeyboardKey::SUBTRACT;
        case VK_DECIMAL: return KeyboardKey::DECIMAL;
        case VK_DIVIDE: return KeyboardKey::DIVIDE;

        case VK_F1: return KeyboardKey::F1;
        case VK_F2: return KeyboardKey::F2;
        case VK_F3: return KeyboardKey::F3;
        case VK_F4: return KeyboardKey::F4;
        case VK_F5: return KeyboardKey::F5;
        case VK_F6: return KeyboardKey::F6;
        case VK_F7: return KeyboardKey::F7;
        case VK_F8: return KeyboardKey::F8;
        case VK_F9: return KeyboardKey::F9;
        case VK_F10: return KeyboardKey::F10;
        case VK_F11: return KeyboardKey::F11;
        case VK_F12: return KeyboardKey::F12;
        case VK_F13: return KeyboardKey::F13;
        case VK_F14: return KeyboardKey::F14;
        case VK_F15: return KeyboardKey::F15;
        case VK_F16: return KeyboardKey::F16;
        case VK_F17: return KeyboardKey::F17;
        case VK_F18: return KeyboardKey::F18;
        case VK_F19: return KeyboardKey::F19;
        case VK_F20: return KeyboardKey::F20;
        case VK_F21: return KeyboardKey::F21;
        case VK_F22: return KeyboardKey::F22;
        case VK_F23: return KeyboardKey::F23;
        case VK_F24: return KeyboardKey::F24;

        case VK_NUMLOCK: return KeyboardKey::NUMLOCK;
        case VK_SCROLL: return KeyboardKey::SCROLL;
        case VK_LSHIFT: return KeyboardKey::LSHIFT;
        case VK_RSHIFT: return KeyboardKey::RSHIFT;
        case VK_LCONTROL: return KeyboardKey::LCONTROL;
        case VK_RCONTROL: return KeyboardKey::RCONTROL;
        case VK_LMENU: return KeyboardKey::LMENU;
        case VK_RMENU: return KeyboardKey::RMENU;

        case VK_OEM_1: return KeyboardKey::OEM_1;
        case VK_OEM_PLUS: return KeyboardKey::PLUS;
        case VK_OEM_COMMA: return KeyboardKey::COMMA;
        case VK_OEM_MINUS: return KeyboardKey::MINUS;
        case VK_OEM_PERIOD: return KeyboardKey::PERIOD;
        case VK_OEM_2: return KeyboardKey::OEM_2;
        case VK_OEM_3: return KeyboardKey::OEM_3;
        case VK_OEM_4: return KeyboardKey::OEM_4;
        case VK_OEM_5: return KeyboardKey::OEM_5;
        case VK_OEM_6: return KeyboardKey::OEM_6;
        case VK_OEM_7: return KeyboardKey::OEM_7;
        case VK_OEM_8: return KeyboardKey::OEM_8;
        case VK_OEM_AX: return KeyboardKey::OEM_AX;
        case VK_OEM_102: return KeyboardKey::OEM_102;

            // ... misc keys ...
    }
    return KeyboardKey::NONE;
}

static uint32_t getKeyboardModifiers(WPARAM wParam)
{
    uint32_t modifiers = 0;

    if (wParam & MK_SHIFT) modifiers |= Event::SHIFT_DOWN;
    if (wParam & MK_ALT) modifiers |= Event::ALT_DOWN;
    if (wParam & MK_CONTROL) modifiers |= Event::CONTROL_DOWN;

    return modifiers;
}

static uint32_t getMouseModifiers(WPARAM wParam)
{
    uint32_t modifiers = 0;

    if (wParam & MK_SHIFT) modifiers |= Event::SHIFT_DOWN;
    if (wParam & MK_CONTROL) modifiers |= Event::CONTROL_DOWN;
    if (wParam & MK_LBUTTON) modifiers |= Event::LEFT_MOUSE_DOWN;
    if (wParam & MK_RBUTTON) modifiers |= Event::RIGHT_MOUSE_DOWN;
    if (wParam & MK_MBUTTON) modifiers |= Event::MIDDLE_MOUSE_DOWN;

    return modifiers;
}

static void handleKeyEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_KEYDOWN)
    {
        Engine::getInstance()->getInput()->keyDown(winKeyToEngineCode(wParam, lParam), getKeyboardModifiers(wParam));
    }
    else if (msg == WM_KEYUP)
    {
        Engine::getInstance()->getInput()->keyUp(winKeyToEngineCode(wParam, lParam), getKeyboardModifiers(wParam));
    }
}

static void handleMouseMoveEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    Engine::getInstance()->getInput()->mouseMove(Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                 getMouseModifiers(wParam));
}

static void handleMouseButtonEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    MouseButton button;

    if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP)
    {
        button = MouseButton::LEFT;
    }
    else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP)
    {
        button = MouseButton::RIGHT;
    }
    else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP)
    {
        button = MouseButton::MIDDLE;
    }
    else if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
    {
        if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
            button = MouseButton::X1;
        else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
            button = MouseButton::X2;
    }
    else
    {
        return;
    }

    if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_XBUTTONDOWN)
    {
        Engine::getInstance()->getInput()->mouseDown(button,
                                                     Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                     getMouseModifiers(wParam));
    }
    else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || msg == WM_MBUTTONUP || msg == WM_XBUTTONUP)
    {
        Engine::getInstance()->getInput()->mouseUp(button,
                                                   Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                   getMouseModifiers(wParam));
    }
}

static void handleMouseWheelEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    if (msg == WM_MOUSEWHEEL)
    {
        Engine::getInstance()->getInput()->mouseScroll(Vector2(0.0f, static_cast<float>(HIWORD(wParam)) / static_cast<float>(WHEEL_DELTA)),
                                                       Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                       getMouseModifiers(wParam));
    }
    else if (msg == WM_MOUSEHWHEEL)
    {
        Engine::getInstance()->getInput()->mouseScroll(Vector2(-static_cast<float>(HIWORD(wParam)) / static_cast<float>(WHEEL_DELTA), 0.0f),
                                                       Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                       getMouseModifiers(wParam));
    }
}

LRESULT CALLBACK windowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_ACTIVATE:
        {
            UINT state = LOWORD(wParam);

            if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
            {
                // TODO: Implement activation of the window
            }
            else if (state == WA_INACTIVE)
            {
                // TODO: Implement activation of the window
            }
            break;
        }
        case WM_KEYUP:
        case WM_KEYDOWN:
        {
            handleKeyEvent(msg, wParam, lParam);
            break;
        }
        case WM_LBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MBUTTONDOWN:
        case WM_MBUTTONUP:
        case WM_XBUTTONDOWN:
        case WM_XBUTTONUP:
        {
            handleMouseButtonEvent(msg, wParam, lParam);

            if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
                return TRUE;

            return 0;
        }
        case WM_MOUSEMOVE:
        {
            handleMouseMoveEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_MOUSEWHEEL:
        case WM_MOUSEHWHEEL:
        {
            handleMouseWheelEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_SETCURSOR:
        {
            if (LOWORD(lParam) == HTCLIENT)
            {
                if (!Engine::getInstance()->getInput()->isCursorVisible())
                {
                    SetCursor(nullptr);
                    return TRUE;
                }
            }
            break;
        }
        case WM_SIZE:
        {
            if (wParam == SIZE_MINIMIZED)
            {
                // TODO: stop engine
            }
            else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
            {
                INT width = LOWORD(lParam);
                INT height = HIWORD(lParam);

                Engine::getInstance()->getRenderer()->resize(Size2(width, height));
            }
            return 0;
        }
        case WM_ERASEBKGND:
        {
            return TRUE;
        }
        case WM_SYSCOMMAND:
        {
            switch (wParam)
            {
            case SC_SCREENSAVE:
            case SC_MONITORPOWER:
            {
                if (Engine::getInstance()->getRenderer()->isFullscreen())
                {
                    // Disable screensaver in fullscreen mode
                    return 0;
                }
                break;
            }
            // Disable accessing menu using alt key
            case SC_KEYMENU:
                return 0;
            }
            break;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            Engine::getInstance()->end();
            return 0;
        }
    }

    return DefWindowProcW(window, msg, wParam, lParam);
}
<commit_msg>Add missing windowsx.h include<commit_after>// Copyright (C) 2015 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <windowsx.h>
#include "Window.h"
#include "Engine.h"
#include "InputWin.h"

using namespace ouzel;

static KeyboardKey winKeyToEngineCode(WPARAM wParam, LPARAM lParam)
{
    switch (wParam)
    {
        case VK_CANCEL: return KeyboardKey::CANCEL;
        case VK_BACK: return KeyboardKey::BACKSPACE;
        case VK_TAB: return KeyboardKey::TAB;
        case VK_CLEAR: return KeyboardKey::CLEAR;
        case VK_RETURN: return KeyboardKey::RETURN;
        case VK_SHIFT: return KeyboardKey::SHIFT;
        case VK_CONTROL: return KeyboardKey::CONTROL;
        case VK_MENU: return KeyboardKey::MENU;
        case VK_PAUSE: return KeyboardKey::PAUSE;
        case VK_CAPITAL: return KeyboardKey::CAPITAL;

            // ... Japanese ...

        case VK_ESCAPE: return KeyboardKey::ESCAPE;

            // ... IME ...

        case VK_SPACE: return KeyboardKey::SPACE;
        case VK_PRIOR: return KeyboardKey::PRIOR;
        case VK_NEXT: return KeyboardKey::NEXT;
        case VK_END: return KeyboardKey::END;
        case VK_HOME: return KeyboardKey::HOME;
        case VK_LEFT: return KeyboardKey::LEFT;
        case VK_UP: return KeyboardKey::UP;
        case VK_RIGHT: return KeyboardKey::RIGHT;
        case VK_DOWN: return KeyboardKey::DOWN;

        case VK_SELECT: return KeyboardKey::SELECT;
        case VK_PRINT: return KeyboardKey::PRINT;
        case VK_EXECUTE: return KeyboardKey::EXECUT;

        case VK_SNAPSHOT: return KeyboardKey::SNAPSHOT;
        case VK_INSERT: return KeyboardKey::INSERT;
        case VK_DELETE: return KeyboardKey::DEL;
        case VK_HELP: return KeyboardKey::HELP;

        case '0': return KeyboardKey::KEY_0;
        case '1': return KeyboardKey::KEY_1;
        case '2': return KeyboardKey::KEY_2;
        case '3': return KeyboardKey::KEY_3;
        case '4': return KeyboardKey::KEY_4;
        case '5': return KeyboardKey::KEY_5;
        case '6': return KeyboardKey::KEY_6;
        case '7': return KeyboardKey::KEY_7;
        case '8': return KeyboardKey::KEY_8;
        case '9': return KeyboardKey::KEY_9;

        case 'A': return KeyboardKey::KEY_A;
        case 'B': return KeyboardKey::KEY_B;
        case 'C': return KeyboardKey::KEY_C;
        case 'D': return KeyboardKey::KEY_D;
        case 'E': return KeyboardKey::KEY_E;
        case 'F': return KeyboardKey::KEY_F;
        case 'G': return KeyboardKey::KEY_G;
        case 'H': return KeyboardKey::KEY_H;
        case 'I': return KeyboardKey::KEY_I;
        case 'J': return KeyboardKey::KEY_J;
        case 'K': return KeyboardKey::KEY_K;
        case 'L': return KeyboardKey::KEY_L;
        case 'M': return KeyboardKey::KEY_M;
        case 'N': return KeyboardKey::KEY_N;
        case 'O': return KeyboardKey::KEY_O;
        case 'P': return KeyboardKey::KEY_P;
        case 'Q': return KeyboardKey::KEY_Q;
        case 'R': return KeyboardKey::KEY_R;
        case 'S': return KeyboardKey::KEY_S;
        case 'T': return KeyboardKey::KEY_T;
        case 'U': return KeyboardKey::KEY_U;
        case 'V': return KeyboardKey::KEY_V;
        case 'W': return KeyboardKey::KEY_W;
        case 'X': return KeyboardKey::KEY_X;
        case 'Y': return KeyboardKey::KEY_Y;
        case 'Z': return KeyboardKey::KEY_Z;

        case VK_LWIN: return KeyboardKey::LWIN;
        case VK_RWIN: return KeyboardKey::RWIN;
        case VK_APPS: return KeyboardKey::MENU;
        case VK_SLEEP: return KeyboardKey::SLEEP;

        case VK_NUMPAD0: return KeyboardKey::NUMPAD0;
        case VK_NUMPAD1: return KeyboardKey::NUMPAD1;
        case VK_NUMPAD2: return KeyboardKey::NUMPAD2;
        case VK_NUMPAD3: return KeyboardKey::NUMPAD3;
        case VK_NUMPAD4: return KeyboardKey::NUMPAD4;
        case VK_NUMPAD5: return KeyboardKey::NUMPAD5;
        case VK_NUMPAD6: return KeyboardKey::NUMPAD6;
        case VK_NUMPAD7: return KeyboardKey::NUMPAD7;
        case VK_NUMPAD8: return KeyboardKey::NUMPAD8;
        case VK_NUMPAD9: return KeyboardKey::NUMPAD9;

        case VK_MULTIPLY: return KeyboardKey::MULTIPLY;
        case VK_ADD: return KeyboardKey::ADD;
        case VK_SEPARATOR: return KeyboardKey::SEPARATOR;
        case VK_SUBTRACT: return KeyboardKey::SUBTRACT;
        case VK_DECIMAL: return KeyboardKey::DECIMAL;
        case VK_DIVIDE: return KeyboardKey::DIVIDE;

        case VK_F1: return KeyboardKey::F1;
        case VK_F2: return KeyboardKey::F2;
        case VK_F3: return KeyboardKey::F3;
        case VK_F4: return KeyboardKey::F4;
        case VK_F5: return KeyboardKey::F5;
        case VK_F6: return KeyboardKey::F6;
        case VK_F7: return KeyboardKey::F7;
        case VK_F8: return KeyboardKey::F8;
        case VK_F9: return KeyboardKey::F9;
        case VK_F10: return KeyboardKey::F10;
        case VK_F11: return KeyboardKey::F11;
        case VK_F12: return KeyboardKey::F12;
        case VK_F13: return KeyboardKey::F13;
        case VK_F14: return KeyboardKey::F14;
        case VK_F15: return KeyboardKey::F15;
        case VK_F16: return KeyboardKey::F16;
        case VK_F17: return KeyboardKey::F17;
        case VK_F18: return KeyboardKey::F18;
        case VK_F19: return KeyboardKey::F19;
        case VK_F20: return KeyboardKey::F20;
        case VK_F21: return KeyboardKey::F21;
        case VK_F22: return KeyboardKey::F22;
        case VK_F23: return KeyboardKey::F23;
        case VK_F24: return KeyboardKey::F24;

        case VK_NUMLOCK: return KeyboardKey::NUMLOCK;
        case VK_SCROLL: return KeyboardKey::SCROLL;
        case VK_LSHIFT: return KeyboardKey::LSHIFT;
        case VK_RSHIFT: return KeyboardKey::RSHIFT;
        case VK_LCONTROL: return KeyboardKey::LCONTROL;
        case VK_RCONTROL: return KeyboardKey::RCONTROL;
        case VK_LMENU: return KeyboardKey::LMENU;
        case VK_RMENU: return KeyboardKey::RMENU;

        case VK_OEM_1: return KeyboardKey::OEM_1;
        case VK_OEM_PLUS: return KeyboardKey::PLUS;
        case VK_OEM_COMMA: return KeyboardKey::COMMA;
        case VK_OEM_MINUS: return KeyboardKey::MINUS;
        case VK_OEM_PERIOD: return KeyboardKey::PERIOD;
        case VK_OEM_2: return KeyboardKey::OEM_2;
        case VK_OEM_3: return KeyboardKey::OEM_3;
        case VK_OEM_4: return KeyboardKey::OEM_4;
        case VK_OEM_5: return KeyboardKey::OEM_5;
        case VK_OEM_6: return KeyboardKey::OEM_6;
        case VK_OEM_7: return KeyboardKey::OEM_7;
        case VK_OEM_8: return KeyboardKey::OEM_8;
        case VK_OEM_AX: return KeyboardKey::OEM_AX;
        case VK_OEM_102: return KeyboardKey::OEM_102;

            // ... misc keys ...
    }
    return KeyboardKey::NONE;
}

static uint32_t getKeyboardModifiers(WPARAM wParam)
{
    uint32_t modifiers = 0;

    if (wParam & MK_SHIFT) modifiers |= Event::SHIFT_DOWN;
    if (wParam & MK_ALT) modifiers |= Event::ALT_DOWN;
    if (wParam & MK_CONTROL) modifiers |= Event::CONTROL_DOWN;

    return modifiers;
}

static uint32_t getMouseModifiers(WPARAM wParam)
{
    uint32_t modifiers = 0;

    if (wParam & MK_SHIFT) modifiers |= Event::SHIFT_DOWN;
    if (wParam & MK_CONTROL) modifiers |= Event::CONTROL_DOWN;
    if (wParam & MK_LBUTTON) modifiers |= Event::LEFT_MOUSE_DOWN;
    if (wParam & MK_RBUTTON) modifiers |= Event::RIGHT_MOUSE_DOWN;
    if (wParam & MK_MBUTTON) modifiers |= Event::MIDDLE_MOUSE_DOWN;

    return modifiers;
}

static void handleKeyEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (msg == WM_KEYDOWN)
    {
        Engine::getInstance()->getInput()->keyDown(winKeyToEngineCode(wParam, lParam), getKeyboardModifiers(wParam));
    }
    else if (msg == WM_KEYUP)
    {
        Engine::getInstance()->getInput()->keyUp(winKeyToEngineCode(wParam, lParam), getKeyboardModifiers(wParam));
    }
}

static void handleMouseMoveEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    Engine::getInstance()->getInput()->mouseMove(Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                 getMouseModifiers(wParam));
}

static void handleMouseButtonEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    MouseButton button;

    if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP)
    {
        button = MouseButton::LEFT;
    }
    else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP)
    {
        button = MouseButton::RIGHT;
    }
    else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP)
    {
        button = MouseButton::MIDDLE;
    }
    else if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
    {
        if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
            button = MouseButton::X1;
        else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
            button = MouseButton::X2;
    }
    else
    {
        return;
    }

    if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_XBUTTONDOWN)
    {
        Engine::getInstance()->getInput()->mouseDown(button,
                                                     Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                     getMouseModifiers(wParam));
    }
    else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || msg == WM_MBUTTONUP || msg == WM_XBUTTONUP)
    {
        Engine::getInstance()->getInput()->mouseUp(button,
                                                   Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                   getMouseModifiers(wParam));
    }
}

static void handleMouseWheelEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    if (msg == WM_MOUSEWHEEL)
    {
        Engine::getInstance()->getInput()->mouseScroll(Vector2(0.0f, static_cast<float>(HIWORD(wParam)) / static_cast<float>(WHEEL_DELTA)),
                                                       Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                       getMouseModifiers(wParam));
    }
    else if (msg == WM_MOUSEHWHEEL)
    {
        Engine::getInstance()->getInput()->mouseScroll(Vector2(-static_cast<float>(HIWORD(wParam)) / static_cast<float>(WHEEL_DELTA), 0.0f),
                                                       Engine::getInstance()->getRenderer()->viewToScreenLocation(pos),
                                                       getMouseModifiers(wParam));
    }
}

LRESULT CALLBACK windowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_ACTIVATE:
        {
            UINT state = LOWORD(wParam);

            if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
            {
                // TODO: Implement activation of the window
            }
            else if (state == WA_INACTIVE)
            {
                // TODO: Implement activation of the window
            }
            break;
        }
        case WM_KEYUP:
        case WM_KEYDOWN:
        {
            handleKeyEvent(msg, wParam, lParam);
            break;
        }
        case WM_LBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MBUTTONDOWN:
        case WM_MBUTTONUP:
        case WM_XBUTTONDOWN:
        case WM_XBUTTONUP:
        {
            handleMouseButtonEvent(msg, wParam, lParam);

            if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
                return TRUE;

            return 0;
        }
        case WM_MOUSEMOVE:
        {
            handleMouseMoveEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_MOUSEWHEEL:
        case WM_MOUSEHWHEEL:
        {
            handleMouseWheelEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_SETCURSOR:
        {
            if (LOWORD(lParam) == HTCLIENT)
            {
                if (!Engine::getInstance()->getInput()->isCursorVisible())
                {
                    SetCursor(nullptr);
                    return TRUE;
                }
            }
            break;
        }
        case WM_SIZE:
        {
            if (wParam == SIZE_MINIMIZED)
            {
                // TODO: stop engine
            }
            else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
            {
                INT width = LOWORD(lParam);
                INT height = HIWORD(lParam);

                Engine::getInstance()->getRenderer()->resize(Size2(width, height));
            }
            return 0;
        }
        case WM_ERASEBKGND:
        {
            return TRUE;
        }
        case WM_SYSCOMMAND:
        {
            switch (wParam)
            {
            case SC_SCREENSAVE:
            case SC_MONITORPOWER:
            {
                if (Engine::getInstance()->getRenderer()->isFullscreen())
                {
                    // Disable screensaver in fullscreen mode
                    return 0;
                }
                break;
            }
            // Disable accessing menu using alt key
            case SC_KEYMENU:
                return 0;
            }
            break;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            Engine::getInstance()->end();
            return 0;
        }
    }

    return DefWindowProcW(window, msg, wParam, lParam);
}
<|endoftext|>


<commit_before>#ifndef KISSFFT_CLASS_HH
#include <complex>
#include <vector>

namespace kissfft_utils {

template <typename T_scalar>
struct traits
{
    typedef T_scalar scalar_type;
    typedef std::complex<scalar_type> cpx_type;
    void fill_twiddles( std::complex<T_scalar> * dst ,int nfft,bool inverse)
    {
        T_scalar phinc =  (inverse?2:-2)* acos( (T_scalar) -1)  / nfft;
        for (int i=0;i<nfft;++i)
            dst[i] = exp( std::complex<T_scalar>(0,i*phinc) );
    }

    void prepare(
            std::vector< std::complex<T_scalar> > & dst,
            int nfft,bool inverse,
            std::vector<int> & stageRadix,
            std::vector<int> & stageRemainder )
    {
        _twiddles.resize(nfft);
        fill_twiddles( &_twiddles[0],nfft,inverse);
        dst = _twiddles;

        //factorize
        //start factoring out 4's, then 2's, then 3,5,7,9,...
        int n= nfft;
        int p=4;
        do {
            while (n % p) {
                switch (p) {
                    case 4: p = 2; break;
                    case 2: p = 3; break;
                    default: p += 2; break;
                }
                if (p*p>n)
                    p=n;// no more factors
            }
            n /= p;
            stageRadix.push_back(p);
            stageRemainder.push_back(n);
        }while(n>1);
    }
    std::vector<cpx_type> _twiddles;

    const cpx_type twiddle(size_t i) { return _twiddles[i]; }
};

}

template <typename T_Scalar,
         typename T_traits=kissfft_utils::traits<T_Scalar>
         >
class kissfft
{
    public:
        typedef T_traits traits_type;
        typedef typename traits_type::scalar_type scalar_type;
        typedef typename traits_type::cpx_type cpx_type;

        kissfft(int nfft,bool inverse,const traits_type & traits=traits_type() )
            :_nfft(nfft),_inverse(inverse),_traits(traits)
        {
            _traits.prepare(_twiddles, _nfft,_inverse ,_stageRadix, _stageRemainder);
        }

        void transform(const cpx_type * src , cpx_type * dst)
        {
            kf_work(0, dst, src, 1,1);
        }

    private:
        void kf_work( int stage,cpx_type * Fout, const cpx_type * f, size_t fstride,size_t in_stride)
        {
            int p = _stageRadix[stage];
            int m = _stageRemainder[stage];
            cpx_type * Fout_beg = Fout;
            cpx_type * Fout_end = Fout + p*m;

            if (m==1) {
                do{
                    *Fout = *f;
                    f += fstride*in_stride;
                }while(++Fout != Fout_end );
            }else{
                do{
                    // recursive call:
                    // DFT of size m*p performed by doing
                    // p instances of smaller DFTs of size m,
                    // each one takes a decimated version of the input
                    kf_work(stage+1, Fout , f, fstride*p,in_stride);
                    f += fstride*in_stride;
                }while( (Fout += m) != Fout_end );
            }

            Fout=Fout_beg;

            // recombine the p smaller DFTs
            switch (p) {
                case 2: kf_bfly2(Fout,fstride,m); break;
                case 3: kf_bfly3(Fout,fstride,m); break;
                case 4: kf_bfly4(Fout,fstride,m); break;
                case 5: kf_bfly5(Fout,fstride,m); break;
                default: kf_bfly_generic(Fout,fstride,m,p); break;
            }
        }

        // these were #define macros in the original kiss_fft
        void C_ADD( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a+b;}
        void C_MUL( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a*b;}
        void C_SUB( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a-b;}
        void C_ADDTO( cpx_type & c,const cpx_type & a) { c+=a;}
        void C_FIXDIV( cpx_type & ,int ) {} // NO-OP for float types
        scalar_type S_MUL( const scalar_type & a,const scalar_type & b) { return a*b;}
        scalar_type HALF_OF( const scalar_type & a) { return a*.5;}
        void C_MULBYSCALAR(cpx_type & c,const scalar_type & a) {c*=a;}

        void kf_bfly2( cpx_type * Fout, const size_t fstride, size_t m)
        {
            for (size_t k=0;k<m;++k) {
                cpx_type t = Fout[m+k] * _traits.twiddle(k*fstride);
                Fout[m+k] = Fout[k] - t;
                Fout[k] += t;
            }
        }

        void kf_bfly4( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type scratch[7];
            int negative_if_inverse = _inverse * -2 +1;
            for (size_t k=0;k<m;++k) {
                scratch[0] = Fout[k+m] * _traits.twiddle(k*fstride);
                scratch[1] = Fout[k+2*m] * _traits.twiddle(k*fstride*2);
                scratch[2] = Fout[k+3*m] * _traits.twiddle(k*fstride*3);
                scratch[5] = Fout[k] - scratch[1];

                Fout[k] += scratch[1];
                scratch[3] = scratch[0] + scratch[2];
                scratch[4] = scratch[0] - scratch[2];
                scratch[4] = cpx_type( scratch[4].imag()*negative_if_inverse , -scratch[4].real()* negative_if_inverse );

                Fout[k+2*m]  = Fout[k] - scratch[3];
                Fout[k] += scratch[3];
                Fout[k+m] = scratch[5] + scratch[4];
                Fout[k+3*m] = scratch[5] - scratch[4];
            }
        }

        void kf_bfly3( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            size_t k=m;
            const size_t m2 = 2*m;
            cpx_type *tw1,*tw2;
            cpx_type scratch[5];
            cpx_type epi3;
            epi3 = _twiddles[fstride*m];

            tw1=tw2=&_twiddles[0];

            do{
                C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);

                C_MUL(scratch[1],Fout[m] , *tw1);
                C_MUL(scratch[2],Fout[m2] , *tw2);

                C_ADD(scratch[3],scratch[1],scratch[2]);
                C_SUB(scratch[0],scratch[1],scratch[2]);
                tw1 += fstride;
                tw2 += fstride*2;

                Fout[m] = cpx_type( Fout->real() - HALF_OF(scratch[3].real() ) , Fout->imag() - HALF_OF(scratch[3].imag() ) );

                C_MULBYSCALAR( scratch[0] , epi3.imag() );

                C_ADDTO(*Fout,scratch[3]);

                Fout[m2] = cpx_type(  Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );

                C_ADDTO( Fout[m] , cpx_type( -scratch[0].imag(),scratch[0].real() ) );
                ++Fout;
            }while(--k);
        }

        void kf_bfly5( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
            size_t u;
            cpx_type scratch[13];
            cpx_type * twiddles = &_twiddles[0];
            cpx_type *tw;
            cpx_type ya,yb;
            ya = twiddles[fstride*m];
            yb = twiddles[fstride*2*m];

            Fout0=Fout;
            Fout1=Fout0+m;
            Fout2=Fout0+2*m;
            Fout3=Fout0+3*m;
            Fout4=Fout0+4*m;

            tw=twiddles;
            for ( u=0; u<m; ++u ) {
                C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
                scratch[0] = *Fout0;

                C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
                C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
                C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
                C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);

                C_ADD( scratch[7],scratch[1],scratch[4]);
                C_SUB( scratch[10],scratch[1],scratch[4]);
                C_ADD( scratch[8],scratch[2],scratch[3]);
                C_SUB( scratch[9],scratch[2],scratch[3]);

                C_ADDTO( *Fout0, scratch[7]);
                C_ADDTO( *Fout0, scratch[8]);

                scratch[5] = scratch[0] + cpx_type(
                        S_MUL(scratch[7].real(),ya.real() ) + S_MUL(scratch[8].real() ,yb.real() ),
                        S_MUL(scratch[7].imag(),ya.real()) + S_MUL(scratch[8].imag(),yb.real())
                        );

                scratch[6] =  cpx_type(
                        S_MUL(scratch[10].imag(),ya.imag()) + S_MUL(scratch[9].imag(),yb.imag()),
                        -S_MUL(scratch[10].real(),ya.imag()) - S_MUL(scratch[9].real(),yb.imag())
                        );

                C_SUB(*Fout1,scratch[5],scratch[6]);
                C_ADD(*Fout4,scratch[5],scratch[6]);

                scratch[11] = scratch[0] +
                    cpx_type(
                            S_MUL(scratch[7].real(),yb.real()) + S_MUL(scratch[8].real(),ya.real()),
                            S_MUL(scratch[7].imag(),yb.real()) + S_MUL(scratch[8].imag(),ya.real())
                            );

                scratch[12] = cpx_type(
                        -S_MUL(scratch[10].imag(),yb.imag()) + S_MUL(scratch[9].imag(),ya.imag()),
                        S_MUL(scratch[10].real(),yb.imag()) - S_MUL(scratch[9].real(),ya.imag())
                        );

                C_ADD(*Fout2,scratch[11],scratch[12]);
                C_SUB(*Fout3,scratch[11],scratch[12]);

                ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
            }
        }

        /* perform the butterfly for one stage of a mixed radix FFT */
        void kf_bfly_generic(
                cpx_type * Fout,
                const size_t fstride,
                int m,
                int p
                )
        {
            int u,k,q1,q;
            cpx_type * twiddles = &_twiddles[0];
            cpx_type t;
            int Norig = _nfft;
            cpx_type* scratchbuf = new cpx_type[p];

            for ( u=0; u<m; ++u ) {
                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    scratchbuf[q1] = Fout[ k  ];
                    C_FIXDIV(scratchbuf[q1],p);
                    k += m;
                }

                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    int twidx=0;
                    Fout[ k ] = scratchbuf[0];
                    for (q=1;q<p;++q ) {
                        twidx += fstride * k;
                        if (twidx>=Norig) twidx-=Norig;
                        C_MUL(t,scratchbuf[q] , twiddles[twidx] );
                        C_ADDTO( Fout[ k ] ,t);
                    }
                    k += m;
                }
            }
			delete[] scratchbuf;
        }

        int _nfft;
        bool _inverse;
        std::vector<cpx_type> _twiddles;
        std::vector<int> _stageRadix;
        std::vector<int> _stageRemainder;
        traits_type _traits;
};
#endif
<commit_msg>fix(kissfft.hh): explicit conversion const size_t <-> const int<commit_after>#ifndef KISSFFT_CLASS_HH
#include <complex>
#include <vector>

namespace kissfft_utils {

template <typename T_scalar>
struct traits
{
    typedef T_scalar scalar_type;
    typedef std::complex<scalar_type> cpx_type;
    void fill_twiddles( std::complex<T_scalar> * dst ,int nfft,bool inverse)
    {
        T_scalar phinc =  (inverse?2:-2)* acos( (T_scalar) -1)  / nfft;
        for (int i=0;i<nfft;++i)
            dst[i] = exp( std::complex<T_scalar>(0,i*phinc) );
    }

    void prepare(
            std::vector< std::complex<T_scalar> > & dst,
            int nfft,bool inverse,
            std::vector<int> & stageRadix,
            std::vector<int> & stageRemainder )
    {
        _twiddles.resize(nfft);
        fill_twiddles( &_twiddles[0],nfft,inverse);
        dst = _twiddles;

        //factorize
        //start factoring out 4's, then 2's, then 3,5,7,9,...
        int n= nfft;
        int p=4;
        do {
            while (n % p) {
                switch (p) {
                    case 4: p = 2; break;
                    case 2: p = 3; break;
                    default: p += 2; break;
                }
                if (p*p>n)
                    p=n;// no more factors
            }
            n /= p;
            stageRadix.push_back(p);
            stageRemainder.push_back(n);
        }while(n>1);
    }
    std::vector<cpx_type> _twiddles;

    const cpx_type twiddle(size_t i) { return _twiddles[i]; }
};

}

template <typename T_Scalar,
         typename T_traits=kissfft_utils::traits<T_Scalar>
         >
class kissfft
{
    public:
        typedef T_traits traits_type;
        typedef typename traits_type::scalar_type scalar_type;
        typedef typename traits_type::cpx_type cpx_type;

        kissfft(int nfft,bool inverse,const traits_type & traits=traits_type() )
            :_nfft(nfft),_inverse(inverse),_traits(traits)
        {
            _traits.prepare(_twiddles, _nfft,_inverse ,_stageRadix, _stageRemainder);
        }

        void transform(const cpx_type * src , cpx_type * dst)
        {
            kf_work(0, dst, src, 1,1);
        }

    private:
        void kf_work( int stage,cpx_type * Fout, const cpx_type * f, size_t fstride,size_t in_stride)
        {
            int p = _stageRadix[stage];
            int m = _stageRemainder[stage];
            cpx_type * Fout_beg = Fout;
            cpx_type * Fout_end = Fout + p*m;

            if (m==1) {
                do{
                    *Fout = *f;
                    f += fstride*in_stride;
                }while(++Fout != Fout_end );
            }else{
                do{
                    // recursive call:
                    // DFT of size m*p performed by doing
                    // p instances of smaller DFTs of size m,
                    // each one takes a decimated version of the input
                    kf_work(stage+1, Fout , f, fstride*p,in_stride);
                    f += fstride*in_stride;
                }while( (Fout += m) != Fout_end );
            }

            Fout=Fout_beg;

            // recombine the p smaller DFTs
            switch (p) {
                case 2: kf_bfly2(Fout,fstride,m); break;
                case 3: kf_bfly3(Fout,fstride,m); break;
                case 4: kf_bfly4(Fout,fstride,m); break;
                case 5: kf_bfly5(Fout,fstride,m); break;
                default: kf_bfly_generic(Fout,fstride,m,p); break;
            }
        }

        // these were #define macros in the original kiss_fft
        void C_ADD( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a+b;}
        void C_MUL( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a*b;}
        void C_SUB( cpx_type & c,const cpx_type & a,const cpx_type & b) { c=a-b;}
        void C_ADDTO( cpx_type & c,const cpx_type & a) { c+=a;}
        void C_FIXDIV( cpx_type & ,int ) {} // NO-OP for float types
        scalar_type S_MUL( const scalar_type & a,const scalar_type & b) { return a*b;}
        scalar_type HALF_OF( const scalar_type & a) { return a*.5;}
        void C_MULBYSCALAR(cpx_type & c,const scalar_type & a) {c*=a;}

        void kf_bfly2( cpx_type * Fout, const size_t fstride, size_t m)
        {
            for (size_t k=0;k<m;++k) {
                cpx_type t = Fout[m+k] * _traits.twiddle(k*fstride);
                Fout[m+k] = Fout[k] - t;
                Fout[k] += t;
            }
        }

        void kf_bfly4( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type scratch[7];
            int negative_if_inverse = _inverse * -2 +1;
            for (size_t k=0;k<m;++k) {
                scratch[0] = Fout[k+m] * _traits.twiddle(k*fstride);
                scratch[1] = Fout[k+2*m] * _traits.twiddle(k*fstride*2);
                scratch[2] = Fout[k+3*m] * _traits.twiddle(k*fstride*3);
                scratch[5] = Fout[k] - scratch[1];

                Fout[k] += scratch[1];
                scratch[3] = scratch[0] + scratch[2];
                scratch[4] = scratch[0] - scratch[2];
                scratch[4] = cpx_type( scratch[4].imag()*negative_if_inverse , -scratch[4].real()* negative_if_inverse );

                Fout[k+2*m]  = Fout[k] - scratch[3];
                Fout[k] += scratch[3];
                Fout[k+m] = scratch[5] + scratch[4];
                Fout[k+3*m] = scratch[5] - scratch[4];
            }
        }

        void kf_bfly3( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            size_t k=m;
            const size_t m2 = 2*m;
            cpx_type *tw1,*tw2;
            cpx_type scratch[5];
            cpx_type epi3;
            epi3 = _twiddles[fstride*m];

            tw1=tw2=&_twiddles[0];

            do{
                C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);

                C_MUL(scratch[1],Fout[m] , *tw1);
                C_MUL(scratch[2],Fout[m2] , *tw2);

                C_ADD(scratch[3],scratch[1],scratch[2]);
                C_SUB(scratch[0],scratch[1],scratch[2]);
                tw1 += fstride;
                tw2 += fstride*2;

                Fout[m] = cpx_type( Fout->real() - HALF_OF(scratch[3].real() ) , Fout->imag() - HALF_OF(scratch[3].imag() ) );

                C_MULBYSCALAR( scratch[0] , epi3.imag() );

                C_ADDTO(*Fout,scratch[3]);

                Fout[m2] = cpx_type(  Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );

                C_ADDTO( Fout[m] , cpx_type( -scratch[0].imag(),scratch[0].real() ) );
                ++Fout;
            }while(--k);
        }

        void kf_bfly5( cpx_type * Fout, const size_t fstride, const size_t m)
        {
            cpx_type *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
            size_t u;
            cpx_type scratch[13];
            cpx_type * twiddles = &_twiddles[0];
            cpx_type *tw;
            cpx_type ya,yb;
            ya = twiddles[fstride*m];
            yb = twiddles[fstride*2*m];

            Fout0=Fout;
            Fout1=Fout0+m;
            Fout2=Fout0+2*m;
            Fout3=Fout0+3*m;
            Fout4=Fout0+4*m;

            tw=twiddles;
            for ( u=0; u<m; ++u ) {
                C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
                scratch[0] = *Fout0;

                C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
                C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
                C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
                C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);

                C_ADD( scratch[7],scratch[1],scratch[4]);
                C_SUB( scratch[10],scratch[1],scratch[4]);
                C_ADD( scratch[8],scratch[2],scratch[3]);
                C_SUB( scratch[9],scratch[2],scratch[3]);

                C_ADDTO( *Fout0, scratch[7]);
                C_ADDTO( *Fout0, scratch[8]);

                scratch[5] = scratch[0] + cpx_type(
                        S_MUL(scratch[7].real(),ya.real() ) + S_MUL(scratch[8].real() ,yb.real() ),
                        S_MUL(scratch[7].imag(),ya.real()) + S_MUL(scratch[8].imag(),yb.real())
                        );

                scratch[6] =  cpx_type(
                        S_MUL(scratch[10].imag(),ya.imag()) + S_MUL(scratch[9].imag(),yb.imag()),
                        -S_MUL(scratch[10].real(),ya.imag()) - S_MUL(scratch[9].real(),yb.imag())
                        );

                C_SUB(*Fout1,scratch[5],scratch[6]);
                C_ADD(*Fout4,scratch[5],scratch[6]);

                scratch[11] = scratch[0] +
                    cpx_type(
                            S_MUL(scratch[7].real(),yb.real()) + S_MUL(scratch[8].real(),ya.real()),
                            S_MUL(scratch[7].imag(),yb.real()) + S_MUL(scratch[8].imag(),ya.real())
                            );

                scratch[12] = cpx_type(
                        -S_MUL(scratch[10].imag(),yb.imag()) + S_MUL(scratch[9].imag(),ya.imag()),
                        S_MUL(scratch[10].real(),yb.imag()) - S_MUL(scratch[9].real(),ya.imag())
                        );

                C_ADD(*Fout2,scratch[11],scratch[12]);
                C_SUB(*Fout3,scratch[11],scratch[12]);

                ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
            }
        }

        /* perform the butterfly for one stage of a mixed radix FFT */
        void kf_bfly_generic(
                cpx_type * Fout,
                const size_t fstride,
                int m,
                int p
                )
        {
            int u,k,q1,q;
            cpx_type * twiddles = &_twiddles[0];
            cpx_type t;
            int Norig = _nfft;
            cpx_type* scratchbuf = new cpx_type[p];

            for ( u=0; u<m; ++u ) {
                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    scratchbuf[q1] = Fout[ k  ];
                    C_FIXDIV(scratchbuf[q1],p);
                    k += m;
                }

                k=u;
                for ( q1=0 ; q1<p ; ++q1 ) {
                    int twidx=0;
                    Fout[ k ] = scratchbuf[0];
                    for (q=1;q<p;++q ) {
                        twidx += (const int)fstride * k;
                        if (twidx>=Norig) twidx-=Norig;
                        C_MUL(t,scratchbuf[q] , twiddles[twidx] );
                        C_ADDTO( Fout[ k ] ,t);
                    }
                    k += m;
                }
            }
			delete[] scratchbuf;
        }

        int _nfft;
        bool _inverse;
        std::vector<cpx_type> _twiddles;
        std::vector<int> _stageRadix;
        std::vector<int> _stageRemainder;
        traits_type _traits;
};
#endif
<|endoftext|>


<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* 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 the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

NodeManager* g_nodeManager = NULL;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

NodeManager::NodeManager()
{
}

NodeManager::~NodeManager()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mutex operations

/**
	@brief Locks the node manager's mutex. This prevents any database manipulation by other threads.

	It is critical to lock the mute whenever querying a specific toolchain object.
	Compute nodes can come and go at any time while the mutex is unlocked; pointers may become invalid at any time.
	Do not retain any node pointers after unlocking the mutex.
 */
void NodeManager::lock()
{
	m_mutex.lock();
}

/**
	@brief Unlocks the node manager's mutex.
 */
void NodeManager::unlock()
{
	m_mutex.unlock();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Database manipulation

/**
	@brief Allocate a new client ID
 */
void NodeManager::AllocateClient(string hostname, string uuid)
{
	lock_guard<recursive_mutex> lock(m_mutex);
	m_workingCopies[uuid] = new WorkingCopy;
	m_workingCopies[uuid]->SetInfo(hostname, uuid);
}

/**
	@brief Delete any state registered to a node
 */
void NodeManager::RemoveClient(clientID id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//Cancel all pending jobs for that node
	g_scheduler->RemoveNode(id);

	auto chains = m_toolchainsByNode[id];
	for(auto x : chains)
		delete x.second;

	m_toolchainsByNode.erase(id);

	for(auto x : m_nodesByLanguage)
		m_nodesByLanguage[x.first].erase(id);

	for(auto x : m_nodesByCompiler)
		m_nodesByCompiler[x.first].erase(id);

	delete m_workingCopies[id];
	m_workingCopies.erase(id);

	//Toolchains may have changed, recompute
	RecomputeCompilerHashes();
}

/**
	@brief Add a toolchain to a node

	moreComing is a hint from the caller that there are more additions pending in the immediate future.
	If set, we defer the recomputation until it's done.
 */
void NodeManager::AddToolchain(clientID id, Toolchain* chain, bool moreComing)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	string hash = chain->GetHash();
	m_toolchainsByNode[id][hash] = chain;
	auto langs = chain->GetSupportedLanguages();
	auto triplets = chain->GetTargetTriplets();
	for(auto l : langs)
		for(auto t : triplets)
			m_nodesByLanguage[larch(l, t)].emplace(id);
	m_nodesByCompiler[hash].emplace(id);

	//Toolchains may have changed, recompute
	if(!moreComing)
		RecomputeCompilerHashes();
}

/**
	@brief Calculate the hash corresponding to each toolchain we know about

	DOES NOT lock the mutex; must be called only after it's locked.
 */
void NodeManager::RecomputeCompilerHashes()
{
	LogDebug("Recomputing compiler hashes\n");

	//Make a list of every language/architecture pair we know about.
	//The list of languages is architecture specific so we need to know what the options are.
	//It's stupid to wasted time looking for a Verilog compiler for mips-elf.
	set<larch> larches;
	for(auto it : m_nodesByLanguage)
		larches.emplace(it.first);

	//Map of toolchain IDs to hashes
	map<carch, string> currentToolchains;

	//For each toolchain we know about, generate the names
	for(auto x : m_nodesByCompiler)
	{
		string hash = x.first;
		Toolchain* tool = GetAnyToolchainForHash(hash);
		if(tool == NULL)
			continue;

		//Generate the names for each arch/triplet combination
		set<string> names;
		tool->GetCompilerNames(names);
		auto triplets = tool->GetTargetTriplets();
		for(auto arch : triplets)
		{
			for(auto name : names)
			{
				//If nobody has claimed this name/arch yet, take it
				carch c(name, arch);
				if(currentToolchains.find(c) == currentToolchains.end())
				{
					currentToolchains[c] = hash;
					continue;
				}

				//If another node took the tuple already, keep the higher version
				Toolchain* otherTool = GetAnyToolchainForHash(currentToolchains[c]);
				if(tool->CompareVersion(otherTool) >= 0)
					currentToolchains[c] = hash;
			}
		}

	}

	//For each language/architecture, find the best toolchain available
	for(auto x : larches)
	{
		//Initial toolchain: nonexistent
		Toolchain* bestToolchain = NULL;
		string bestHash = "";

		//Loop over all toolchains we have (TODO: only per language? index this somehow?)
		for(auto it : m_nodesByCompiler)
		{
			//Look up the toolchain object for that client
			string hash = it.first;
			Toolchain* tool = GetAnyToolchainForHash(hash);
			if(tool == NULL)
				continue;

			//If we can't compile our platform with this toolchain it's of no value to us :(
			if(!tool->IsLanguageSupported(x.first))
				continue;
			if(!tool->IsArchitectureSupported(x.second))
				continue;

			//See if it's any better than what we have now. Skip it if not
			if((bestToolchain != NULL) && (tool->CompareVersionAndType(bestToolchain) < 0) )
				continue;

			bestToolchain = tool;
			bestHash = hash;
		}

		//Register the generic toolchains
		if(bestToolchain != NULL)
		{
			string lang = MakeStringLowercase(Toolchain::LangToString(x.first));
			currentToolchains[carch(lang + "/generic", x.second)] = bestHash;
		}
	}

	//Update the global toolchain list
	bool changed = (m_toolchainsByName != currentToolchains);
	m_toolchainsByName = currentToolchains;

	/*
	//DEBUG: Print the final mapping
	for(auto it : m_toolchainsByName)
	{
		carch c = it.first;
		string hash = it.second;
		Toolchain* tool = GetAnyToolchainForHash(hash);

		LogDebug("%25s for %20s is %25s (%s)\n",
			c.first.c_str(), c.second.c_str(), tool->GetVersionString().c_str(), hash.c_str());
	}
	*/

	//FIXME: do something more efficient based on what changed
	//For now, just re-run every build script in every working copy.
	if(changed)
	{
		for(auto it : m_workingCopies)
			it.second->RefreshToolchains();
	}
}

/**
	@brief Get a pointer to some node's toolchain for the specified hash.

	The exact choice of node is unpredictable and should not be relied on.

	MUST be called while m_mutex is locked. Do not use the returned pointer once the mutex is unlocked.
 */
Toolchain* NodeManager::GetAnyToolchainForHash(string hash)
{
	//If we couldn't find any instances, then complain
	if(m_nodesByCompiler.find(hash) == m_nodesByCompiler.end())
		return NULL;
	if(m_nodesByCompiler[hash].empty())
		return NULL;

	//Find a client that has this toolchain installed
	clientID id = *m_nodesByCompiler[hash].begin();

	//Look up the toolchain object for that client
	return m_toolchainsByNode[id][hash];
}

/**
	@brief Get a pointer to some node's toolchain for the specified toolchain name and target architecture.

	The exact choice of node is unpredictable and should not be relied on.

	MUST be called while m_mutex is locked. Do not use the returned pointer once the mutex is unlocked.
 */
Toolchain* NodeManager::GetAnyToolchainForName(string arch, string name)
{
	lock_guard<recursive_mutex> lock(m_mutex);
	return GetAnyToolchainForHash(GetToolchainHash(arch, name));
}

/**
	@brief Gets the current hash of the requested toolchain, or the empty string if it doesn't exist.
 */
string NodeManager::GetToolchainHash(string arch, string name)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If we do not have such a toolchain, give up
	carch c(name, arch);
	if(m_toolchainsByName.find(c) == m_toolchainsByName.end())
		return "";
	return m_toolchainsByName[c];
}

/**
	@brief Get the ID of the "golden node" for the specified toolchain hash.

	This functionality is not fully implemented.

	MUST be called while m_mutex is locked. Do not use the returned value once the mutex is unlocked.
 */
clientID NodeManager::GetGoldenNodeForToolchain(string hash)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If we know about the toolchain, but nobody has it, give up
	if(m_nodesByCompiler.find(hash) == m_nodesByCompiler.end())
		return 0;
	auto nodes = m_nodesByCompiler[hash];
	if(nodes.empty())
		return 0;

	//If we have only one node, return it.
	if(nodes.size() == 1)
		return *nodes.begin();

	//If more than one, print a warning and return the first
	//TODO: Pick golden node based on explicit config
	else
	{
		LogWarning("NodeManager::GetGoldenNodeForToolchain() does not have golden config yet\n");
		return *nodes.begin();
	}
}
<commit_msg>splashcore: NodeManager now properly refcounts multiple clients with same UUID<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* 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 the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

NodeManager* g_nodeManager = NULL;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

NodeManager::NodeManager()
{
}

NodeManager::~NodeManager()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mutex operations

/**
	@brief Locks the node manager's mutex. This prevents any database manipulation by other threads.

	It is critical to lock the mute whenever querying a specific toolchain object.
	Compute nodes can come and go at any time while the mutex is unlocked; pointers may become invalid at any time.
	Do not retain any node pointers after unlocking the mutex.
 */
void NodeManager::lock()
{
	m_mutex.lock();
}

/**
	@brief Unlocks the node manager's mutex.
 */
void NodeManager::unlock()
{
	m_mutex.unlock();
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Database manipulation

/**
	@brief Allocate a new client ID
 */
void NodeManager::AllocateClient(string hostname, clientID id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//See if we had one already
	if(m_nodeRefcounts.find(id) != m_nodeRefcounts.end())
		m_nodeRefcounts[id] ++;

	//Nope, create a new one
	else
	{
		m_nodeRefcounts[id] = 1;
		m_workingCopies[id] = new WorkingCopy;
		m_workingCopies[id]->SetInfo(hostname, id);
	}
}

/**
	@brief Delete any state registered to a node.
 */
void NodeManager::RemoveClient(clientID id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//Drop the refcount
	m_nodeRefcounts[id] --;

	//If the last client is gone, wipe state
	if(m_nodeRefcounts[id] == 0)
	{
		LogDebug("NodeManager: Removing state for node %s as last client has disconnected\n", id.c_str());

		m_nodeRefcounts.erase(id);

		//Cancel all pending jobs for that node
		g_scheduler->RemoveNode(id);

		auto chains = m_toolchainsByNode[id];
		for(auto x : chains)
			delete x.second;

		m_toolchainsByNode.erase(id);

		for(auto x : m_nodesByLanguage)
			m_nodesByLanguage[x.first].erase(id);

		for(auto x : m_nodesByCompiler)
			m_nodesByCompiler[x.first].erase(id);

		delete m_workingCopies[id];
		m_workingCopies.erase(id);

		//Toolchains may have changed, recompute
		RecomputeCompilerHashes();
	}
	else
	{
		LogDebug("NodeManager: Keeping state for node %s as %d clients are still active\n",
			id.c_str(), m_nodeRefcounts[id]);
	}
}

/**
	@brief Add a toolchain to a node

	moreComing is a hint from the caller that there are more additions pending in the immediate future.
	If set, we defer the recomputation until it's done.
 */
void NodeManager::AddToolchain(clientID id, Toolchain* chain, bool moreComing)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	string hash = chain->GetHash();
	m_toolchainsByNode[id][hash] = chain;
	auto langs = chain->GetSupportedLanguages();
	auto triplets = chain->GetTargetTriplets();
	for(auto l : langs)
		for(auto t : triplets)
			m_nodesByLanguage[larch(l, t)].emplace(id);
	m_nodesByCompiler[hash].emplace(id);

	//Toolchains may have changed, recompute
	if(!moreComing)
		RecomputeCompilerHashes();
}

/**
	@brief Calculate the hash corresponding to each toolchain we know about

	DOES NOT lock the mutex; must be called only after it's locked.
 */
void NodeManager::RecomputeCompilerHashes()
{
	LogDebug("Recomputing compiler hashes\n");

	//Make a list of every language/architecture pair we know about.
	//The list of languages is architecture specific so we need to know what the options are.
	//It's stupid to wasted time looking for a Verilog compiler for mips-elf.
	set<larch> larches;
	for(auto it : m_nodesByLanguage)
		larches.emplace(it.first);

	//Map of toolchain IDs to hashes
	map<carch, string> currentToolchains;

	//For each toolchain we know about, generate the names
	for(auto x : m_nodesByCompiler)
	{
		string hash = x.first;
		Toolchain* tool = GetAnyToolchainForHash(hash);
		if(tool == NULL)
			continue;

		//Generate the names for each arch/triplet combination
		set<string> names;
		tool->GetCompilerNames(names);
		auto triplets = tool->GetTargetTriplets();
		for(auto arch : triplets)
		{
			for(auto name : names)
			{
				//If nobody has claimed this name/arch yet, take it
				carch c(name, arch);
				if(currentToolchains.find(c) == currentToolchains.end())
				{
					currentToolchains[c] = hash;
					continue;
				}

				//If another node took the tuple already, keep the higher version
				Toolchain* otherTool = GetAnyToolchainForHash(currentToolchains[c]);
				if(tool->CompareVersion(otherTool) >= 0)
					currentToolchains[c] = hash;
			}
		}

	}

	//For each language/architecture, find the best toolchain available
	for(auto x : larches)
	{
		//Initial toolchain: nonexistent
		Toolchain* bestToolchain = NULL;
		string bestHash = "";

		//Loop over all toolchains we have (TODO: only per language? index this somehow?)
		for(auto it : m_nodesByCompiler)
		{
			//Look up the toolchain object for that client
			string hash = it.first;
			Toolchain* tool = GetAnyToolchainForHash(hash);
			if(tool == NULL)
				continue;

			//If we can't compile our platform with this toolchain it's of no value to us :(
			if(!tool->IsLanguageSupported(x.first))
				continue;
			if(!tool->IsArchitectureSupported(x.second))
				continue;

			//See if it's any better than what we have now. Skip it if not
			if((bestToolchain != NULL) && (tool->CompareVersionAndType(bestToolchain) < 0) )
				continue;

			bestToolchain = tool;
			bestHash = hash;
		}

		//Register the generic toolchains
		if(bestToolchain != NULL)
		{
			string lang = MakeStringLowercase(Toolchain::LangToString(x.first));
			currentToolchains[carch(lang + "/generic", x.second)] = bestHash;
		}
	}

	//Update the global toolchain list
	bool changed = (m_toolchainsByName != currentToolchains);
	m_toolchainsByName = currentToolchains;

	/*
	//DEBUG: Print the final mapping
	for(auto it : m_toolchainsByName)
	{
		carch c = it.first;
		string hash = it.second;
		Toolchain* tool = GetAnyToolchainForHash(hash);

		LogDebug("%25s for %20s is %25s (%s)\n",
			c.first.c_str(), c.second.c_str(), tool->GetVersionString().c_str(), hash.c_str());
	}
	*/

	//FIXME: do something more efficient based on what changed
	//For now, just re-run every build script in every working copy.
	if(changed)
	{
		for(auto it : m_workingCopies)
			it.second->RefreshToolchains();
	}
}

/**
	@brief Get a pointer to some node's toolchain for the specified hash.

	The exact choice of node is unpredictable and should not be relied on.

	MUST be called while m_mutex is locked. Do not use the returned pointer once the mutex is unlocked.
 */
Toolchain* NodeManager::GetAnyToolchainForHash(string hash)
{
	//If we couldn't find any instances, then complain
	if(m_nodesByCompiler.find(hash) == m_nodesByCompiler.end())
		return NULL;
	if(m_nodesByCompiler[hash].empty())
		return NULL;

	//Find a client that has this toolchain installed
	clientID id = *m_nodesByCompiler[hash].begin();

	//Look up the toolchain object for that client
	return m_toolchainsByNode[id][hash];
}

/**
	@brief Get a pointer to some node's toolchain for the specified toolchain name and target architecture.

	The exact choice of node is unpredictable and should not be relied on.

	MUST be called while m_mutex is locked. Do not use the returned pointer once the mutex is unlocked.
 */
Toolchain* NodeManager::GetAnyToolchainForName(string arch, string name)
{
	lock_guard<recursive_mutex> lock(m_mutex);
	return GetAnyToolchainForHash(GetToolchainHash(arch, name));
}

/**
	@brief Gets the current hash of the requested toolchain, or the empty string if it doesn't exist.
 */
string NodeManager::GetToolchainHash(string arch, string name)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If we do not have such a toolchain, give up
	carch c(name, arch);
	if(m_toolchainsByName.find(c) == m_toolchainsByName.end())
		return "";
	return m_toolchainsByName[c];
}

/**
	@brief Get the ID of the "golden node" for the specified toolchain hash.

	This functionality is not fully implemented.

	MUST be called while m_mutex is locked. Do not use the returned value once the mutex is unlocked.
 */
clientID NodeManager::GetGoldenNodeForToolchain(string hash)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If we know about the toolchain, but nobody has it, give up
	if(m_nodesByCompiler.find(hash) == m_nodesByCompiler.end())
		return 0;
	auto nodes = m_nodesByCompiler[hash];
	if(nodes.empty())
		return 0;

	//If we have only one node, return it.
	if(nodes.size() == 1)
		return *nodes.begin();

	//If more than one, print a warning and return the first
	//TODO: Pick golden node based on explicit config
	else
	{
		LogWarning("NodeManager::GetGoldenNodeForToolchain() does not have golden config yet\n");
		return *nodes.begin();
	}
}
<|endoftext|>


<commit_before>/*
The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.
*/

#include <algorithm>
#include <string>

using namespace std;

class Solution
{
public:
    // efficient.
    // use math method.
    string getPermutation(int n, int k)
    {
        string base;
        base.reserve(n);
        int total = 1;
        for (int i = 1; i <= n; ++i)
        {
            base.push_back('0' + i);
            total *= i;
        }
        string result;
        if (total < k)
        {
            return result;
        }
        int group = total;
        --k;
        while (n > 0)
        {
            group = group / n;
            int index = k / group;
            result.push_back(base[index]);
            base.erase(base.begin() + index);
            k = k % group;
            --n;
        }
        return result;
    }

    // Time Limit Exceeded
    string getPermutation_normal(int n, int k)
    {
        string base;
        base.reserve(n);
        for (int i = 1; i <= n; ++i)
        {
            base.push_back('0' + i);
        }
        string result;
        int count = 0;
        doPermutation(base, k, 0, count, result);
        return result;
    }

    bool doPermutation(string& base, int k, int index, int& count, string& result)
    {
        if (index == base.size())
        {
            ++count;
            if (count == k)
            {
                result = base;
                return true;
            }
            return false;
        }
        for (int i = index; i < base.size(); ++i)
        {
            std::swap(base[index], base[i]);
            std::sort(base.begin() + index + 1, base.end());
            if (doPermutation(base, k, index + 1, count, result))
            {
                return true;
            }
            std::sort(base.begin() + index, base.end());
        }
        return false;
    }
};

int main(int argc, char* argv[])
{
    Solution s;
    string&& result = s.getPermutation(3, 5);
    printf("%s\n", result.c_str());
    return 0;
}
<commit_msg>add annotation for math<commit_after>/*
The set [1,2,3,…,n] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.
*/

#include <algorithm>
#include <string>

using namespace std;

class Solution
{
public:
    // efficient.
    // use math method.
    string getPermutation(int n, int k)
    {
        string base;
        base.reserve(n);
        int total = 1;
        for (int i = 1; i <= n; ++i)
        {
            base.push_back('0' + i);
            total *= i;
        }
        string result;
        if (total < k)
        {
            return result;
        }
        int group = total;
        --k;
        while (n > 0)
        {
            group = group / n;
            int index = k / group;
            result.push_back(base[index]);
            base.erase(base.begin() + index);
            //k = k % group;  this can also work.
            k = k - index * group;
            --n;
        }
        return result;
    }

    // Time Limit Exceeded
    string getPermutation_normal(int n, int k)
    {
        string base;
        base.reserve(n);
        for (int i = 1; i <= n; ++i)
        {
            base.push_back('0' + i);
        }
        string result;
        int count = 0;
        doPermutation(base, k, 0, count, result);
        return result;
    }

    bool doPermutation(string& base, int k, int index, int& count, string& result)
    {
        if (index == base.size())
        {
            ++count;
            if (count == k)
            {
                result = base;
                return true;
            }
            return false;
        }
        for (int i = index; i < base.size(); ++i)
        {
            std::swap(base[index], base[i]);
            std::sort(base.begin() + index + 1, base.end());
            if (doPermutation(base, k, index + 1, count, result))
            {
                return true;
            }
            std::sort(base.begin() + index, base.end());
        }
        return false;
    }
};

int main(int argc, char* argv[])
{
    Solution s;
    string&& result = s.getPermutation(3, 5);
    printf("%s\n", result.c_str());
    return 0;
}
<|endoftext|>