<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 <link.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

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

namespace __asan {

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

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 *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) {
  return asan_mmap((void*)fixed_addr, size,
                   PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                   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 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 << 20);
  }
  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 close(fd);
}

AsanProcMaps::AsanProcMaps() {
  proc_self_maps_buff_len_ =
      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
                       &proc_self_maps_buff_mmaped_size_, 1 << 20);
  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;
}

struct DlIterateData {
  int count;
  uintptr_t addr;
  uintptr_t offset;
  char *filename;
  size_t filename_size;
};

static int dl_iterate_phdr_callback(struct dl_phdr_info *info,
                                    size_t size, void *raw_data) {
  DlIterateData *data = (DlIterateData*)raw_data;
  int count = data->count++;
  if (info->dlpi_addr > data->addr)
    return 0;
  if (count == 0) {
    // The first item (the main executable) does not have a so name,
    // but we can just read it from /proc/self/exe.
    size_t path_len = readlink("/proc/self/exe",
                               data->filename, data->filename_size - 1);
    data->filename[path_len] = 0;
  } else {
    CHECK(info->dlpi_name);
    real_strncpy(data->filename, info->dlpi_name, data->filename_size);
  }
  data->offset = data->addr - info->dlpi_addr;
  return 1;
}

// Gets the object name and the offset using dl_iterate_phdr.
bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
                                          char filename[],
                                          size_t filename_size) {
  DlIterateData data;
  data.count = 0;
  data.addr = addr;
  data.filename = filename;
  data.filename_size = filename_size;
  if (dl_iterate_phdr(dl_iterate_phdr_callback, &data)) {
    *offset = data.offset;
    return true;
  }
  return false;
}

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;
    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;
  // 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) {
    stack_bottom_ = stack_top_ - kMaxThreadStackSize;
  }
  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_);
}

}  // namespace __asan

#endif  // __linux__
<commit_msg>[asan] Implement GetObjectNameAndOffset on ARM.<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 <link.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

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

namespace __asan {

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

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 *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) {
  return asan_mmap((void*)fixed_addr, size,
                   PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                   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 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 << 20);
  }
  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 close(fd);
}

AsanProcMaps::AsanProcMaps() {
  proc_self_maps_buff_len_ =
      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
                       &proc_self_maps_buff_mmaped_size_, 1 << 20);
  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;
}

#ifdef __arm__

// 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) {
  AsanProcMaps proc_maps;
  uintptr_t start, end, file_offset;
  while (proc_maps.Next(&start, &end, &file_offset, filename, filename_size)) {
    if (addr >= start && addr < end) {
      *offset = (addr - start) + file_offset;
      return true;
    }
  }
  if (filename_size)
    filename[0] = '\0';
  return false;
}

#else // __arm__

struct DlIterateData {
  int count;
  uintptr_t addr;
  uintptr_t offset;
  char *filename;
  size_t filename_size;
};

static int dl_iterate_phdr_callback(struct dl_phdr_info *info,
                                    size_t size, void *raw_data) {
  DlIterateData *data = (DlIterateData*)raw_data;
  int count = data->count++;
  if (info->dlpi_addr > data->addr)
    return 0;
  if (count == 0) {
    // The first item (the main executable) does not have a so name,
    // but we can just read it from /proc/self/exe.
    size_t path_len = readlink("/proc/self/exe",
                               data->filename, data->filename_size - 1);
    data->filename[path_len] = 0;
  } else {
    CHECK(info->dlpi_name);
    real_strncpy(data->filename, info->dlpi_name, data->filename_size);
  }
  data->offset = data->addr - info->dlpi_addr;
  return 1;
}

// Gets the object name and the offset using dl_iterate_phdr.
bool AsanProcMaps::GetObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
                                          char filename[],
                                          size_t filename_size) {
  DlIterateData data;
  data.count = 0;
  data.addr = addr;
  data.filename = filename;
  data.filename_size = filename_size;
  if (dl_iterate_phdr(dl_iterate_phdr_callback, &data)) {
    *offset = data.offset;
    return true;
  }
  return false;
}

#endif // __arm__

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;
    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;
  // 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) {
    stack_bottom_ = stack_top_ - kMaxThreadStackSize;
  }
  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_);
}

}  // namespace __asan

#endif  // __linux__
<|endoftext|>


<commit_before>//
//  PackageReporter.cpp
//  Emojicode
//
//  Created by Theo Weidmann on 02/05/16.
//  Copyright © 2016 Theo Weidmann. All rights reserved.
//

#include <cstring>
#include <vector>
#include <list>
#include <map>
#include "utf8.h"
#include "Function.hpp"
#include "Class.hpp"
#include "EmojicodeCompiler.hpp"
#include "Enum.hpp"
#include "Protocol.hpp"
#include "PackageReporter.hpp"
#include "TypeContext.hpp"

enum ReturnManner {
    Return,
    NoReturn,
    CanReturnNothingness
};

void reportDocumentation(const EmojicodeString &documentation) {
    if (documentation.size() == 0) {
        return;
    }

    const char *d = documentation.utf8CString();
    printf("\"documentation\":");
    printJSONStringToFile(d, stdout);
    putc(',', stdout);
    delete [] d;
}

void reportType(const char *key, Type type, TypeContext tc) {
    auto returnTypeName = type.toString(tc, false).c_str();

    if (key) {
        printf("\"%s\": {\"package\": \"%s\", \"name\": \"%s\", \"optional\": %s}",
               key, type.typePackage(), returnTypeName, type.optional() ? "true" : "false");
    }
    else {
        printf("{\"package\": \"%s\", \"name\": \"%s\", \"optional\": %s}",
               type.typePackage(), returnTypeName, type.optional() ? "true" : "false");
    }
}

void commaPrinter(bool *b) {
    if (*b) {
        putc(',', stdout);
    }
    *b = true;
}

void reportGenericArguments(std::map<EmojicodeString, Type> map, std::vector<Type> constraints,
                            size_t superCount, TypeContext tc) {
    printf("\"genericArguments\": [");

    auto gans = std::vector<EmojicodeString>(map.size());
    for (auto it : map) {
        gans[it.second.reference - superCount] = it.first;
    }

    auto reported = false;

    for (size_t i = 0; i < gans.size(); i++) {
        auto gan = gans[i];
        auto utf8 = gan.utf8CString();
        commaPrinter(&reported);
        printf("{\"name\": ");
        printJSONStringToFile(utf8, stdout);
        printf(",");
        reportType("constraint", constraints[i], tc);
        printf("}");
        delete [] utf8;
    }

    printf("],");
}

void reportFunctionInformation(Function *p, ReturnManner returnm, bool last, TypeContext tc) {
    ecCharToCharStack(p->name, nameString);

    printf("{");
    printf("\"name\": \"%s\",", nameString);
    if (p->access == PRIVATE) {
        printf("\"access\": \"🔒\",");
    }
    else if (p->access == PROTECTED) {
        printf("\"access\": \"🔐\",");
    }
    else {
        printf("\"access\": \"🔓\",");
    }

    if (returnm == Return) {
        reportType("returnType", p->returnType, tc);
        putc(',', stdout);
    }
    else if (returnm == CanReturnNothingness) {
        printf("\"canReturnNothingness\": true,");
    }

    reportGenericArguments(p->genericArgumentVariables, p->genericArgumentConstraints, 0, tc);
    reportDocumentation(p->documentationToken);

    printf("\"arguments\": [");
    for (int i = 0; i < p->arguments.size(); i++) {
        printf("{");
        auto argument = p->arguments[i];

        const char *varname = argument.name.value.utf8CString();

        reportType("type", argument.type, tc);
        printf(",\"name\":");
        printJSONStringToFile(varname, stdout);
        printf("}%s", i + 1 == p->arguments.size() ? "" : ",");

        delete [] varname;
    }
    printf("]");

    printf("}%s", last ? "" : ",");
}

void reportPackage(Package *package) {
    std::list<Enum *> enums;
    std::list<Class *> classes;
    std::list<Protocol *> protocols;

    for (auto exported : package->exportedTypes()) { // TODO: Add Value Type
        switch (exported.type.type()) {
            case TT_CLASS:
                classes.push_back(exported.type.eclass());
                break;
            case TT_ENUM:
                enums.push_back(exported.type.eenum());
                break;
            case TT_PROTOCOL:
                protocols.push_back(exported.type.protocol());
                break;
            default:
                break;
        }
    }

    bool printedClass = false;
    printf("{");
    printf("\"classes\": [");
    for (auto eclass : classes) {
        if (printedClass) {
            putchar(',');
        }
        printedClass = true;

        printf("{");

        ecCharToCharStack(eclass->name(), className);
        printf("\"name\": \"%s\",", className);

        reportGenericArguments(eclass->ownGenericArgumentVariables(), eclass->genericArgumentConstraints(),
                               eclass->superGenericArguments().size(), TypeContext(Type(eclass)));
        reportDocumentation(eclass->documentation());

        if (eclass->superclass) {
            ecCharToCharStack(eclass->superclass->name(), superClassName);
            printf("\"superclass\": {\"package\": \"%s\", \"name\": \"%s\"},",
                   eclass->superclass->package()->name(), superClassName);
        }

        printf("\"methods\": [");
        for (size_t i = 0; i < eclass->methodList().size(); i++) {
            Method *method = eclass->methodList()[i];
            reportFunctionInformation(method, Return, i + 1 == eclass->methodList().size(),
                                       TypeContext(Type(eclass), method));
        }
        printf("],");

        printf("\"initializers\": [");
        for (size_t i = 0; i < eclass->initializerList().size(); i++) {
            Initializer *initializer = eclass->initializerList()[i];
            reportFunctionInformation(initializer, initializer->canReturnNothingness ? CanReturnNothingness : NoReturn,
                                       i + 1 == eclass->initializerList().size(),
                                       TypeContext(Type(eclass), initializer));
        }
        printf("],");

        printf("\"classMethods\": [");
        for (size_t i = 0; i < eclass->classMethodList().size(); i++) {
            ClassMethod *classMethod = eclass->classMethodList()[i];
            reportFunctionInformation(classMethod, Return, eclass->classMethodList().size() == i + 1,
                                       TypeContext(Type(eclass), classMethod));
        }
        printf("],");

        printf("\"conformsTo\": [");
        bool printedProtocol = false;
        for (auto protocol : eclass->protocols()) {
            commaPrinter(&printedProtocol);
            reportType(nullptr, protocol, TypeContext(Type(eclass)));
        }
        printf("]}");
    }
    printf("],");

    printf("\"enums\": [");
    bool printedEnum = false;
    for (auto eenum : enums) {
        if (printedEnum) {
            putchar(',');
        }
        printf("{");

        printedEnum = true;

        ecCharToCharStack(eenum->name(), enumName);
        printf("\"name\": \"%s\",", enumName);

        reportDocumentation(eenum->documentation());

        bool printedValue = false;
        printf("\"values\": [");
        for (auto it : eenum->values()) {
            ecCharToCharStack(it.first, value);
            if (printedValue) {
                putchar(',');
            }
            printf("\"%s\"", value);
            printedValue = true;
        }
        printf("]}");
    }
    printf("],");

    printf("\"protocols\": [");
    bool printedProtocol = false;
    for (auto protocol : protocols) {
        if (printedProtocol) {
            putchar(',');
        }
        printedProtocol = true;
        printf("{");

        ecCharToCharStack(protocol->name(), protocolName);
        printf("\"name\": \"%s\",", protocolName);

        reportGenericArguments(protocol->ownGenericArgumentVariables(), protocol->genericArgumentConstraints(),
                               protocol->superGenericArguments().size(), Type(protocol, false));
        reportDocumentation(protocol->documentation());

        printf("\"methods\": [");
        for (size_t i = 0; i < protocol->methods().size(); i++) {
            Method *method = protocol->methods()[i];
            reportFunctionInformation(method, Return, i + 1 == protocol->methods().size(),
                                       TypeContext(Type(protocol, false)));
        }
        printf("]}");
    }
    printf("]");
    printf("}");
}<commit_msg>📃 Report on value types<commit_after>//
//  PackageReporter.cpp
//  Emojicode
//
//  Created by Theo Weidmann on 02/05/16.
//  Copyright © 2016 Theo Weidmann. All rights reserved.
//

#include <cstring>
#include <vector>
#include <list>
#include <map>
#include "utf8.h"
#include "Function.hpp"
#include "Class.hpp"
#include "EmojicodeCompiler.hpp"
#include "Enum.hpp"
#include "Protocol.hpp"
#include "PackageReporter.hpp"
#include "TypeContext.hpp"
#include "ValueType.hpp"

enum ReturnManner {
    Return,
    NoReturn,
    CanReturnNothingness
};

void reportDocumentation(const EmojicodeString &documentation) {
    if (documentation.size() == 0) {
        return;
    }

    const char *d = documentation.utf8CString();
    printf("\"documentation\":");
    printJSONStringToFile(d, stdout);
    putc(',', stdout);
    delete [] d;
}

void reportType(const char *key, Type type, TypeContext tc) {
    auto returnTypeName = type.toString(tc, false).c_str();

    if (key) {
        printf("\"%s\": {\"package\": \"%s\", \"name\": \"%s\", \"optional\": %s}",
               key, type.typePackage(), returnTypeName, type.optional() ? "true" : "false");
    }
    else {
        printf("{\"package\": \"%s\", \"name\": \"%s\", \"optional\": %s}",
               type.typePackage(), returnTypeName, type.optional() ? "true" : "false");
    }
}

void commaPrinter(bool *b) {
    if (*b) {
        putc(',', stdout);
    }
    *b = true;
}

void reportGenericArguments(std::map<EmojicodeString, Type> map, std::vector<Type> constraints,
                            size_t superCount, TypeContext tc) {
    printf("\"genericArguments\": [");

    auto gans = std::vector<EmojicodeString>(map.size());
    for (auto it : map) {
        gans[it.second.reference - superCount] = it.first;
    }

    auto reported = false;

    for (size_t i = 0; i < gans.size(); i++) {
        auto gan = gans[i];
        auto utf8 = gan.utf8CString();
        commaPrinter(&reported);
        printf("{\"name\": ");
        printJSONStringToFile(utf8, stdout);
        printf(",");
        reportType("constraint", constraints[i], tc);
        printf("}");
        delete [] utf8;
    }

    printf("],");
}

void reportFunctionInformation(Function *p, ReturnManner returnm, bool last, TypeContext tc) {
    ecCharToCharStack(p->name, nameString);

    printf("{");
    printf("\"name\": \"%s\",", nameString);
    if (p->access == PRIVATE) {
        printf("\"access\": \"🔒\",");
    }
    else if (p->access == PROTECTED) {
        printf("\"access\": \"🔐\",");
    }
    else {
        printf("\"access\": \"🔓\",");
    }

    if (returnm == Return) {
        reportType("returnType", p->returnType, tc);
        putc(',', stdout);
    }
    else if (returnm == CanReturnNothingness) {
        printf("\"canReturnNothingness\": true,");
    }

    reportGenericArguments(p->genericArgumentVariables, p->genericArgumentConstraints, 0, tc);
    reportDocumentation(p->documentationToken);

    printf("\"arguments\": [");
    for (int i = 0; i < p->arguments.size(); i++) {
        printf("{");
        auto argument = p->arguments[i];

        const char *varname = argument.name.value.utf8CString();

        reportType("type", argument.type, tc);
        printf(",\"name\":");
        printJSONStringToFile(varname, stdout);
        printf("}%s", i + 1 == p->arguments.size() ? "" : ",");

        delete [] varname;
    }
    printf("]");

    printf("}%s", last ? "" : ",");
}

void reportPackage(Package *package) {
    std::list<Enum *> enums;
    std::list<Class *> classes;
    std::list<Protocol *> protocols;
    std::list<ValueType *> valueTypes;

    for (auto exported : package->exportedTypes()) { // TODO: Add Value Type
        switch (exported.type.type()) {
            case TT_CLASS:
                classes.push_back(exported.type.eclass());
                break;
            case TT_ENUM:
                enums.push_back(exported.type.eenum());
                break;
            case TT_PROTOCOL:
                protocols.push_back(exported.type.protocol());
                break;
            case TT_VALUE_TYPE:
                valueTypes.push_back(exported.type.valueType());
                break;
            default:
                break;
        }
    }

    printf("{");

    bool printedValueType = false;
    printf("\"valueTypes\": [");
    for (auto vt : valueTypes) {
        auto vtcontext = TypeContext(Type(vt, false));
        if (printedValueType) {
            putchar(',');
        }
        printedValueType = true;

        printf("{");

        ecCharToCharStack(vt->name(), className);
        printf("\"name\": \"%s\",", className);

        reportGenericArguments(vt->ownGenericArgumentVariables(), vt->genericArgumentConstraints(),
                               vt->superGenericArguments().size(), vtcontext);
        reportDocumentation(vt->documentation());

        printf("\"methods\": [");
        for (size_t i = 0; i < vt->methodList().size(); i++) {
            Method *method = vt->methodList()[i];
            reportFunctionInformation(method, Return, i + 1 == vt->methodList().size(),
                                      TypeContext(Type(vt, false), method));
        }
        printf("],");

        printf("\"initializers\": [");
        for (size_t i = 0; i < vt->initializerList().size(); i++) {
            Initializer *initializer = vt->initializerList()[i];
            reportFunctionInformation(initializer, initializer->canReturnNothingness ? CanReturnNothingness : NoReturn,
                                      i + 1 == vt->initializerList().size(),
                                      TypeContext(Type(vt, false), initializer));
        }
        printf("],");

        printf("\"classMethods\": [");
        for (size_t i = 0; i < vt->classMethodList().size(); i++) {
            ClassMethod *classMethod = vt->classMethodList()[i];
            reportFunctionInformation(classMethod, Return, vt->classMethodList().size() == i + 1,
                                      TypeContext(Type(vt, false), classMethod));
        }
        printf("]}");
    }
    printf("],");

    bool printedClass = false;
    printf("\"classes\": [");
    for (auto eclass : classes) {
        if (printedClass) {
            putchar(',');
        }
        printedClass = true;

        printf("{");

        ecCharToCharStack(eclass->name(), className);
        printf("\"name\": \"%s\",", className);

        reportGenericArguments(eclass->ownGenericArgumentVariables(), eclass->genericArgumentConstraints(),
                               eclass->superGenericArguments().size(), TypeContext(Type(eclass)));
        reportDocumentation(eclass->documentation());

        if (eclass->superclass) {
            ecCharToCharStack(eclass->superclass->name(), superClassName);
            printf("\"superclass\": {\"package\": \"%s\", \"name\": \"%s\"},",
                   eclass->superclass->package()->name(), superClassName);
        }

        printf("\"methods\": [");
        for (size_t i = 0; i < eclass->methodList().size(); i++) {
            Method *method = eclass->methodList()[i];
            reportFunctionInformation(method, Return, i + 1 == eclass->methodList().size(),
                                       TypeContext(Type(eclass), method));
        }
        printf("],");

        printf("\"initializers\": [");
        for (size_t i = 0; i < eclass->initializerList().size(); i++) {
            Initializer *initializer = eclass->initializerList()[i];
            reportFunctionInformation(initializer, initializer->canReturnNothingness ? CanReturnNothingness : NoReturn,
                                       i + 1 == eclass->initializerList().size(),
                                       TypeContext(Type(eclass), initializer));
        }
        printf("],");

        printf("\"classMethods\": [");
        for (size_t i = 0; i < eclass->classMethodList().size(); i++) {
            ClassMethod *classMethod = eclass->classMethodList()[i];
            reportFunctionInformation(classMethod, Return, eclass->classMethodList().size() == i + 1,
                                       TypeContext(Type(eclass), classMethod));
        }
        printf("],");

        printf("\"conformsTo\": [");
        bool printedProtocol = false;
        for (auto protocol : eclass->protocols()) {
            commaPrinter(&printedProtocol);
            reportType(nullptr, protocol, TypeContext(Type(eclass)));
        }
        printf("]}");
    }
    printf("],");

    printf("\"enums\": [");
    bool printedEnum = false;
    for (auto eenum : enums) {
        if (printedEnum) {
            putchar(',');
        }
        printf("{");

        printedEnum = true;

        ecCharToCharStack(eenum->name(), enumName);
        printf("\"name\": \"%s\",", enumName);

        reportDocumentation(eenum->documentation());

        bool printedValue = false;
        printf("\"values\": [");
        for (auto it : eenum->values()) {
            ecCharToCharStack(it.first, value);
            if (printedValue) {
                putchar(',');
            }
            printf("\"%s\"", value);
            printedValue = true;
        }
        printf("]}");
    }
    printf("],");

    printf("\"protocols\": [");
    bool printedProtocol = false;
    for (auto protocol : protocols) {
        if (printedProtocol) {
            putchar(',');
        }
        printedProtocol = true;
        printf("{");

        ecCharToCharStack(protocol->name(), protocolName);
        printf("\"name\": \"%s\",", protocolName);

        reportGenericArguments(protocol->ownGenericArgumentVariables(), protocol->genericArgumentConstraints(),
                               protocol->superGenericArguments().size(), Type(protocol, false));
        reportDocumentation(protocol->documentation());

        printf("\"methods\": [");
        for (size_t i = 0; i < protocol->methods().size(); i++) {
            Method *method = protocol->methods()[i];
            reportFunctionInformation(method, Return, i + 1 == protocol->methods().size(),
                                       TypeContext(Type(protocol, false)));
        }
        printf("]}");
    }
    printf("]");
    printf("}");
}<|endoftext|>


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

#include <typeindex>
#include <typeinfo>
#include <unordered_set>

#include "ngraph/node.hpp"
#include "ngraph/ops/avg_pool.hpp"
#include "ngraph/ops/convolution.hpp"
#include "ngraph/ops/max_pool.hpp"

#include "mkldnn_utils.hpp"

namespace ngraph
{
    namespace runtime
    {
        namespace cpu
        {
            namespace mkldnn_utils
            {
#define TI(x) std::type_index(typeid(x))

                const std::unordered_set<std::type_index> s_op_registry{
                    TI(ngraph::op::AvgPool),
                    TI(ngraph::op::AvgPoolBackprop),
                    TI(ngraph::op::Convolution),
                    TI(ngraph::op::ConvolutionBackpropData),
                    TI(ngraph::op::ConvolutionBackpropFilters),
                    TI(ngraph::op::MaxPool)};

                bool IsMKLDNNOp(ngraph::Node& op)
                {
                    return (s_op_registry.find(TI(op)) != s_op_registry.end());
                }

                mkldnn::memory::format
                    CreateNativeDataFormat(const ngraph::runtime::cpu::LayoutDescriptor& layout)
                {
                    switch (layout.get_shape().size())
                    {
                    case 1: return mkldnn::memory::format::x;
                    case 2: return mkldnn::memory::format::nc;
                    case 4: return mkldnn::memory::format::nchw;
                    default: return mkldnn::memory::format::format_undef;
                    }
                }
            }
        }
    }
}
<commit_msg>Added MaxPoolBackprop to the mkldnn_util<commit_after>/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include <typeindex>
#include <typeinfo>
#include <unordered_set>

#include "ngraph/node.hpp"
#include "ngraph/ops/avg_pool.hpp"
#include "ngraph/ops/convolution.hpp"
#include "ngraph/ops/max_pool.hpp"

#include "mkldnn_utils.hpp"

namespace ngraph
{
    namespace runtime
    {
        namespace cpu
        {
            namespace mkldnn_utils
            {
#define TI(x) std::type_index(typeid(x))

                const std::unordered_set<std::type_index> s_op_registry{
                    TI(ngraph::op::AvgPool),
                    TI(ngraph::op::AvgPoolBackprop),
                    TI(ngraph::op::Convolution),
                    TI(ngraph::op::ConvolutionBackpropData),
                    TI(ngraph::op::ConvolutionBackpropFilters),
                    TI(ngraph::op::MaxPool),
                    T1(ngraph::op::MaxPoolBackprop)};

                bool IsMKLDNNOp(ngraph::Node& op)
                {
                    return (s_op_registry.find(TI(op)) != s_op_registry.end());
                }

                mkldnn::memory::format
                    CreateNativeDataFormat(const ngraph::runtime::cpu::LayoutDescriptor& layout)
                {
                    switch (layout.get_shape().size())
                    {
                    case 1: return mkldnn::memory::format::x;
                    case 2: return mkldnn::memory::format::nc;
                    case 4: return mkldnn::memory::format::nchw;
                    default: return mkldnn::memory::format::format_undef;
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>
// define before any includes
#define BOOST_SPIRIT_THREADSAFE

#include <dirent.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cassert>
#include <strings.h>
#include <algorithm>
#include <exception>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <tuple>
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/atomic.hpp>
#include <boost/timer/timer.hpp>
#include "proj.hpp"
#include "path-mapper.h"

#include "git-revision.h"
#define VERSION "0.0.0"

#if __GNUC__ >= 3
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif

#define CANVAS_SCALE 8
#define RENDER_SIZE (TILE_SIZE*(CANVAS_SCALE+1))

// typedef std::tuple<uint32_t, uint32_t, uint32_t> triplet;
// Since boost::lockfree::queue supports only a type that "has_trivial_assign",
// we encode a triple (zoom, x, y) into a single 64bit value divided as (16, 24, 24)-bits.
typedef uint64_t triplet;
static inline triplet pack(uint32_t z, uint32_t x, uint32_t y) {
    z &= 0xFFFF;
    x &= 0xFFFFFF;
    y &= 0xFFFFFF;

    triplet val = z;
    val <<= 24;
    val |= x;
    val <<= 24;
    val |= y;
    return val;
}
static inline void unpack(triplet val, uint32_t& z, uint32_t& x, uint32_t& y) {
    y = (uint32_t)(val & 0xFFFFFF);
    val >>= 24;
    x = (uint32_t)(val & 0xFFFFFF);
    val >>= 24;
    z = (uint32_t)(val & 0xFFFF);
}
boost::lockfree::queue<triplet, boost::lockfree::capacity<1024>> queue;
boost::atomic<bool> done (false);
boost::atomic<uint64_t> removed(0);     // # of tiles removed.
boost::atomic<uint64_t> skipped(0);     // # of tiles that are non-existent or failed to unlink(), thus skipped.
bool echo_back = false;                 // If true, print each processed line to stdout, invariant during the execution
boost::timer::cpu_timer* timer;

void worker(const boost::filesystem::path& base_path) {

    const std::string& base_as_string = base_path.string();
    size_t base_len  = base_as_string.length();

    // tile_path holds the full path base_path/nnn/.../nnn.png to remove
    char* tile_path = (char*)alloca(base_len + 28);
    strncpy(tile_path, base_as_string.c_str(), base_len);

    // tp_head points to the end of base_path in tile_path
    char* tp_head = tile_path + base_len;
    if (tile_path[base_len-1] != '/') {
        tile_path[base_len] = '/';
        ++tp_head;
    }

#define EXISTS(p) boost::filesystem::exists(p)
#define DO_REMOVE(tile_id) { \
    unpack(tile_id, z, x, y); \
    to_physical_path(tp_head, z, x, y, PNG); \
    if (!EXISTS( (boost::filesystem::path(tile_path)) )) { \
        ++skipped; \
    } else { \
        if ( likely(unlink(tile_path) == 0) ) { \
            ++removed; \
            if (echo_back) { \
                printf("%u/%u/%u\n", z, x, y); \
            } \
        } else { \
            ++skipped; \
        } \
    } \
}
    triplet tile_id;
    uint32_t z, x, y;
    while (!done) {
        while (queue.pop(tile_id)) {
            DO_REMOVE(tile_id);
        }
    }

    while (queue.pop(tile_id)) {
        DO_REMOVE(tile_id)
    }
}

void dry_worker(const boost::filesystem::path& base_path) {

    const std::string& base_as_string = base_path.string();
    size_t base_len  = base_as_string.length();

    // tile_path holds the full path base_path/nnn/.../nnn.png to remove
    char* tile_path = (char*)alloca(base_len + 28);
    strncpy(tile_path, base_as_string.c_str(), base_len);

    // tp_head points to the end of base_path in tile_path
    char* tp_head = tile_path + base_len;
    if (tile_path[base_len-1] != '/') {
        tile_path[base_len] = '/';
        ++tp_head;
    }

#define EXISTS(p) boost::filesystem::exists(p)
#define DO_DRY_RUN(tile_id) { \
    unpack(tile_id, z, x, y); \
    to_physical_path(tp_head, z, x, y, PNG); \
    if (!EXISTS( (boost::filesystem::path(tile_path)) )) { \
        ++skipped; \
    } else { \
        printf("%s will be removed\n", tile_path); \
        ++removed; \
    } \
}
    triplet tile_id;
    uint32_t z, x, y;
    while (!done) {
        while (queue.pop(tile_id)) {
            DO_DRY_RUN(tile_id);
        }
    }

    while (queue.pop(tile_id)) {
        DO_DRY_RUN(tile_id)
    }
}

/*
expire-tiles -p base-path [-f expire-list-file] [-t num-threads]
removes tiles listed in expire-list-file under base-path.
Options:
    -p,--prefix base-path: a valid directory name, into which tiles are rendered
    -f,--file expire-list-file: the list of tiles to expire:
                                a tile list consists of lines, each of which is slash-delimited triple of integers
                                    z/x/y
                                each line denotes the logical path of a tile, without suffix.
                                Example:
                                    15/5252/11331
                                    15/5253/11331
                                    15/7540/11128
                                    ...
                                When this option is omitted, or '-' is given, stdin is used.
    -t,--threads n: the number of threads to render
        + defaults to boost::thread::hardware_concurrency()
    -d,--dry-run
        + only echoes the tile paths to be expired, without actual removing
    -e,--echo-back
        + prints each successfully processed line to stdout, this is useful when pipelining another process such as re-rendering
    -v,--version
    -h,--help
*/
int main(int ac, char** av) {
    try {
        std::string base;
        std::string list_file;
        unsigned int nthreads;
        bool dry_run = false;
        /** Define and parse the program options
        */
        namespace po = boost::program_options;
        po::options_description desc(
            "expire-tiles -p base-path [-f expire-list-file] [-t num-threads]\n"
            "removes tiles listed in expire-list-file under base-path.\n\n"
            "Options"
        );
        desc.add_options()
            ("help,h", "Prints help messages")
            ("version,v", "Prints version info.")
            ("prefix,p", po::value<std::string>(&base)->value_name("base-path")->required(), "Specifies the base directory into which tile are rendered")
            ("file,f", po::value<std::string>(&list_file)->value_name("expire-list-file")->default_value("(stdin)"), "Specifies the list of tiles to expire")
            ("echo-back,e", "prints each successfully processed line to stdout, this is useful when pipelining another process such as re-rendering")
            ("threads,t",
                po::value<unsigned int>(&nthreads)->value_name("n")->default_value(boost::thread::hardware_concurrency()),
                "Specifies the number of threas to render\n"
                "  + defaults to boost::thread::hardware_concurrency()")
            ("dry-run,d",
                "Only estimates the number of tiles, does not actually render\n")
        ;
        if (ac <= 1) {
            // No options are given.
            // Just print the usage w.o. error messages.
            std::cerr << desc;
            return 0;
        }
        po::variables_map vm;

        try {
            po::store(po::command_line_parser(ac, av).options(desc).run(), vm); // throws on error

            // --help
            if ( vm.count("help")  ) {
                std::cerr << desc;
                return 0;
            }

            if ( vm.count("version") ) {
                std::cout << (
                    VERSION " (commit: " GIT_REVISION_SHORT ")"
                ) << std::endl;
                return 0;
            }

            // --dry-run
            if ( vm.count("dry-run") ) {
                dry_run = true;
            }

            // --echo-back
            if ( vm.count("echo-back") ) {
                echo_back = true;
            }

            po::notify(vm); // throws on error, so do after help in case
                            // there are any problems
            if ( !vm.count("expire-list-file") || list_file == "(stdin)") {
                list_file = "-";
            }

        } catch(po::required_option& e) {
            std::cerr << desc << std::endl;
            std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
            return -1;
        } catch(po::error& e) {
            std::cerr << desc << std::endl;
            std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
            return -1;
        }

        // Check if base-path is really there.
        const boost::filesystem::path base_path(base);
        if (!boost::filesystem::exists(base)) {
            std::cerr << "ERROR: The base path " << base << " does not exist." << std::endl << std::endl;
            return -1;
        }

        // Open the list file
        std::istream* in;
        if (list_file == "-") {
            in = &std::cin;
        } else {
            try {
                in = new std::ifstream(list_file);
            } catch (std::runtime_error& e) {
                std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
                return -1;
            }
        }
        std::cout
            << "Now expiration begins:" << std::endl
            << "  Base path : " << base_path.string() << std::endl
            << "  List file : " << (base == "-" ? "(stdin)" : list_file) << std::endl
        ;
        timer = new boost::timer::cpu_timer;

        // Awake renderer threads
        boost::thread_group consumer_threads;
        for (int i = 0; i != nthreads; ++i) {
            consumer_threads.create_thread(boost::bind( dry_run ? dry_worker : worker, base_path));
        }

        // Let it run!
        try {
            std::string line;
            uint64_t lineno = 0;
            uint32_t z, x, y;
            std::getline(*in, line);
            while (std::getline(*in, line)) {
                ++lineno;
                std::vector<std::string> tokens;
                boost::split(tokens, line, boost::is_from_range('/','/'));
                if (tokens.size() != 3 ||
                    !boost::conversion::try_lexical_convert<uint32_t>(tokens[0], z) ||
                    !boost::conversion::try_lexical_convert<uint32_t>(tokens[1], x) ||
                    !boost::conversion::try_lexical_convert<uint32_t>(tokens[2], y) ) {
                    std::cerr << "WARN: skipped illfomed line: " << line << " (line at " << lineno << ")" << std::endl;
                }
                uint64_t tile_id = pack(z, x, y);
                while (!queue.push(tile_id)) {}
            }
        } catch (std::runtime_error& e) {
            std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
            return -1;
        }
        done = true;
        consumer_threads.join_all();

        if (in != &std::cin) {
            delete in;
        }

        std::cout
            << timer->format() << std::endl
            << removed << " tiles removed." << std::endl
            << skipped << " tiles did not exist or could not unlink(), thus skipped." << std::endl
            << "Completed!" << std::endl;
        ;
    } catch(std::exception& e) {
        std::cerr << "Unhandled Exception reached the top of main: "
              << e.what() << ", application will now exit" << std::endl;
        return -1;

    }
    return 0;
}
<commit_msg>Swipe away boost::conversion::try_lexical_convert(), which is only available w. boost >= 1.56<commit_after>
// define before any includes
#define BOOST_SPIRIT_THREADSAFE

#include <dirent.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cassert>
#include <strings.h>
#include <algorithm>
#include <exception>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <tuple>
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/atomic.hpp>
#include <boost/timer/timer.hpp>
#include "proj.hpp"
#include "path-mapper.h"

#include "git-revision.h"
#define VERSION "0.0.0"

#if __GNUC__ >= 3
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif

#define CANVAS_SCALE 8
#define RENDER_SIZE (TILE_SIZE*(CANVAS_SCALE+1))

// typedef std::tuple<uint32_t, uint32_t, uint32_t> triplet;
// Since boost::lockfree::queue supports only a type that "has_trivial_assign",
// we encode a triple (zoom, x, y) into a single 64bit value divided as (16, 24, 24)-bits.
typedef uint64_t triplet;
static inline triplet pack(uint32_t z, uint32_t x, uint32_t y) {
    z &= 0xFFFF;
    x &= 0xFFFFFF;
    y &= 0xFFFFFF;

    triplet val = z;
    val <<= 24;
    val |= x;
    val <<= 24;
    val |= y;
    return val;
}
static inline void unpack(triplet val, uint32_t& z, uint32_t& x, uint32_t& y) {
    y = (uint32_t)(val & 0xFFFFFF);
    val >>= 24;
    x = (uint32_t)(val & 0xFFFFFF);
    val >>= 24;
    z = (uint32_t)(val & 0xFFFF);
}
boost::lockfree::queue<triplet, boost::lockfree::capacity<1024>> queue;
boost::atomic<bool> done (false);
boost::atomic<uint64_t> removed(0);     // # of tiles removed.
boost::atomic<uint64_t> skipped(0);     // # of tiles that are non-existent or failed to unlink(), thus skipped.
bool echo_back = false;                 // If true, print each processed line to stdout, invariant during the execution
boost::timer::cpu_timer* timer;

void worker(const boost::filesystem::path& base_path) {

    const std::string& base_as_string = base_path.string();
    size_t base_len  = base_as_string.length();

    // tile_path holds the full path base_path/nnn/.../nnn.png to remove
    char* tile_path = (char*)alloca(base_len + 28);
    strncpy(tile_path, base_as_string.c_str(), base_len);

    // tp_head points to the end of base_path in tile_path
    char* tp_head = tile_path + base_len;
    if (tile_path[base_len-1] != '/') {
        tile_path[base_len] = '/';
        ++tp_head;
    }

#define EXISTS(p) boost::filesystem::exists(p)
#define DO_REMOVE(tile_id) { \
    unpack(tile_id, z, x, y); \
    to_physical_path(tp_head, z, x, y, PNG); \
    if (!EXISTS( (boost::filesystem::path(tile_path)) )) { \
        ++skipped; \
    } else { \
        if ( likely(unlink(tile_path) == 0) ) { \
            ++removed; \
            if (echo_back) { \
                printf("%u/%u/%u\n", z, x, y); \
            } \
        } else { \
            ++skipped; \
        } \
    } \
}
    triplet tile_id;
    uint32_t z, x, y;
    while (!done) {
        while (queue.pop(tile_id)) {
            DO_REMOVE(tile_id);
        }
    }

    while (queue.pop(tile_id)) {
        DO_REMOVE(tile_id)
    }
}

void dry_worker(const boost::filesystem::path& base_path) {

    const std::string& base_as_string = base_path.string();
    size_t base_len  = base_as_string.length();

    // tile_path holds the full path base_path/nnn/.../nnn.png to remove
    char* tile_path = (char*)alloca(base_len + 28);
    strncpy(tile_path, base_as_string.c_str(), base_len);

    // tp_head points to the end of base_path in tile_path
    char* tp_head = tile_path + base_len;
    if (tile_path[base_len-1] != '/') {
        tile_path[base_len] = '/';
        ++tp_head;
    }

#define EXISTS(p) boost::filesystem::exists(p)
#define DO_DRY_RUN(tile_id) { \
    unpack(tile_id, z, x, y); \
    to_physical_path(tp_head, z, x, y, PNG); \
    if (!EXISTS( (boost::filesystem::path(tile_path)) )) { \
        ++skipped; \
    } else { \
        printf("%s will be removed\n", tile_path); \
        ++removed; \
    } \
}
    triplet tile_id;
    uint32_t z, x, y;
    while (!done) {
        while (queue.pop(tile_id)) {
            DO_DRY_RUN(tile_id);
        }
    }

    while (queue.pop(tile_id)) {
        DO_DRY_RUN(tile_id)
    }
}

/*
expire-tiles -p base-path [-f expire-list-file] [-t num-threads]
removes tiles listed in expire-list-file under base-path.
Options:
    -p,--prefix base-path: a valid directory name, into which tiles are rendered
    -f,--file expire-list-file: the list of tiles to expire:
                                a tile list consists of lines, each of which is slash-delimited triple of integers
                                    z/x/y
                                each line denotes the logical path of a tile, without suffix.
                                Example:
                                    15/5252/11331
                                    15/5253/11331
                                    15/7540/11128
                                    ...
                                When this option is omitted, or '-' is given, stdin is used.
    -t,--threads n: the number of threads to render
        + defaults to boost::thread::hardware_concurrency()
    -d,--dry-run
        + only echoes the tile paths to be expired, without actual removing
    -e,--echo-back
        + prints each successfully processed line to stdout, this is useful when pipelining another process such as re-rendering
    -v,--version
    -h,--help
*/

template <typename T>
static inline bool try_lexical_convert(const std::string& tk, T& r) {
    try {
        r = boost::lexical_cast<T>(tk);
        return true;
    } catch (boost::bad_lexical_cast& e) {
        return false;
    }
}
int main(int ac, char** av) {
    try {
        std::string base;
        std::string list_file;
        unsigned int nthreads;
        bool dry_run = false;
        /** Define and parse the program options
        */
        namespace po = boost::program_options;
        po::options_description desc(
            "expire-tiles -p base-path [-f expire-list-file] [-t num-threads]\n"
            "removes tiles listed in expire-list-file under base-path.\n\n"
            "Options"
        );
        desc.add_options()
            ("help,h", "Prints help messages")
            ("version,v", "Prints version info.")
            ("prefix,p", po::value<std::string>(&base)->value_name("base-path")->required(), "Specifies the base directory into which tile are rendered")
            ("file,f", po::value<std::string>(&list_file)->value_name("expire-list-file")->default_value("(stdin)"), "Specifies the list of tiles to expire")
            ("echo-back,e", "prints each successfully processed line to stdout, this is useful when pipelining another process such as re-rendering")
            ("threads,t",
                po::value<unsigned int>(&nthreads)->value_name("n")->default_value(boost::thread::hardware_concurrency()),
                "Specifies the number of threas to render\n"
                "  + defaults to boost::thread::hardware_concurrency()")
            ("dry-run,d",
                "Only estimates the number of tiles, does not actually render\n")
        ;
        if (ac <= 1) {
            // No options are given.
            // Just print the usage w.o. error messages.
            std::cerr << desc;
            return 0;
        }
        po::variables_map vm;

        try {
            po::store(po::command_line_parser(ac, av).options(desc).run(), vm); // throws on error

            // --help
            if ( vm.count("help")  ) {
                std::cerr << desc;
                return 0;
            }

            if ( vm.count("version") ) {
                std::cout << (
                    VERSION " (commit: " GIT_REVISION_SHORT ")"
                ) << std::endl;
                return 0;
            }

            // --dry-run
            if ( vm.count("dry-run") ) {
                dry_run = true;
            }

            // --echo-back
            if ( vm.count("echo-back") ) {
                echo_back = true;
            }

            po::notify(vm); // throws on error, so do after help in case
                            // there are any problems
            if ( !vm.count("expire-list-file") || list_file == "(stdin)") {
                list_file = "-";
            }

        } catch(po::required_option& e) {
            std::cerr << desc << std::endl;
            std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
            return -1;
        } catch(po::error& e) {
            std::cerr << desc << std::endl;
            std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
            return -1;
        }

        // Check if base-path is really there.
        const boost::filesystem::path base_path(base);
        if (!boost::filesystem::exists(base)) {
            std::cerr << "ERROR: The base path " << base << " does not exist." << std::endl << std::endl;
            return -1;
        }

        // Open the list file
        std::istream* in;
        if (list_file == "-") {
            in = &std::cin;
        } else {
            try {
                in = new std::ifstream(list_file);
            } catch (std::runtime_error& e) {
                std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
                return -1;
            }
        }
        std::cout
            << "Now expiration begins:" << std::endl
            << "  Base path : " << base_path.string() << std::endl
            << "  List file : " << (base == "-" ? "(stdin)" : list_file) << std::endl
        ;
        timer = new boost::timer::cpu_timer;

        // Awake renderer threads
        boost::thread_group consumer_threads;
        for (int i = 0; i != nthreads; ++i) {
            consumer_threads.create_thread(boost::bind( dry_run ? dry_worker : worker, base_path));
        }

        // Let it run!
        try {
            std::string line;
            uint64_t lineno = 0;
            uint32_t z, x, y;
            while (std::getline(*in, line)) {
                ++lineno;
                std::vector<std::string> tokens;
                boost::split(tokens, line, boost::is_from_range('/','/'));
                if (tokens.size() != 3 ||
                    !try_lexical_convert<uint32_t>(tokens[0], z) ||
                    !try_lexical_convert<uint32_t>(tokens[1], x) ||
                    !try_lexical_convert<uint32_t>(tokens[2], y) ) {
                    std::cerr << "WARN: skipped illfomed line: " << line << " (line at " << lineno << ")" << std::endl;
                    continue;
                }
                uint64_t tile_id = pack(z, x, y);
                while (!queue.push(tile_id)) {}
            }
        } catch (std::runtime_error& e) {
            std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
            return -1;
        }
        done = true;
        consumer_threads.join_all();

        if (in != &std::cin) {
            delete in;
        }

        std::cout
            << timer->format() << std::endl
            << removed << " tiles removed." << std::endl
            << skipped << " tiles did not exist or could not unlink(), thus skipped." << std::endl
            << "Completed!" << std::endl;
        ;
    } catch(std::exception& e) {
        std::cerr << "Unhandled Exception reached the top of main: "
              << e.what() << ", application will now exit" << std::endl;
        return -1;

    }
    return 0;
}
<|endoftext|>


<commit_before>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2014 Romuald Perrot, Pierre Moulon, Chris Sweeney.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_IMAGE_IMAGE_CONVOLUTION_HPP
#define OPENMVG_IMAGE_IMAGE_CONVOLUTION_HPP

#include <cassert>
#include <vector>

#include "openMVG/image/image_container.hpp"
#include "openMVG/image/image_convolution_base.hpp"
#include "openMVG/numeric/accumulator_trait.hpp"
#include "openMVG/numeric/eigen_alias_definition.hpp"

/**
 ** @file Standard 2D image convolution functions :
 ** - vertical
 ** - horizontal
 ** - 2D (using standard 2d kernel of with separable kernels)
 **/

namespace openMVG
{
namespace image
{

/**
 ** General image convolution by a kernel
 ** assume kernel has odd size in both dimensions and (border pixel are copied)
 ** @param img source image
 ** @param kernel convolution kernel
 ** @param out resulting image
 **/
template<typename Image>
void ImageConvolution( const Image & img , const Mat & kernel , Image & out )
{
  const int kernel_width  = kernel.cols();
  const int kernel_height = kernel.rows();

  assert( kernel_width % 2 != 0 && kernel_height % 2 != 0 );

  using pix_t = typename Image::Tpixel;
  using acc_pix_t = typename Accumulator< pix_t >::Type;

  out.resize( img.Width() , img.Height() );

  for (int row = 0; row < img.rows(); ++row )
  {
    for (int col = 0; col < img.cols(); ++col )
    {
      acc_pix_t sum = acc_pix_t( );

      for (int i = 0; i < kernel_height; ++i )
      {
        for (int j = 0; j < kernel_width; ++j )
        {
          int idy = row + i - kernel_height / 2;
          int idx = col + j - kernel_width / 2;

          // Get correct value
          idx = idx < 0 ? 0 : ( idx >= img.cols() ? img.cols() - 1 : idx );
          idy = idy < 0 ? 0 : ( idy >= img.rows() ? img.rows() - 1 : idy );

          sum += kernel( i , j ) * img( idy , idx );
        }
      }
      out( row , col ) = sum;
    }
  }
}

/**
 ** Horizontal (1d) convolution
 ** assume kernel has odd size
 ** @param img Input image
 ** @param kernel convolution kernel
 ** @param out Output image
 **/
template<typename ImageTypeIn, typename ImageTypeOut, typename Kernel>
void ImageHorizontalConvolution( const ImageTypeIn & img , const Kernel & kernel , ImageTypeOut & out )
{
  using pix_t = typename ImageTypeIn::Tpixel;

  const int rows ( img.rows() );
  const int cols ( img.cols() );

  out.resize( cols , rows );

  const int kernel_width = kernel.size();
  const int half_kernel_width = kernel_width / 2;

  std::vector<pix_t, Eigen::aligned_allocator<pix_t>> line( cols + kernel_width );

  for (int row = 0; row < rows; ++row )
  {
    // Copy line
    const pix_t start_pix = img.coeffRef( row , 0 );
    for (int k = 0; k < half_kernel_width; ++k ) // pad before
    {
      line[ k ] = start_pix;
    }
    std::memcpy( &line[0] + half_kernel_width, img.data() + row * cols, sizeof( pix_t ) * cols );
    const pix_t end_pix = img.coeffRef( row , cols - 1 );
    for (int k = 0; k < half_kernel_width; ++k ) // pad after
    {
      line[ k + half_kernel_width + cols ] = end_pix;
    }

    // Apply convolution
    conv_buffer_( &line[0] , kernel.data() , cols , kernel_width );

    std::memcpy( out.data() + row * cols, &line[0], sizeof( pix_t ) * cols );
  }
}

/**
 ** Vertical (1d) convolution
 ** assume kernel has odd size
 ** @param img Input image
 ** @param kernel convolution kernel
 ** @param out Output image
 **/
template<typename ImageTypeIn, typename ImageTypeOut, typename Kernel>
void ImageVerticalConvolution( const ImageTypeIn & img , const Kernel & kernel , ImageTypeOut & out )
{
  using pix_t = typename ImageTypeIn::Tpixel;

  const int kernel_width = kernel.size();
  const int half_kernel_width = kernel_width / 2;

  const int rows = img.rows();
  const int cols = img.cols();

  out.resize( cols , rows );

  std::vector<pix_t, Eigen::aligned_allocator<pix_t>> line( rows + kernel_width );

  for (int col = 0; col < cols; ++col )
  {
    // Copy column
    for (int k = 0; k < half_kernel_width; ++k )
    {
      line[ k ] = img.coeffRef( 0 , col );
    }
    for (int k = 0; k < rows; ++k )
    {
      line[ k + half_kernel_width ] = img.coeffRef( k , col );
    }
    for (int k = 0; k < half_kernel_width; ++k )
    {
      line[ k + half_kernel_width + rows ] = img.coeffRef( rows - 1 , col );
    }

    // Apply convolution
    conv_buffer_( &line[0] , kernel.data() , rows , kernel_width );

    for (int row = 0; row < rows; ++row )
    {
      out.coeffRef( row , col ) = line[row];
    }
  }
}

/**
 ** Separable 2D convolution
 ** (nxm kernel is replaced by two 1D convolution of (size n then size m) )
 ** @param img source image
 ** @param horiz_k horizontal kernel
 ** @param vert_k vertical kernel
 ** @param out output image
 **/
template<typename ImageType, typename Kernel>
void ImageSeparableConvolution( const ImageType & img ,
                                const Kernel & horiz_k ,
                                const Kernel & vert_k ,
                                ImageType & out )
{
  // Cast the Kernel to the appropriate type
  using pix_t = typename ImageType::Tpixel;
  using VecKernel = Eigen::Matrix<typename Accumulator<pix_t>::Type, Eigen::Dynamic, 1>;
  const VecKernel horiz_k_cast = horiz_k.template cast< typename Accumulator<pix_t>::Type >();
  const VecKernel vert_k_cast = vert_k.template cast< typename Accumulator<pix_t>::Type >();

  ImageType tmp;
  ImageHorizontalConvolution( img , horiz_k_cast , tmp );
  ImageVerticalConvolution( tmp , vert_k_cast , out );
}

using RowMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;

/// Specialization for Float based image (for arbitrary sized kernel)
inline void SeparableConvolution2d( const RowMatrixXf& image,
                                    const Eigen::Matrix<float, 1, Eigen::Dynamic>& kernel_x,
                                    const Eigen::Matrix<float, 1, Eigen::Dynamic>& kernel_y,
                                    RowMatrixXf* out )
{
  const int sigma_y = static_cast<int>( kernel_y.cols() );
  const int half_sigma_y = static_cast<int>( kernel_y.cols() ) / 2;

  // Convolving a vertical filter across rows is the same thing as transpose
  // multiply i.e. kernel_y^t * rows. This will give us the convoled value for
  // each row. However, care must be taken at the top and bottom borders.
  const Eigen::Matrix<float, 1, Eigen::Dynamic> reverse_kernel_y = kernel_y.reverse();
#if defined(OPENMVG_USE_OPENMP)
  #pragma omp parallel for schedule(dynamic)
#endif
  for ( int i = 0; i < half_sigma_y; i++ )
  {
    const int forward_size = i + half_sigma_y + 1;
    const int reverse_size = sigma_y - forward_size;
    out->row( i ) = kernel_y.tail( forward_size ) *
                    image.block( 0, 0, forward_size, image.cols() ) +
                    reverse_kernel_y.tail( reverse_size ) *
                    image.block( 1, 0, reverse_size, image.cols() );

    // Apply the same technique for the end rows.
    out->row( image.rows() - i - 1 ) =
      kernel_y.head( forward_size ) *
      image.block( image.rows() - forward_size, 0, forward_size, image.cols() )
      +
      reverse_kernel_y.head( reverse_size ) *
      image.block( image.rows() - reverse_size - 1, 0, reverse_size, image.cols() );
  }

  // Applying the rest of the y filter.
#if defined(OPENMVG_USE_OPENMP)
  #pragma omp parallel for schedule(dynamic)
#endif
  for ( int row = half_sigma_y; row < image.rows() - half_sigma_y; row++ )
  {
    out->row( row ) =  kernel_y * image.block( row - half_sigma_y, 0, sigma_y, out->cols() );
  }

  const int sigma_x = static_cast<int>( kernel_x.cols() );
  const int half_sigma_x = static_cast<int>( kernel_x.cols() / 2 );

  // Convolving with the horizontal filter is easy. Rather than using the kernel
  // as a sliding window, we use the row pixels as a sliding window around the
  // filter. We prepend and append the proper border values so that we are sure
  // to end up with the correct convolved values.
  Eigen::RowVectorXf temp_row( image.cols() + sigma_x - 1 );
#if defined(OPENMVG_USE_OPENMP)
  #pragma omp parallel for firstprivate(temp_row), schedule(dynamic)
#endif
  for ( int row = 0; row < out->rows(); row++ )
  {
    temp_row.head( half_sigma_x ) =
      out->row( row ).segment( 1, half_sigma_x ).reverse();
    temp_row.segment( half_sigma_x, image.cols() ) = out->row( row );
    temp_row.tail( half_sigma_x ) =
      out->row( row )
      .segment( image.cols() - 2 - half_sigma_x, half_sigma_x )
      .reverse();

    // Convolve the row. We perform the first step here explicitly so that we
    // avoid setting the row equal to zero.
    out->row( row ) = kernel_x( 0 ) * temp_row.head( image.cols() );
    for ( int i = 1; i < sigma_x; i++ )
    {
      out->row( row ) += kernel_x( i ) * temp_row.segment( i, image.cols() );
    }
  }
}

/**
* @brief Specialization for Image<float> in order to use SeparableConvolution2d
* @param img Input image
* @param horiz_k Kernel used for horizontal convolution
* @param vert_k Kernl used for vertical convolution
* @param[out] out Convolved image
*/
template<typename Kernel>
void ImageSeparableConvolution( const Image<float> & img ,
                                const Kernel & horiz_k ,
                                const Kernel & vert_k ,
                                Image<float> & out )
{
  // Cast the Kernel to the appropriate type
  using pix_t = Image<float>::Tpixel;
  using VecKernel = Eigen::Matrix<typename openMVG::Accumulator<pix_t>::Type, Eigen::Dynamic, 1>;
  const VecKernel horiz_k_cast = horiz_k.template cast< typename openMVG::Accumulator<pix_t>::Type >();
  const VecKernel vert_k_cast = vert_k.template cast< typename openMVG::Accumulator<pix_t>::Type >();

  out.resize( img.Width(), img.Height() );
  SeparableConvolution2d( img.GetMat(), horiz_k_cast, vert_k_cast, &( ( Image<float>::Base& )out ) );
}

} // namespace image
} // namespace openMVG

#endif // OPENMVG_IMAGE_IMAGE_CONVOLUTION_HPP
<commit_msg>[image] Fix a useless cast.<commit_after>// This file is part of OpenMVG, an Open Multiple View Geometry C++ library.

// Copyright (c) 2014 Romuald Perrot, Pierre Moulon, Chris Sweeney.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_IMAGE_IMAGE_CONVOLUTION_HPP
#define OPENMVG_IMAGE_IMAGE_CONVOLUTION_HPP

#include <cassert>
#include <vector>

#include "openMVG/image/image_container.hpp"
#include "openMVG/image/image_convolution_base.hpp"
#include "openMVG/numeric/accumulator_trait.hpp"
#include "openMVG/numeric/eigen_alias_definition.hpp"

/**
 ** @file Standard 2D image convolution functions :
 ** - vertical
 ** - horizontal
 ** - 2D (using standard 2d kernel of with separable kernels)
 **/

namespace openMVG
{
namespace image
{

/**
 ** General image convolution by a kernel
 ** assume kernel has odd size in both dimensions and (border pixel are copied)
 ** @param img source image
 ** @param kernel convolution kernel
 ** @param out resulting image
 **/
template<typename Image>
void ImageConvolution( const Image & img , const Mat & kernel , Image & out )
{
  const int kernel_width  = kernel.cols();
  const int kernel_height = kernel.rows();

  assert( kernel_width % 2 != 0 && kernel_height % 2 != 0 );

  using pix_t = typename Image::Tpixel;
  using acc_pix_t = typename Accumulator< pix_t >::Type;

  out.resize( img.Width() , img.Height() );

  for (int row = 0; row < img.rows(); ++row )
  {
    for (int col = 0; col < img.cols(); ++col )
    {
      acc_pix_t sum = acc_pix_t( );

      for (int i = 0; i < kernel_height; ++i )
      {
        for (int j = 0; j < kernel_width; ++j )
        {
          int idy = row + i - kernel_height / 2;
          int idx = col + j - kernel_width / 2;

          // Get correct value
          idx = idx < 0 ? 0 : ( idx >= img.cols() ? img.cols() - 1 : idx );
          idy = idy < 0 ? 0 : ( idy >= img.rows() ? img.rows() - 1 : idy );

          sum += kernel( i , j ) * img( idy , idx );
        }
      }
      out( row , col ) = sum;
    }
  }
}

/**
 ** Horizontal (1d) convolution
 ** assume kernel has odd size
 ** @param img Input image
 ** @param kernel convolution kernel
 ** @param out Output image
 **/
template<typename ImageTypeIn, typename ImageTypeOut, typename Kernel>
void ImageHorizontalConvolution( const ImageTypeIn & img , const Kernel & kernel , ImageTypeOut & out )
{
  using pix_t = typename ImageTypeIn::Tpixel;

  const int rows ( img.rows() );
  const int cols ( img.cols() );

  out.resize( cols , rows );

  const int kernel_width = kernel.size();
  const int half_kernel_width = kernel_width / 2;

  std::vector<pix_t, Eigen::aligned_allocator<pix_t>> line( cols + kernel_width );

  for (int row = 0; row < rows; ++row )
  {
    // Copy line
    const pix_t start_pix = img.coeffRef( row , 0 );
    for (int k = 0; k < half_kernel_width; ++k ) // pad before
    {
      line[ k ] = start_pix;
    }
    std::memcpy( &line[0] + half_kernel_width, img.data() + row * cols, sizeof( pix_t ) * cols );
    const pix_t end_pix = img.coeffRef( row , cols - 1 );
    for (int k = 0; k < half_kernel_width; ++k ) // pad after
    {
      line[ k + half_kernel_width + cols ] = end_pix;
    }

    // Apply convolution
    conv_buffer_( &line[0] , kernel.data() , cols , kernel_width );

    std::memcpy( out.data() + row * cols, &line[0], sizeof( pix_t ) * cols );
  }
}

/**
 ** Vertical (1d) convolution
 ** assume kernel has odd size
 ** @param img Input image
 ** @param kernel convolution kernel
 ** @param out Output image
 **/
template<typename ImageTypeIn, typename ImageTypeOut, typename Kernel>
void ImageVerticalConvolution( const ImageTypeIn & img , const Kernel & kernel , ImageTypeOut & out )
{
  using pix_t = typename ImageTypeIn::Tpixel;

  const int kernel_width = kernel.size();
  const int half_kernel_width = kernel_width / 2;

  const int rows = img.rows();
  const int cols = img.cols();

  out.resize( cols , rows );

  std::vector<pix_t, Eigen::aligned_allocator<pix_t>> line( rows + kernel_width );

  for (int col = 0; col < cols; ++col )
  {
    // Copy column
    for (int k = 0; k < half_kernel_width; ++k )
    {
      line[ k ] = img.coeffRef( 0 , col );
    }
    for (int k = 0; k < rows; ++k )
    {
      line[ k + half_kernel_width ] = img.coeffRef( k , col );
    }
    for (int k = 0; k < half_kernel_width; ++k )
    {
      line[ k + half_kernel_width + rows ] = img.coeffRef( rows - 1 , col );
    }

    // Apply convolution
    conv_buffer_( &line[0] , kernel.data() , rows , kernel_width );

    for (int row = 0; row < rows; ++row )
    {
      out.coeffRef( row , col ) = line[row];
    }
  }
}

/**
 ** Separable 2D convolution
 ** (nxm kernel is replaced by two 1D convolution of (size n then size m) )
 ** @param img source image
 ** @param horiz_k horizontal kernel
 ** @param vert_k vertical kernel
 ** @param out output image
 **/
template<typename ImageType, typename Kernel>
void ImageSeparableConvolution( const ImageType & img ,
                                const Kernel & horiz_k ,
                                const Kernel & vert_k ,
                                ImageType & out )
{
  // Cast the Kernel to the appropriate type
  using pix_t = typename ImageType::Tpixel;
  using VecKernel = Eigen::Matrix<typename Accumulator<pix_t>::Type, Eigen::Dynamic, 1>;
  const VecKernel horiz_k_cast = horiz_k.template cast< typename Accumulator<pix_t>::Type >();
  const VecKernel vert_k_cast = vert_k.template cast< typename Accumulator<pix_t>::Type >();

  ImageType tmp;
  ImageHorizontalConvolution( img , horiz_k_cast , tmp );
  ImageVerticalConvolution( tmp , vert_k_cast , out );
}

using RowMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;

/// Specialization for Float based image (for arbitrary sized kernel)
inline void SeparableConvolution2d( const RowMatrixXf& image,
                                    const Eigen::Matrix<float, 1, Eigen::Dynamic>& kernel_x,
                                    const Eigen::Matrix<float, 1, Eigen::Dynamic>& kernel_y,
                                    RowMatrixXf* out )
{
  const int sigma_y = static_cast<int>( kernel_y.cols() );
  const int half_sigma_y = static_cast<int>( kernel_y.cols() ) / 2;

  // Convolving a vertical filter across rows is the same thing as transpose
  // multiply i.e. kernel_y^t * rows. This will give us the convoled value for
  // each row. However, care must be taken at the top and bottom borders.
  const Eigen::Matrix<float, 1, Eigen::Dynamic> reverse_kernel_y = kernel_y.reverse();
#if defined(OPENMVG_USE_OPENMP)
  #pragma omp parallel for schedule(dynamic)
#endif
  for ( int i = 0; i < half_sigma_y; i++ )
  {
    const int forward_size = i + half_sigma_y + 1;
    const int reverse_size = sigma_y - forward_size;
    out->row( i ) = kernel_y.tail( forward_size ) *
                    image.block( 0, 0, forward_size, image.cols() ) +
                    reverse_kernel_y.tail( reverse_size ) *
                    image.block( 1, 0, reverse_size, image.cols() );

    // Apply the same technique for the end rows.
    out->row( image.rows() - i - 1 ) =
      kernel_y.head( forward_size ) *
      image.block( image.rows() - forward_size, 0, forward_size, image.cols() )
      +
      reverse_kernel_y.head( reverse_size ) *
      image.block( image.rows() - reverse_size - 1, 0, reverse_size, image.cols() );
  }

  // Applying the rest of the y filter.
#if defined(OPENMVG_USE_OPENMP)
  #pragma omp parallel for schedule(dynamic)
#endif
  for ( int row = half_sigma_y; row < image.rows() - half_sigma_y; row++ )
  {
    out->row( row ) =  kernel_y * image.block( row - half_sigma_y, 0, sigma_y, out->cols() );
  }

  const int sigma_x = static_cast<int>( kernel_x.cols() );
  const int half_sigma_x = static_cast<int>( kernel_x.cols() / 2 );

  // Convolving with the horizontal filter is easy. Rather than using the kernel
  // as a sliding window, we use the row pixels as a sliding window around the
  // filter. We prepend and append the proper border values so that we are sure
  // to end up with the correct convolved values.
  Eigen::RowVectorXf temp_row( image.cols() + sigma_x - 1 );
#if defined(OPENMVG_USE_OPENMP)
  #pragma omp parallel for firstprivate(temp_row), schedule(dynamic)
#endif
  for ( int row = 0; row < out->rows(); row++ )
  {
    temp_row.head( half_sigma_x ) =
      out->row( row ).segment( 1, half_sigma_x ).reverse();
    temp_row.segment( half_sigma_x, image.cols() ) = out->row( row );
    temp_row.tail( half_sigma_x ) =
      out->row( row )
      .segment( image.cols() - 2 - half_sigma_x, half_sigma_x )
      .reverse();

    // Convolve the row. We perform the first step here explicitly so that we
    // avoid setting the row equal to zero.
    out->row( row ) = kernel_x( 0 ) * temp_row.head( image.cols() );
    for ( int i = 1; i < sigma_x; i++ )
    {
      out->row( row ) += kernel_x( i ) * temp_row.segment( i, image.cols() );
    }
  }
}

/**
* @brief Specialization for Image<float> in order to use SeparableConvolution2d
* @param img Input image
* @param horiz_k Kernel used for horizontal convolution
* @param vert_k Kernl used for vertical convolution
* @param[out] out Convolved image
*/
template<typename Kernel>
void ImageSeparableConvolution( const Image<float> & img ,
                                const Kernel & horiz_k ,
                                const Kernel & vert_k ,
                                Image<float> & out )
{
  // Cast the Kernel to the appropriate type
  using pix_t = Image<float>::Tpixel;
  using VecKernel = Eigen::Matrix<typename openMVG::Accumulator<pix_t>::Type, Eigen::Dynamic, 1>;
  const VecKernel horiz_k_cast = horiz_k.template cast< typename openMVG::Accumulator<pix_t>::Type >();
  const VecKernel vert_k_cast = vert_k.template cast< typename openMVG::Accumulator<pix_t>::Type >();

  out.resize( img.Width(), img.Height() );
  SeparableConvolution2d( img.GetMat(), horiz_k_cast, vert_k_cast, &out );
}

} // namespace image
} // namespace openMVG

#endif // OPENMVG_IMAGE_IMAGE_CONVOLUTION_HPP
<|endoftext|>


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

#include "core/global.h"
#include "util/Role.h"
#include "core/RoleFactory.h"
#include "util/Datagram.h"

static ConfigVariable<std::string> bind_addr("bind", "0.0.0.0:7198");

class ClientAgent : public Role
{
public:
	ClientAgent(RoleConfig roleconfig) : Role(roleconfig)
	{
		std::stringstream ss;
		ss << "Client Agent (" << bind_addr.get_rval(roleconfig) << ")";
		m_log = new LogCategory("clientagent", ss.str());
	}

	~ClientAgent()
	{
		delete m_log;
	}

	void handle_datagram(Datagram &in_dg, DatagramIterator &dgi)
	{

	}

private:
	LogCategory *m_log;
};

static RoleFactoryItem<ClientAgent> ca_fact("clientagent");
<commit_msg>ClientAgent: Style conformance<commit_after>#include <boost/asio.hpp>
#include <boost/bind.hpp>

#include "core/global.h"
#include "util/Role.h"
#include "core/RoleFactory.h"
#include "util/Datagram.h"

static ConfigVariable<std::string> bind_addr("bind", "0.0.0.0:7198");

class ClientAgent : public Role
{
	public:
		ClientAgent(RoleConfig roleconfig) : Role(roleconfig)
		{
			std::stringstream ss;
			ss << "Client Agent (" << bind_addr.get_rval(roleconfig) << ")";
			m_log = new LogCategory("clientagent", ss.str());
		}

		~ClientAgent()
		{
			delete m_log;
		}

		void handle_datagram(Datagram &in_dg, DatagramIterator &dgi)
		{

		}

	private:
		LogCategory *m_log;
};

static RoleFactoryItem<ClientAgent> ca_fact("clientagent");
<|endoftext|>


<commit_before>#include <QtGui>

#include <list>

#include "Backends.h"
#include "DTIDESplash.h"
#include "DTIDE.h"

extern "C"
{
#include <osutil.h>
#include <bstring.h>
#include <debug.h>
#include <iio.h>
#include <GL/glfw3.h>
}

int main(int argc, char** argv)
{
    // Some set up required for toolchain to work.
    debug_setlevel(LEVEL_VERBOSE);
    osutil_setarg0(bautofree(bfromcstr(argv[0])));
    isetmode(IMODE_BIG);

    // Show version information.
    version_print(bautofree(bfromcstr("IDE")));

    // Start glfw.
    glfwInit();

    // Now start the IDE.
    QApplication app(argc, argv);

    std::list<Toolchain*> toolchains;
    toolchains.insert(toolchains.end(), new DCPUToolchain());

    /*DTIDESplash* splash = new DTIDESplash(toolchains);
    if(!splash->exec())
        return 0;

    DTIDE mainWindow(splash->toolchain, splash->fileName);*/

    DTIDE mainWindow(new DCPUToolchain(), "test.dasm16");
    mainWindow.show();

    int returncode = app.exec();
    glfwTerminate();
    return returncode;
}

<commit_msg>Added missing include for IDE.<commit_after>#include <QtGui>

#include <list>

#include "Backends.h"
#include "DTIDESplash.h"
#include "DTIDE.h"

extern "C"
{
#include <osutil.h>
#include <bstring.h>
#include <debug.h>
#include <iio.h>
#include <version.h>
#include <GL/glfw3.h>
}

int main(int argc, char** argv)
{
    // Some set up required for toolchain to work.
    debug_setlevel(LEVEL_VERBOSE);
    osutil_setarg0(bautofree(bfromcstr(argv[0])));
    isetmode(IMODE_BIG);

    // Show version information.
    version_print(bautofree(bfromcstr("IDE")));

    // Start glfw.
    glfwInit();

    // Now start the IDE.
    QApplication app(argc, argv);

    std::list<Toolchain*> toolchains;
    toolchains.insert(toolchains.end(), new DCPUToolchain());

    /*DTIDESplash* splash = new DTIDESplash(toolchains);
    if(!splash->exec())
        return 0;

    DTIDE mainWindow(splash->toolchain, splash->fileName);*/

    DTIDE mainWindow(new DCPUToolchain(), "test.dasm16");
    mainWindow.show();

    int returncode = app.exec();
    glfwTerminate();
    return returncode;
}

<|endoftext|>