<commit_before>//===-- asan_dll_thunk.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.
//
// This file defines a family of thunks that should be statically linked into
// the DLLs that have ASan instrumentation in order to delegate the calls to the
// shared runtime that lives in the main binary.
// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
// details.
//===----------------------------------------------------------------------===//

// Only compile this code when buidling asan_dll_thunk.lib
// Using #ifdef rather than relying on Makefiles etc.
// simplifies the build procedure.
#ifdef ASAN_DLL_THUNK
#include "sanitizer_common/sanitizer_interception.h"

// ----------------- Helper functions and macros --------------------- {{{1
extern "C" {
void *__stdcall GetModuleHandleA(const char *module_name);
void *__stdcall GetProcAddress(void *module, const char *proc_name);
void abort();
}

static void *getRealProcAddressOrDie(const char *name) {
  void *ret = GetProcAddress(GetModuleHandleA(0), name);
  if (!ret)
    abort();
  return ret;
}

#define WRAP_V_V(name)                                                         \
  extern "C" void name() {                                                     \
    typedef void (*fntype)();                                                  \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn();                                                                      \
  }

#define WRAP_V_W(name)                                                         \
  extern "C" void name(void *arg) {                                            \
    typedef void (*fntype)(void *arg);                                         \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn(arg);                                                                   \
  }

#define WRAP_V_WW(name)                                                        \
  extern "C" void name(void *arg1, void *arg2) {                               \
    typedef void (*fntype)(void *, void *);                                    \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn(arg1, arg2);                                                            \
  }

#define WRAP_V_WWW(name)                                                       \
  extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
    typedef void *(*fntype)(void *, void *, void *);                           \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn(arg1, arg2, arg3);                                                      \
  }

#define WRAP_W_V(name)                                                         \
  extern "C" void *name() {                                                    \
    typedef void *(*fntype)();                                                 \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn();                                                               \
  }

#define WRAP_W_W(name)                                                         \
  extern "C" void *name(void *arg) {                                           \
    typedef void *(*fntype)(void *arg);                                        \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg);                                                            \
  }

#define WRAP_W_WW(name)                                                        \
  extern "C" void *name(void *arg1, void *arg2) {                              \
    typedef void *(*fntype)(void *, void *);                                   \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2);                                                     \
  }

#define WRAP_W_WWW(name)                                                       \
  extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
    typedef void *(*fntype)(void *, void *, void *);                           \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3);                                               \
  }

#define WRAP_W_WWWW(name)                                                      \
  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
    typedef void *(*fntype)(void *, void *, void *, void *);                   \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3, arg4);                                         \
  }

#define WRAP_W_WWWWW(name)                                                     \
  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
                        void *arg5) {                                          \
    typedef void *(*fntype)(void *, void *, void *, void *, void *);           \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3, arg4, arg5);                                   \
  }

#define WRAP_W_WWWWWW(name)                                                    \
  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
                        void *arg5, void *arg6) {                              \
    typedef void *(*fntype)(void *, void *, void *, void *, void *, void *);   \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
  }
// }}}

// --------- Interface interception helper functions and macros ----------- {{{1
// We need to intercept the ASan interface exported by the DLL thunk and forward
// all the functions to the runtime in the main module.
// However, we don't want to keep two lists of interface functions.
// To avoid that, the list of interface functions should be defined using the
// INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once
// by calling INTERCEPT_ASAN_INTERFACE().

// Use macro+template magic to automatically generate the list of interface
// functions.  Each interface function at line LINE defines a template class
// with a static InterfaceInteceptor<LINE>::Execute() method intercepting the
// function.  The default implementation of InterfaceInteceptor<LINE> is to call
// the Execute() method corresponding to the previous line.
template<int LINE>
struct InterfaceInteceptor {
  static void Execute() { InterfaceInteceptor<LINE-1>::Execute(); }
};

// There shouldn't be any interface function with negative line number.
template<>
struct InterfaceInteceptor<0> {
  static void Execute() {}
};

#define INTERFACE_FUNCTION(name)                                               \
  extern "C" void name() { __debugbreak(); }                                   \
  template<> struct InterfaceInteceptor<__LINE__> {                            \
    static void Execute() {                                                    \
      void *wrapper = getRealProcAddressOrDie(#name);                          \
      if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0))     \
        abort();                                                               \
      InterfaceInteceptor<__LINE__-1>::Execute();                              \
    }                                                                          \
  };

// INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION.
#define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute

static void InterceptASanInterface();
// }}}

// ----------------- ASan own interface functions --------------------
// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
// want to call it in the __asan_init interceptor.
WRAP_W_V(__asan_should_detect_stack_use_after_return)

extern "C" {
  int __asan_option_detect_stack_use_after_return;

  // Manually wrap __asan_init as we need to initialize
  // __asan_option_detect_stack_use_after_return afterwards.
  void __asan_init_v3() {
    typedef void (*fntype)();
    static fntype fn = 0;
    if (fn) return;

    fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
    fn();
    __asan_option_detect_stack_use_after_return =
        (__asan_should_detect_stack_use_after_return() != 0);

    InterceptASanInterface();
  }
}

INTERFACE_FUNCTION(__asan_handle_no_return)

INTERFACE_FUNCTION(__asan_report_store1)
INTERFACE_FUNCTION(__asan_report_store2)
INTERFACE_FUNCTION(__asan_report_store4)
INTERFACE_FUNCTION(__asan_report_store8)
INTERFACE_FUNCTION(__asan_report_store16)
INTERFACE_FUNCTION(__asan_report_store_n)

INTERFACE_FUNCTION(__asan_report_load1)
INTERFACE_FUNCTION(__asan_report_load2)
INTERFACE_FUNCTION(__asan_report_load4)
INTERFACE_FUNCTION(__asan_report_load8)
INTERFACE_FUNCTION(__asan_report_load16)
INTERFACE_FUNCTION(__asan_report_load_n)

INTERFACE_FUNCTION(__asan_memcpy);
INTERFACE_FUNCTION(__asan_memset);
INTERFACE_FUNCTION(__asan_memmove);

INTERFACE_FUNCTION(__asan_register_globals)
INTERFACE_FUNCTION(__asan_unregister_globals)

INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_after_dynamic_init)

INTERFACE_FUNCTION(__asan_poison_stack_memory)
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)

INTERFACE_FUNCTION(__asan_poison_memory_region)
INTERFACE_FUNCTION(__asan_unpoison_memory_region)

INTERFACE_FUNCTION(__asan_get_current_fake_stack)
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)

INTERFACE_FUNCTION(__asan_stack_malloc_0)
INTERFACE_FUNCTION(__asan_stack_malloc_1)
INTERFACE_FUNCTION(__asan_stack_malloc_2)
INTERFACE_FUNCTION(__asan_stack_malloc_3)
INTERFACE_FUNCTION(__asan_stack_malloc_4)
INTERFACE_FUNCTION(__asan_stack_malloc_5)
INTERFACE_FUNCTION(__asan_stack_malloc_6)
INTERFACE_FUNCTION(__asan_stack_malloc_7)
INTERFACE_FUNCTION(__asan_stack_malloc_8)
INTERFACE_FUNCTION(__asan_stack_malloc_9)
INTERFACE_FUNCTION(__asan_stack_malloc_10)

INTERFACE_FUNCTION(__asan_stack_free_0)
INTERFACE_FUNCTION(__asan_stack_free_1)
INTERFACE_FUNCTION(__asan_stack_free_2)
INTERFACE_FUNCTION(__asan_stack_free_4)
INTERFACE_FUNCTION(__asan_stack_free_5)
INTERFACE_FUNCTION(__asan_stack_free_6)
INTERFACE_FUNCTION(__asan_stack_free_7)
INTERFACE_FUNCTION(__asan_stack_free_8)
INTERFACE_FUNCTION(__asan_stack_free_9)
INTERFACE_FUNCTION(__asan_stack_free_10)

// TODO(timurrrr): Add more interface functions on the as-needed basis.

// ----------------- Memory allocation functions ---------------------
WRAP_V_W(free)
WRAP_V_WW(_free_dbg)

WRAP_W_W(malloc)
WRAP_W_WWWW(_malloc_dbg)

WRAP_W_WW(calloc)
WRAP_W_WWWWW(_calloc_dbg)
WRAP_W_WWW(_calloc_impl)

WRAP_W_WW(realloc)
WRAP_W_WWW(_realloc_dbg)
WRAP_W_WWW(_recalloc)

WRAP_W_W(_msize)
WRAP_W_W(_expand)
WRAP_W_W(_expand_dbg)

// TODO(timurrrr): Might want to add support for _aligned_* allocation
// functions to detect a bit more bugs.  Those functions seem to wrap malloc().

// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).

void InterceptASanInterface() {
  INTERCEPT_ASAN_INTERFACE();
}

#endif // ASAN_DLL_THUNK
<commit_msg>[ASan/Win] Add a comment about DCL-using-static vs threads<commit_after>//===-- asan_dll_thunk.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.
//
// This file defines a family of thunks that should be statically linked into
// the DLLs that have ASan instrumentation in order to delegate the calls to the
// shared runtime that lives in the main binary.
// See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
// details.
//===----------------------------------------------------------------------===//

// Only compile this code when buidling asan_dll_thunk.lib
// Using #ifdef rather than relying on Makefiles etc.
// simplifies the build procedure.
#ifdef ASAN_DLL_THUNK
#include "sanitizer_common/sanitizer_interception.h"

// ----------------- Helper functions and macros --------------------- {{{1
extern "C" {
void *__stdcall GetModuleHandleA(const char *module_name);
void *__stdcall GetProcAddress(void *module, const char *proc_name);
void abort();
}

static void *getRealProcAddressOrDie(const char *name) {
  void *ret = GetProcAddress(GetModuleHandleA(0), name);
  if (!ret)
    abort();
  return ret;
}

#define WRAP_V_V(name)                                                         \
  extern "C" void name() {                                                     \
    typedef void (*fntype)();                                                  \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn();                                                                      \
  }

#define WRAP_V_W(name)                                                         \
  extern "C" void name(void *arg) {                                            \
    typedef void (*fntype)(void *arg);                                         \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn(arg);                                                                   \
  }

#define WRAP_V_WW(name)                                                        \
  extern "C" void name(void *arg1, void *arg2) {                               \
    typedef void (*fntype)(void *, void *);                                    \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn(arg1, arg2);                                                            \
  }

#define WRAP_V_WWW(name)                                                       \
  extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
    typedef void *(*fntype)(void *, void *, void *);                           \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    fn(arg1, arg2, arg3);                                                      \
  }

#define WRAP_W_V(name)                                                         \
  extern "C" void *name() {                                                    \
    typedef void *(*fntype)();                                                 \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn();                                                               \
  }

#define WRAP_W_W(name)                                                         \
  extern "C" void *name(void *arg) {                                           \
    typedef void *(*fntype)(void *arg);                                        \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg);                                                            \
  }

#define WRAP_W_WW(name)                                                        \
  extern "C" void *name(void *arg1, void *arg2) {                              \
    typedef void *(*fntype)(void *, void *);                                   \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2);                                                     \
  }

#define WRAP_W_WWW(name)                                                       \
  extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
    typedef void *(*fntype)(void *, void *, void *);                           \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3);                                               \
  }

#define WRAP_W_WWWW(name)                                                      \
  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
    typedef void *(*fntype)(void *, void *, void *, void *);                   \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3, arg4);                                         \
  }

#define WRAP_W_WWWWW(name)                                                     \
  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
                        void *arg5) {                                          \
    typedef void *(*fntype)(void *, void *, void *, void *, void *);           \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3, arg4, arg5);                                   \
  }

#define WRAP_W_WWWWWW(name)                                                    \
  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
                        void *arg5, void *arg6) {                              \
    typedef void *(*fntype)(void *, void *, void *, void *, void *, void *);   \
    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
    return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
  }
// }}}

// --------- Interface interception helper functions and macros ----------- {{{1
// We need to intercept the ASan interface exported by the DLL thunk and forward
// all the functions to the runtime in the main module.
// However, we don't want to keep two lists of interface functions.
// To avoid that, the list of interface functions should be defined using the
// INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once
// by calling INTERCEPT_ASAN_INTERFACE().

// Use macro+template magic to automatically generate the list of interface
// functions.  Each interface function at line LINE defines a template class
// with a static InterfaceInteceptor<LINE>::Execute() method intercepting the
// function.  The default implementation of InterfaceInteceptor<LINE> is to call
// the Execute() method corresponding to the previous line.
template<int LINE>
struct InterfaceInteceptor {
  static void Execute() { InterfaceInteceptor<LINE-1>::Execute(); }
};

// There shouldn't be any interface function with negative line number.
template<>
struct InterfaceInteceptor<0> {
  static void Execute() {}
};

#define INTERFACE_FUNCTION(name)                                               \
  extern "C" void name() { __debugbreak(); }                                   \
  template<> struct InterfaceInteceptor<__LINE__> {                            \
    static void Execute() {                                                    \
      void *wrapper = getRealProcAddressOrDie(#name);                          \
      if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0))     \
        abort();                                                               \
      InterfaceInteceptor<__LINE__-1>::Execute();                              \
    }                                                                          \
  };

// INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION.
#define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute

static void InterceptASanInterface();
// }}}

// ----------------- ASan own interface functions --------------------
// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
// want to call it in the __asan_init interceptor.
WRAP_W_V(__asan_should_detect_stack_use_after_return)

extern "C" {
  int __asan_option_detect_stack_use_after_return;

  // Manually wrap __asan_init as we need to initialize
  // __asan_option_detect_stack_use_after_return afterwards.
  void __asan_init_v3() {
    typedef void (*fntype)();
    static fntype fn = 0;
    // __asan_init_v3 is expected to be called by only one thread.
    if (fn) return;

    fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
    fn();
    __asan_option_detect_stack_use_after_return =
        (__asan_should_detect_stack_use_after_return() != 0);

    InterceptASanInterface();
  }
}

INTERFACE_FUNCTION(__asan_handle_no_return)

INTERFACE_FUNCTION(__asan_report_store1)
INTERFACE_FUNCTION(__asan_report_store2)
INTERFACE_FUNCTION(__asan_report_store4)
INTERFACE_FUNCTION(__asan_report_store8)
INTERFACE_FUNCTION(__asan_report_store16)
INTERFACE_FUNCTION(__asan_report_store_n)

INTERFACE_FUNCTION(__asan_report_load1)
INTERFACE_FUNCTION(__asan_report_load2)
INTERFACE_FUNCTION(__asan_report_load4)
INTERFACE_FUNCTION(__asan_report_load8)
INTERFACE_FUNCTION(__asan_report_load16)
INTERFACE_FUNCTION(__asan_report_load_n)

INTERFACE_FUNCTION(__asan_memcpy);
INTERFACE_FUNCTION(__asan_memset);
INTERFACE_FUNCTION(__asan_memmove);

INTERFACE_FUNCTION(__asan_register_globals)
INTERFACE_FUNCTION(__asan_unregister_globals)

INTERFACE_FUNCTION(__asan_before_dynamic_init)
INTERFACE_FUNCTION(__asan_after_dynamic_init)

INTERFACE_FUNCTION(__asan_poison_stack_memory)
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)

INTERFACE_FUNCTION(__asan_poison_memory_region)
INTERFACE_FUNCTION(__asan_unpoison_memory_region)

INTERFACE_FUNCTION(__asan_get_current_fake_stack)
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)

INTERFACE_FUNCTION(__asan_stack_malloc_0)
INTERFACE_FUNCTION(__asan_stack_malloc_1)
INTERFACE_FUNCTION(__asan_stack_malloc_2)
INTERFACE_FUNCTION(__asan_stack_malloc_3)
INTERFACE_FUNCTION(__asan_stack_malloc_4)
INTERFACE_FUNCTION(__asan_stack_malloc_5)
INTERFACE_FUNCTION(__asan_stack_malloc_6)
INTERFACE_FUNCTION(__asan_stack_malloc_7)
INTERFACE_FUNCTION(__asan_stack_malloc_8)
INTERFACE_FUNCTION(__asan_stack_malloc_9)
INTERFACE_FUNCTION(__asan_stack_malloc_10)

INTERFACE_FUNCTION(__asan_stack_free_0)
INTERFACE_FUNCTION(__asan_stack_free_1)
INTERFACE_FUNCTION(__asan_stack_free_2)
INTERFACE_FUNCTION(__asan_stack_free_4)
INTERFACE_FUNCTION(__asan_stack_free_5)
INTERFACE_FUNCTION(__asan_stack_free_6)
INTERFACE_FUNCTION(__asan_stack_free_7)
INTERFACE_FUNCTION(__asan_stack_free_8)
INTERFACE_FUNCTION(__asan_stack_free_9)
INTERFACE_FUNCTION(__asan_stack_free_10)

// TODO(timurrrr): Add more interface functions on the as-needed basis.

// ----------------- Memory allocation functions ---------------------
WRAP_V_W(free)
WRAP_V_WW(_free_dbg)

WRAP_W_W(malloc)
WRAP_W_WWWW(_malloc_dbg)

WRAP_W_WW(calloc)
WRAP_W_WWWWW(_calloc_dbg)
WRAP_W_WWW(_calloc_impl)

WRAP_W_WW(realloc)
WRAP_W_WWW(_realloc_dbg)
WRAP_W_WWW(_recalloc)

WRAP_W_W(_msize)
WRAP_W_W(_expand)
WRAP_W_W(_expand_dbg)

// TODO(timurrrr): Might want to add support for _aligned_* allocation
// functions to detect a bit more bugs.  Those functions seem to wrap malloc().

// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).

void InterceptASanInterface() {
  INTERCEPT_ASAN_INTERFACE();
}

#endif // ASAN_DLL_THUNK
<|endoftext|>


<commit_before>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "buffer.h"

#include <cassert>      /* for assert() */
#include <cerrno>       /* for errno */
#include <stdexcept>    /* for std::bad_alloc */
#include <sys/mman.h>   /* for mmap(), munmap(), mremap() */
#include <system_error> /* for std::system_error */
#include <unistd.h>     /* for sysconf() */

using namespace machinery::util;

static const int mmap_prot  = PROT_READ | PROT_WRITE | PROT_EXEC;
static const int mmap_flags = MAP_PRIVATE | MAP_ANON;
static const std::size_t mmap_size = sysconf(_SC_PAGESIZE);

executable_buffer::executable_buffer()
  : _data(nullptr),
    _size(mmap_size),
    _capacity(mmap_size) {

  void* const addr = ::mmap(nullptr, _capacity, mmap_prot, mmap_flags, -1, 0);
  if (addr == MAP_FAILED) {
    switch (errno) {
      case ENOMEM: /* Cannot allocate memory in kernel */
        throw std::bad_alloc();
      default:
        assert(errno != EBADF);
        throw std::system_error(errno, std::system_category());
    }
  }

  _data = reinterpret_cast<std::uint8_t*>(addr);
}

executable_buffer::~executable_buffer() noexcept {
  if (_data) {
    if (::munmap(reinterpret_cast<void*>(_data), _size) == -1) {
      /* Ignore any errors from munmap(). */
    }
    _data = nullptr;
    _size = _capacity = 0;
  }
}

void
executable_buffer::grow() {
#ifdef __linux__
  // TODO: use mremap()
#else
  // TODO: use mmap()
#endif
  throw std::system_error(ENOSYS, std::system_category());
}
<commit_msg>Fixed a bug in executable_buffer construction.<commit_after>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "buffer.h"

#include <cassert>      /* for assert() */
#include <cerrno>       /* for errno */
#include <stdexcept>    /* for std::bad_alloc */
#include <sys/mman.h>   /* for mmap(), munmap(), mremap() */
#include <system_error> /* for std::system_error */
#include <unistd.h>     /* for sysconf() */

using namespace machinery::util;

static const int mmap_prot  = PROT_READ | PROT_WRITE | PROT_EXEC;
static const int mmap_flags = MAP_PRIVATE | MAP_ANON;
static const std::size_t mmap_size = sysconf(_SC_PAGESIZE);

executable_buffer::executable_buffer()
  : _data(nullptr),
    _size(0),
    _capacity(mmap_size) {

  void* const addr = ::mmap(nullptr, _capacity, mmap_prot, mmap_flags, -1, 0);
  if (addr == MAP_FAILED) {
    switch (errno) {
      case ENOMEM: /* Cannot allocate memory in kernel */
        throw std::bad_alloc();
      default:
        assert(errno != EBADF);
        throw std::system_error(errno, std::system_category());
    }
  }

  _data = reinterpret_cast<std::uint8_t*>(addr);
}

executable_buffer::~executable_buffer() noexcept {
  if (_data) {
    if (::munmap(reinterpret_cast<void*>(_data), _size) == -1) {
      /* Ignore any errors from munmap(). */
    }
    _data = nullptr;
    _size = _capacity = 0;
  }
}

void
executable_buffer::grow() {
#ifdef __linux__
  // TODO: use mremap()
#else
  // TODO: use mmap()
#endif
  throw std::system_error(ENOSYS, std::system_category());
}
<|endoftext|>


<commit_before>#include "xmlbinder.h"
#include "raiden.h"
#include "paramset.h"
#include <string>
void XMLBinder::Init()
{
}

void XMLBinder::Release()
{
}

void PushInteger(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_int();
    set.AddInt(v_name, std::unique_ptr<int[]>(new int[1]{v}), 1);
    LInfo << "--->integer name:" << v_name << " value:" << v;
}

void PushFloat(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_float();
    set.AddFloat(v_name, std::unique_ptr<float[]>(new float[1]{v}), 1);
    LInfo << "--->float name:" << v_name << " value:" << v;
}

void PushBool(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_bool();
    set.AddBool(v_name, std::unique_ptr<bool[]>(new bool[1]{v}), 1);
    LInfo << "--->bool name:" << v_name << " value:" << v;
}

void PushRGB(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float r = node.attribute("r").as_float();
    float g = node.attribute("g").as_float();
    float b = node.attribute("b").as_float();
    set.AddRGBSpectrum(v_name, std::unique_ptr<float[]>(new float[3]{r, g, b}), 3);
    LInfo << "--->rgb name:" << v_name << " value:[" << r << "," << g << "," << b << "]";
}

void PushPoint2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddPoint2f(v_name, std::unique_ptr<Point2f[]>(new Point2f[1]{Point2f(x, y)}), 1);
    LInfo << "--->point2f name:" << v_name << " value:[" << x << "," << y << "]";
}

void PushPoint3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddPoint3f(v_name, std::unique_ptr<Point3f[]>(new Point3f[1]{Point3f(x, y, z)}), 1);
    LInfo << "--->point3f name:" << v_name << " value:[" << x << "," << y << "," << z << "]";
}

void PushVector2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddVector2f(v_name, std::unique_ptr<Vector2f[]>(new Vector2f[1]{Vector2f(x, y)}), 1);
    LInfo << "--->vector2f name:" << v_name << " value:[" << x << "," << y << "]";
}

void PushVector3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddVector3f(v_name, std::unique_ptr<Vector3f[]>(new Vector3f[1]{Vector3f(x, y, z)}), 1);
    LInfo << "--->vector3f name:" << v_name << " value:[" << x << "," << y << "," << z << "]";
}

void PushNormal3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddNormal3f(v_name, std::unique_ptr<Normal3f[]>(new Normal3f[1]{Normal3f(x, y, z)}), 1);
    LInfo << "--->normal3f name:" << v_name << " value:[" << x << "," << y << "," << z << "]";
}

void PushIntegetArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<int> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atoi(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<int[]> ints(new int[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        ints[i] = splits[i];
    }
    set.AddInt(v_value, std::move(ints), splits.size());
    LInfo << "--->int[] name:" << v_name << " value:[" << v_value << "]";
}

void PushFloatArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<float> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atof(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<float[]> floats(new float[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        floats[i] = splits[i];
    }
    set.AddFloat(v_value, std::move(floats), splits.size());
    LInfo << "--->float[] name:" << v_name << " value:[" << v_value << "]";
}

void PushTexture(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddTexture(name, v_name);
    LInfo << "--->texture name:" << v_name;
}

void PushString(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddString(name, std::unique_ptr<std::string[]>(new std::string[1]{v_name}), 1);
    LInfo << "--->string name:" << v_name;
}

void XMLBinder::PharseChildNodeParamSet(ParamSet &set, const pugi::xml_node &root) const
{

    for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
    {
        const char *name = node.name();
        if (strcmp(name, "integer") == 0)
        {
            //单个整数
            PushInteger(set, node);
        }
        else if (strcmp(name, "float") == 0)
        {
            //单个浮点数
            PushFloat(set, node);
        }
        else if (strcmp(name, "bool") == 0)
        {
            //单个布尔值
            PushBool(set, node);
        }
        else if (strcmp(name, "rgb") == 0)
        {
            PushRGB(set, node);
        }
        else if (strcmp(name, "point2f") == 0)
        {
            PushPoint2f(set, node);
        }
        else if (strcmp(name, "point3f") == 0)
        {
            PushPoint3f(set, node);
        }
        else if (strcmp(name, "vector2f") == 0)
        {
            PushVector2f(set, node);
        }
        else if (strcmp(name, "vector3f") == 0)
        {
            PushVector3f(set, node);
        }
        else if (strcmp(name, "normal3f") == 0)
        {
            PushNormal3f(set, node);
        }
        else if (strcmp(name, "integer_array") == 0)
        {
            PushIntegetArray(set, node);
        }
        else if (strcmp(name, "float_array") == 0)
        {
            PushFloatArray(set, node);
        }
        else if (strcmp(name, "texture") == 0)
        {
            PushTexture(set, node);
        }
        else if (strcmp(name, "string") == 0)
        {
            //字符串
            PushString(set, node);
        }
    }
}

void XMLBinder::ExecScript(const char *fileName)
{
    pugi::xml_parse_result result = _doc.load_file(fileName);
    LInfo << "Loading XML state:" << result.description();
    auto root = _doc.first_child();
    if (strcmp(root.name(), "scene") == 0)
    {
        //开始解析scene层
        LInfo << "->scene node";
        for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
        {
            const char *name = node.name();
            if (strcmp(name, "world_begin") == 0)
            {
                LInfo << "-->world begin node";
                raidenWorldBegin();
            }
            else if (strcmp(name, "world_end") == 0)
            {
                LInfo << "-->world end node";
                raidenWorldEnd();
            }
            else if (strcmp(name, "translate") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                LInfo << "-->translate node:[" << dx << " ," << dy << " ," << dz << "]";
                raidenTranslate(dx, dy, dz);
            }
            else if (strcmp(name, "rotate") == 0)
            {
                float angle = node.attribute("angle").as_float();
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                LInfo << "-->rotate node:[" << angle << "|" << dx << " ," << dy << " ," << dz << "]";
                raidenRotate(angle, dx, dy, dz);
            }
            else if (strcmp(name, "scale") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                LInfo << "-->scale node:[" << dx << " ," << dy << " ," << dz << "]";
                raidenScale(dx, dy, dz);
            }
            else if (strcmp(name, "frame_save") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordinateSystem(frame_name);
                LInfo << "-->save_frame:" << frame_name;
            }
            else if (strcmp(name, "frame_load") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordSysTransform(frame_name);
                LInfo << "-->load_frame:" << frame_name;
            }
            //TODO 和时间有关的API还没有绑定
            else if (strcmp(name, "filter") == 0)
            {
                LInfo << "-->filter node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenPixelFilter(type, params);
            }
            else if (strcmp(name, "accelerator") == 0)
            {
                LInfo << "-->accelerator node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAccelerator(type, params);
            }
            else if (strcmp(name, "integrator") == 0)
            {
                LInfo << "-->integrator node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenIntegrator(type, params);
            }
            else if (strcmp(name, "camera") == 0)
            {
                LInfo << "-->camera node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenCamera(type, params);
            }
            else if (strcmp(name, "film") == 0)
            {
                LInfo << "-->film node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenFilm(type, params);
            }
            else if (strcmp(name, "sampler") == 0)
            {
                LInfo << "-->sampler node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenSampler(type, params);
            }
            else if (strcmp(name, "shape") == 0)
            {
                LInfo << "-->shape node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenShape(type, params);
            }
            else if (strcmp(name, "texture") == 0)
            {
                LInfo << "-->texture node";
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                auto type = node.attribute("type").as_string();
                auto src = node.attribute("source").as_string();
                PharseChildNodeParamSet(params, node);
                raidenTexture(t_name, type, src, params);
            }
            else if (strcmp(name, "material") == 0)
            {
                LInfo << "-->material node";
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                PushString(params, node, "type");
                PharseChildNodeParamSet(params, node);
                raidenMakeNamedMaterial(t_name, params);
            }
            else if (strcmp(name, "material_tmp") == 0)
            {
                LInfo << "-->temporary material node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenMaterial(type, params);
            }
            else if (strcmp(name, "material_ref") == 0)
            {
                LInfo << "-->reference material node";
                auto t_name = node.attribute("name").as_string();
                raidenNamedMaterial(t_name);
            }
            else if (strcmp(name, "transform_begin") == 0)
            {
                LInfo << "-->transfrom begin node";
                raidenTransformBegin();
            }
            else if (strcmp(name, "transform_end") == 0)
            {
                LInfo << "-->transfrom end node";
                raidenTransformEnd();
            }
            else if (strcmp(name, "light") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenLightSource(type, params);
            }
            else if (strcmp(name, "area_light") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAreaLightSource(type,params);
            }
        }
    }
    else
    {
        LWarning << "XML file must has a root node \"scene\" but \"" << root << "\" now";
    }
}<commit_msg>重新修改xml的表情名，和LUA端统一<commit_after>#include "xmlbinder.h"
#include "raiden.h"
#include "paramset.h"
#include <string>
void XMLBinder::Init()
{
}

void XMLBinder::Release()
{
}

void PushInteger(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_int();
    set.AddInt(v_name, std::unique_ptr<int[]>(new int[1]{v}), 1);
}

void PushFloat(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_float();
    set.AddFloat(v_name, std::unique_ptr<float[]>(new float[1]{v}), 1);
}

void PushBool(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_bool();
    set.AddBool(v_name, std::unique_ptr<bool[]>(new bool[1]{v}), 1);
}

void PushRGB(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float r = node.attribute("r").as_float();
    float g = node.attribute("g").as_float();
    float b = node.attribute("b").as_float();
    set.AddRGBSpectrum(v_name, std::unique_ptr<float[]>(new float[3]{r, g, b}), 3);
}

void PushPoint2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddPoint2f(v_name, std::unique_ptr<Point2f[]>(new Point2f[1]{Point2f(x, y)}), 1);
}

void PushPoint3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddPoint3f(v_name, std::unique_ptr<Point3f[]>(new Point3f[1]{Point3f(x, y, z)}), 1);
}

void PushVector2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddVector2f(v_name, std::unique_ptr<Vector2f[]>(new Vector2f[1]{Vector2f(x, y)}), 1);
}

void PushVector3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddVector3f(v_name, std::unique_ptr<Vector3f[]>(new Vector3f[1]{Vector3f(x, y, z)}), 1);
}

void PushNormal3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddNormal3f(v_name, std::unique_ptr<Normal3f[]>(new Normal3f[1]{Normal3f(x, y, z)}), 1);
}

void PushIntegetArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<int> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atoi(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<int[]> ints(new int[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        ints[i] = splits[i];
    }
    set.AddInt(v_value, std::move(ints), splits.size());
}

void PushFloatArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<float> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atof(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<float[]> floats(new float[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        floats[i] = splits[i];
    }
    set.AddFloat(v_value, std::move(floats), splits.size());
}

void PushTexture(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddTexture(name, v_name);
}

void PushString(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddString(name, std::unique_ptr<std::string[]>(new std::string[1]{v_name}), 1);
}

void XMLBinder::PharseChildNodeParamSet(ParamSet &set, const pugi::xml_node &root) const
{

    for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
    {
        const char *name = node.name();
        if (strcmp(name, "integer") == 0)
        {
            //单个整数
            PushInteger(set, node);
        }
        else if (strcmp(name, "float") == 0)
        {
            //单个浮点数
            PushFloat(set, node);
        }
        else if (strcmp(name, "bool") == 0)
        {
            //单个布尔值
            PushBool(set, node);
        }
        else if (strcmp(name, "rgb") == 0)
        {
            PushRGB(set, node);
        }
        else if (strcmp(name, "point2f") == 0)
        {
            PushPoint2f(set, node);
        }
        else if (strcmp(name, "point3f") == 0)
        {
            PushPoint3f(set, node);
        }
        else if (strcmp(name, "vector2f") == 0)
        {
            PushVector2f(set, node);
        }
        else if (strcmp(name, "vector3f") == 0)
        {
            PushVector3f(set, node);
        }
        else if (strcmp(name, "normal3f") == 0)
        {
            PushNormal3f(set, node);
        }
        else if (strcmp(name, "integer_array") == 0)
        {
            PushIntegetArray(set, node);
        }
        else if (strcmp(name, "float_array") == 0)
        {
            PushFloatArray(set, node);
        }
        else if (strcmp(name, "texture") == 0)
        {
            PushTexture(set, node);
        }
        else if (strcmp(name, "string") == 0)
        {
            //字符串
            PushString(set, node);
        }
    }
}

void XMLBinder::ExecScript(const char *fileName)
{
    pugi::xml_parse_result result = _doc.load_file(fileName);
    LInfo << "Loading XML state:" << result.description();
    auto root = _doc.first_child();
    if (strcmp(root.name(), "Scene") == 0)
    {
        //开始解析scene层
        LInfo << "->scene node";
        for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
        {
            const char *name = node.name();
            if (strcmp(name, "WorldBegin") == 0)
            {
                raidenWorldBegin();
            }
            else if (strcmp(name, "WorldEnd") == 0)
            {
                raidenWorldEnd();
            }
            else if (strcmp(name, "Translate") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenTranslate(dx, dy, dz);
            }
            else if (strcmp(name, "Rotate") == 0)
            {
                float angle = node.attribute("angle").as_float();
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenRotate(angle, dx, dy, dz);
            }
            else if (strcmp(name, "Scale") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenScale(dx, dy, dz);
            }
            else if (strcmp(name, "CoordinateSystem") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordinateSystem(frame_name);
            }
            else if (strcmp(name, "CoordSysTransform") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordSysTransform(frame_name);
            }
            //TODO 和时间有关的API还没有绑定
            else if (strcmp(name, "PixelFilter") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenPixelFilter(type, params);
            }
            else if (strcmp(name, "Accelerator") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAccelerator(type, params);
            }
            else if (strcmp(name, "Integrator") == 0)
            {
                LInfo << "-->integrator node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenIntegrator(type, params);
            }
            else if (strcmp(name, "Camera") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenCamera(type, params);
            }
            else if (strcmp(name, "Film") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenFilm(type, params);
            }
            else if (strcmp(name, "Sampler") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenSampler(type, params);
            }
            else if (strcmp(name, "Shape") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenShape(type, params);
            }
            else if (strcmp(name, "Texture") == 0)
            {
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                auto type = node.attribute("type").as_string();
                auto src = node.attribute("source").as_string();
                PharseChildNodeParamSet(params, node);
                raidenTexture(t_name, type, src, params);
            }
            else if (strcmp(name, "MakeNamedMaterial") == 0)
            {
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                PushString(params, node, "type");
                PharseChildNodeParamSet(params, node);
                raidenMakeNamedMaterial(t_name, params);
            }
            else if (strcmp(name, "Material") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenMaterial(type, params);
            }
            else if (strcmp(name, "NamedMaterial") == 0)
            {
                auto t_name = node.attribute("name").as_string();
                raidenNamedMaterial(t_name);
            }
            else if (strcmp(name, "TransformBegin") == 0)
            {
                raidenTransformBegin();
            }
            else if (strcmp(name, "TransformEnd") == 0)
            {
                raidenTransformEnd();
            }
            else if (strcmp(name, "LightSource") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenLightSource(type, params);
            }
            else if (strcmp(name, "AreaLightSource") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAreaLightSource(type,params);
            }
        }
    }
    else
    {
        LWarning << "XML file must has a root node \"scene\" but \"" << root << "\" now";
    }
}<|endoftext|>


<commit_before>/*
 * This file is part of the "libstx" project
 *   Copyright (c) 2015 Paul Asmuth, FnordCorp B.V.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include "stx/stdtypes.h"
#include "stx/rpc/RPCRequest.h"
#include "stx/rpc/RPCContext.h"

namespace stx {
namespace rpc {

RPCRequest::RPCRequest(
    Function<void (RPCContext* ctx)> call_fn) :
    call_fn_(call_fn),
    ready_(false),
    error_(nullptr),
    running_(false) {}

void RPCRequest::run() {
  {
    std::unique_lock<std::mutex> lk(mutex_);
    if (ready_ || running_) {
      RAISE(kRuntimeError, "refusing to run a finished/running job");
    }

    running_ = true;
  }

  RPCContext ctx(this);
  try {
    call_fn_(&ctx);
  } catch (const StandardException& e) {
    returnError(e);
    return;
  }

  return returnSuccess();
}

void RPCRequest::returnSuccess() {
  {
    std::unique_lock<std::mutex> lk(mutex_);
    ready_ = true;
  }

  cv_.notify_all();

  if (on_ready_) {
    on_ready_();
  }

  on_ready_ = nullptr;
  on_cancel_ = nullptr;
  on_event_.clear();
}

void RPCRequest::returnError(const StandardException& e) {
  try {
    auto rte = dynamic_cast<const stx::Exception&>(e);
    returnError(rte.getType(), rte.getMessage());
  } catch (const std::exception& cast_error) {
    returnError(kRuntimeError, e.what());
  }
}

void RPCRequest::returnError(ExceptionType error_type, const String& message) {
  std::unique_lock<std::mutex> lk(mutex_);
  if (ready_) {
    RAISE(kRuntimeError, "refusing to send an error to a finished job");
  }

  error_ = error_type;
  error_message_ = message;
  ready_ = true;
  lk.unlock();

  cv_.notify_all();

  if (on_ready_) {
    on_ready_();
  }

  on_ready_ = nullptr;
  on_cancel_ = nullptr;
  on_event_.clear();
}

void RPCRequest::cancel() {
  std::unique_lock<std::mutex> lk(mutex_);
  if (ready_) {
    return;
  }

  error_ = kCancelledError;
  error_message_ =  "RPCRequest cancelled";
  ready_ = true;
  lk.unlock();

  cv_.notify_all();

  if (on_cancel_) {
    on_cancel_();
  }

  if (on_ready_) {
    on_ready_();
  }

  on_ready_ = nullptr;
  on_cancel_ = nullptr;
  on_event_.clear();
}

void RPCRequest::wait() const {
  std::unique_lock<std::mutex> lk(mutex_);

  while (!ready_) {
    cv_.wait(lk);
  }
}

bool RPCRequest::waitFor(const Duration& timeout) const {
  std::unique_lock<std::mutex> lk(mutex_);

  if (ready_) {
    return true;
  }

  cv_.wait_for(lk, std::chrono::microseconds(timeout.microseconds()));
  return ready_;
}

} // namespace rpc
} // namespace stx

<commit_msg>RPCRequest::onReady<commit_after>/*
 * This file is part of the "libstx" project
 *   Copyright (c) 2015 Paul Asmuth, FnordCorp B.V.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include "stx/stdtypes.h"
#include "stx/rpc/RPCRequest.h"
#include "stx/rpc/RPCContext.h"

namespace stx {
namespace rpc {

RPCRequest::RPCRequest(
    Function<void (RPCContext* ctx)> call_fn) :
    call_fn_(call_fn),
    ready_(false),
    error_(nullptr),
    running_(false) {}

void RPCRequest::run() {
  {
    std::unique_lock<std::mutex> lk(mutex_);
    if (ready_ || running_) {
      RAISE(kRuntimeError, "refusing to run a finished/running job");
    }

    running_ = true;
  }

  RPCContext ctx(this);
  try {
    call_fn_(&ctx);
  } catch (const StandardException& e) {
    returnError(e);
    return;
  }

  return returnSuccess();
}

void RPCRequest::onReady(Function<void ()> fn) {
  std::unique_lock<std::mutex> lk(mutex_);

  if (ready_) {
    fn();
  } else {
    on_ready_ = fn;
  }
}

void RPCRequest::returnSuccess() {
  {
    std::unique_lock<std::mutex> lk(mutex_);
    ready_ = true;
  }

  cv_.notify_all();

  if (on_ready_) {
    on_ready_();
  }

  on_ready_ = nullptr;
  on_cancel_ = nullptr;
  on_event_.clear();
}

void RPCRequest::returnError(const StandardException& e) {
  try {
    auto rte = dynamic_cast<const stx::Exception&>(e);
    returnError(rte.getType(), rte.getMessage());
  } catch (const std::exception& cast_error) {
    returnError(kRuntimeError, e.what());
  }
}

void RPCRequest::returnError(ExceptionType error_type, const String& message) {
  std::unique_lock<std::mutex> lk(mutex_);
  if (ready_) {
    RAISE(kRuntimeError, "refusing to send an error to a finished job");
  }

  error_ = error_type;
  error_message_ = message;
  ready_ = true;
  lk.unlock();

  cv_.notify_all();

  if (on_ready_) {
    on_ready_();
  }

  on_ready_ = nullptr;
  on_cancel_ = nullptr;
  on_event_.clear();
}

void RPCRequest::cancel() {
  std::unique_lock<std::mutex> lk(mutex_);
  if (ready_) {
    return;
  }

  error_ = kCancelledError;
  error_message_ =  "RPCRequest cancelled";
  ready_ = true;
  lk.unlock();

  cv_.notify_all();

  if (on_cancel_) {
    on_cancel_();
  }

  if (on_ready_) {
    on_ready_();
  }

  on_ready_ = nullptr;
  on_cancel_ = nullptr;
  on_event_.clear();
}

void RPCRequest::wait() const {
  std::unique_lock<std::mutex> lk(mutex_);

  while (!ready_) {
    cv_.wait(lk);
  }
}

bool RPCRequest::waitFor(const Duration& timeout) const {
  std::unique_lock<std::mutex> lk(mutex_);

  if (ready_) {
    return true;
  }

  cv_.wait_for(lk, std::chrono::microseconds(timeout.microseconds()));
  return ready_;
}

} // namespace rpc
} // namespace stx

<|endoftext|>


<commit_before>/*******************************************************************************
FILE : choose_enumerator_class.hpp

LAST MODIFIED : 10 March 2007

DESCRIPTION :
Class for implementing an wxList dialog control for choosing an object
from its manager (subject to an optional conditional function). Handles manager
messages to keep the menu up-to-date.
Calls the client-specified callback routine if a different object is chosen.
==============================================================================*/
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is cmgui.
 *
 * The Initial Developer of the Original Code is
 * Auckland Uniservices Ltd, Auckland, New Zealand.
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
#if !defined (CHOOSE_ENUMERATOR_CLASS_H)
#define CHOOSE_ENUMERATOR_CLASS_H

template < class Enumerator > class wxEnumeratorChooser : public wxChoice
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
============================================================================*/
{
private:
	Callback_base< typename Enumerator::Enumerator_type > *callback;

public:
	wxEnumeratorChooser<Enumerator>(wxPanel *parent,
		int number_of_items,
		const char **item_names, typename Enumerator::Enumerator_type current_value,
		User_interface *user_interface) :
		wxChoice(parent, /*id*/-1, wxPoint(0,0), wxSize(-1,-1))
	{
		USE_PARAMETER(user_interface);
		build_main_menu(number_of_items, item_names, current_value);

		Connect(wxEVT_COMMAND_CHOICE_SELECTED,
			wxCommandEventHandler(wxEnumeratorChooser::OnChoiceSelected));

		wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
		sizer->Add(this,
			wxSizerFlags(1).Align(wxALIGN_CENTER).Expand());
		parent->SetSizer(sizer);

		Show();
	}

	void OnChoiceSelected(wxCommandEvent& event)
	{
		USE_PARAMETER(event);
		if (callback)
		{
			callback->callback_function(get_item());
		}
   }

	typename Enumerator::Enumerator_type get_item()
	{
		return (static_cast<typename Enumerator::Enumerator_type>
			(GetSelection()));
	}

	int set_callback(Callback_base< typename Enumerator::Enumerator_type >
		*callback_object)
	{
		callback = callback_object;
		return (1);
	}

	int set_item(typename Enumerator::Enumerator_type new_value)
	{
		unsigned int return_code;

		SetSelection(new_value);

		// Could check to see that the value was actually set
		return_code = 1;

		return (return_code);
	}

	int build_main_menu(int number_of_items,
		const char **item_names,
		typename Enumerator::Enumerator_type current_value)
	{
		int i;
		Clear();
		for (i = 0 ; i < number_of_items ; i++)
		{
			Append(item_names[i]);
		}
		SetSelection(current_value);
		return 1;
	}
};

template < class Enumerator > class Enumerator_chooser
/*****************************************************************************
LAST MODIFIED : 10 March 2007

DESCRIPTION :
============================================================================*/
{
private:
	Enumerator *enumerator;
	wxPanel *parent;
	typename Enumerator::Conditional_function *conditional_function;
	void *conditional_function_user_data;
	wxEnumeratorChooser<Enumerator> *chooser;
	Callback_base< typename Enumerator::Enumerator_type > *update_callback;
   int number_of_items;
   const char **item_names;

public:
	Enumerator_chooser(wxPanel *parent,
		typename Enumerator::Enumerator_type current_value,
		typename Enumerator::Conditional_function *conditional_function,
		void *conditional_function_user_data,
		User_interface *user_interface) :
		enumerator(new Enumerator()), parent(parent),
		conditional_function(conditional_function),
		conditional_function_user_data(conditional_function_user_data)
/*****************************************************************************
LAST MODIFIED : 10 March 2007

DESCRIPTION :
============================================================================*/
	{
		chooser = (wxEnumeratorChooser<Enumerator> *)NULL;
		update_callback = (Callback_base< typename Enumerator::Enumerator_type > *)NULL;
		number_of_items = 0;
		item_names = (const char **)NULL;
		if (build_items())
		{
			chooser = new wxEnumeratorChooser<Enumerator>
				(parent, number_of_items,
				item_names, current_value,
				user_interface);
			typedef int (Enumerator_chooser::*Member_function)(typename Enumerator::Enumerator_type);
			Callback_base<typename Enumerator::Enumerator_type> *callback =
				new Callback_member_callback< typename Enumerator::Enumerator_type,
				Enumerator_chooser, Member_function>(
				this, &Enumerator_chooser::chooser_callback);

			chooser->set_callback(callback);
		}
		else
		{
			display_message(ERROR_MESSAGE,
				"Enumerator_chooser::Enumerator_chooser.   "
				" Could not get items");
		}

	} /* Enumerator_chooser::Enumerator_chooser */

	~Enumerator_chooser()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
============================================================================*/
	{
		if (chooser)
		{
			  chooser->Destroy();
		}

		delete enumerator;
		if (item_names)
		{
			 // We only free the array, not the strings themselves for
			 // strings from an enumerator
			DEALLOCATE(item_names);
		}
	} /* Enumerator_chooser::~Enumerator_chooser() */

	int chooser_callback(typename Enumerator::Enumerator_type value)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Called by the
============================================================================*/
	{
		int return_code;

		if (update_callback)
		{
			/* now call the procedure with the user data */
			update_callback->callback_function(value);
		}
		return_code=1;

		return (return_code);
	} /* Enumerator_chooser::get_callback */

	Callback_base< typename Enumerator::Enumerator_type > *get_callback()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Returns a pointer to the callback item.
============================================================================*/
	{
		return update_callback;
	} /* Enumerator_chooser::get_callback */

	int set_callback(Callback_base< typename Enumerator::Enumerator_type > *new_callback)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Changes the callback item.
============================================================================*/
	{
		update_callback = new_callback;
		return(1);
	} /* Enumerator_chooser::set_callback */

	typename Enumerator::Enumerator_type get_value()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Returns the currently chosen object.
============================================================================*/
	{
		return(chooser->get_item());
	} /* Enumerator_chooser::get_object */

	int set_value(typename Enumerator::Enumerator_type new_value)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Changes the chosen object in the choose_object_widget.
============================================================================*/
	{
		return(chooser->set_item(new_value));
	} /* Enumerator_chooser::set_object */

	int set_conditional_function(
		typename Enumerator::Conditional_function *conditional_function,
		void *conditional_function_user_data, typename Enumerator::Enumerator_type new_value)
/*****************************************************************************
LAST MODIFIED : 10 March 2007

DESCRIPTION :
Changes the conditional_function and user_data limiting the available
selection of objects. Also allows new_object to be set simultaneously.
============================================================================*/
	{
		int return_code;

		conditional_function = conditional_function;
		conditional_function_user_data = conditional_function_user_data;
		if (build_items())
		{
			return_code=chooser->build_main_menu(
				number_of_items, item_names, new_value);
		}
		else
		{
			return_code=0;
		}
		if (!return_code)
		{
			display_message(ERROR_MESSAGE,
				"Enumerator_chooser::set_conditional_function"
				"Could not update menu");
		}
		return (return_code);
	} /* Enumerator_chooser::set_conditional_function */

private:

	int is_item_in_chooser(typename Enumerator::Enumerator_type value)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
============================================================================*/
	{
		int i, return_code;

		if ((value > 0) && (value <= number_of_items))
		{
			return_code = 1;
		}
		else
		{
			return_code=0;
		}

		return (return_code);
	} /* Enumerator_chooser::is_item_in_chooser */

	int build_items()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Updates the arrays of all the choosable objects and their names.
============================================================================*/
	{
		int return_code;

		if (item_names)
		{
			 // We only free the array, not the strings themselves for
			 // strings from an enumerator
			DEALLOCATE(item_names);
		}

		item_names = enumerator->get_valid_strings(&number_of_items,
			conditional_function, conditional_function_user_data);
		return_code = 1;

		return (return_code);
	}  /* Enumerator_chooser::build_items */

}; /* template < class Managed_object > class Enumerator_chooser */

#endif /* !defined (CHOOSE_ENUMERATOR_CLASS_H) */
<commit_msg>Fixed enumerator chooser hold on to an callback object and do not release it at the end. Tracker item 2610, https://tracker.physiomeproject.org/show_bug.cgi?id=2610<commit_after>/*******************************************************************************
FILE : choose_enumerator_class.hpp

LAST MODIFIED : 10 March 2007

DESCRIPTION :
Class for implementing an wxList dialog control for choosing an object
from its manager (subject to an optional conditional function). Handles manager
messages to keep the menu up-to-date.
Calls the client-specified callback routine if a different object is chosen.
==============================================================================*/
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is cmgui.
 *
 * The Initial Developer of the Original Code is
 * Auckland Uniservices Ltd, Auckland, New Zealand.
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
#if !defined (CHOOSE_ENUMERATOR_CLASS_H)
#define CHOOSE_ENUMERATOR_CLASS_H

template < class Enumerator > class wxEnumeratorChooser : public wxChoice
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
============================================================================*/
{
private:
	Callback_base< typename Enumerator::Enumerator_type > *callback;

public:
	wxEnumeratorChooser<Enumerator>(wxPanel *parent,
		int number_of_items,
		const char **item_names, typename Enumerator::Enumerator_type current_value,
		User_interface *user_interface) :
		wxChoice(parent, /*id*/-1, wxPoint(0,0), wxSize(-1,-1))
	{
		USE_PARAMETER(user_interface);
		callback = NULL;
		build_main_menu(number_of_items, item_names, current_value);

		Connect(wxEVT_COMMAND_CHOICE_SELECTED,
			wxCommandEventHandler(wxEnumeratorChooser::OnChoiceSelected));

		wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
		sizer->Add(this,
			wxSizerFlags(1).Align(wxALIGN_CENTER).Expand());
		parent->SetSizer(sizer);

		Show();
	}

	~wxEnumeratorChooser<Enumerator>()
		{
			if (callback)
				delete callback;
		}

	void OnChoiceSelected(wxCommandEvent& event)
	{
		USE_PARAMETER(event);
		if (callback)
		{
			callback->callback_function(get_item());
		}
   }

	typename Enumerator::Enumerator_type get_item()
	{
		return (static_cast<typename Enumerator::Enumerator_type>
			(GetSelection()));
	}

	int set_callback(Callback_base< typename Enumerator::Enumerator_type >
		*callback_object)
	{
		if (callback)
			delete callback;
		callback = callback_object;
		return (1);
	}

	int set_item(typename Enumerator::Enumerator_type new_value)
	{
		unsigned int return_code;

		SetSelection(new_value);

		// Could check to see that the value was actually set
		return_code = 1;

		return (return_code);
	}

	int build_main_menu(int number_of_items,
		const char **item_names,
		typename Enumerator::Enumerator_type current_value)
	{
		int i;
		Clear();
		for (i = 0 ; i < number_of_items ; i++)
		{
			Append(item_names[i]);
		}
		SetSelection(current_value);
		return 1;
	}
};

template < class Enumerator > class Enumerator_chooser
/*****************************************************************************
LAST MODIFIED : 10 March 2007

DESCRIPTION :
============================================================================*/
{
private:
	Enumerator *enumerator;
	wxPanel *parent;
	typename Enumerator::Conditional_function *conditional_function;
	void *conditional_function_user_data;
	wxEnumeratorChooser<Enumerator> *chooser;
	Callback_base< typename Enumerator::Enumerator_type > *update_callback;
   int number_of_items;
   const char **item_names;

public:
	Enumerator_chooser(wxPanel *parent,
		typename Enumerator::Enumerator_type current_value,
		typename Enumerator::Conditional_function *conditional_function,
		void *conditional_function_user_data,
		User_interface *user_interface) :
		enumerator(new Enumerator()), parent(parent),
		conditional_function(conditional_function),
		conditional_function_user_data(conditional_function_user_data)
/*****************************************************************************
LAST MODIFIED : 10 March 2007

DESCRIPTION :
============================================================================*/
	{
		chooser = (wxEnumeratorChooser<Enumerator> *)NULL;
		update_callback = (Callback_base< typename Enumerator::Enumerator_type > *)NULL;
		number_of_items = 0;
		item_names = (const char **)NULL;
		if (build_items())
		{
			chooser = new wxEnumeratorChooser<Enumerator>
				(parent, number_of_items,
				item_names, current_value,
				user_interface);
			typedef int (Enumerator_chooser::*Member_function)(typename Enumerator::Enumerator_type);
			Callback_base<typename Enumerator::Enumerator_type> *callback =
				new Callback_member_callback< typename Enumerator::Enumerator_type,
				Enumerator_chooser, Member_function>(
				this, &Enumerator_chooser::chooser_callback);

			chooser->set_callback(callback);
		}
		else
		{
			display_message(ERROR_MESSAGE,
				"Enumerator_chooser::Enumerator_chooser.   "
				" Could not get items");
		}

	} /* Enumerator_chooser::Enumerator_chooser */

	~Enumerator_chooser()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
============================================================================*/
	{
		if (chooser)
		{
			  chooser->Destroy();
		}
		if (update_callback)
			delete update_callback;
		delete enumerator;
		if (item_names)
		{
			 // We only free the array, not the strings themselves for
			 // strings from an enumerator
			DEALLOCATE(item_names);
		}
	} /* Enumerator_chooser::~Enumerator_chooser() */

	int chooser_callback(typename Enumerator::Enumerator_type value)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Called by the
============================================================================*/
	{
		int return_code;

		if (update_callback)
		{
			/* now call the procedure with the user data */
			update_callback->callback_function(value);
		}
		return_code=1;

		return (return_code);
	} /* Enumerator_chooser::get_callback */

	Callback_base< typename Enumerator::Enumerator_type > *get_callback()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Returns a pointer to the callback item.
============================================================================*/
	{
		return update_callback;
	} /* Enumerator_chooser::get_callback */

	int set_callback(Callback_base< typename Enumerator::Enumerator_type > *new_callback)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Changes the callback item.
============================================================================*/
	{
		if (update_callback)
		{
			delete update_callback;
		}
		update_callback = new_callback;
		return(1);
	} /* Enumerator_chooser::set_callback */

	typename Enumerator::Enumerator_type get_value()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Returns the currently chosen object.
============================================================================*/
	{
		return(chooser->get_item());
	} /* Enumerator_chooser::get_object */

	int set_value(typename Enumerator::Enumerator_type new_value)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Changes the chosen object in the choose_object_widget.
============================================================================*/
	{
		return(chooser->set_item(new_value));
	} /* Enumerator_chooser::set_object */

	int set_conditional_function(
		typename Enumerator::Conditional_function *conditional_function,
		void *conditional_function_user_data, typename Enumerator::Enumerator_type new_value)
/*****************************************************************************
LAST MODIFIED : 10 March 2007

DESCRIPTION :
Changes the conditional_function and user_data limiting the available
selection of objects. Also allows new_object to be set simultaneously.
============================================================================*/
	{
		int return_code;

		conditional_function = conditional_function;
		conditional_function_user_data = conditional_function_user_data;
		if (build_items())
		{
			return_code=chooser->build_main_menu(
				number_of_items, item_names, new_value);
		}
		else
		{
			return_code=0;
		}
		if (!return_code)
		{
			display_message(ERROR_MESSAGE,
				"Enumerator_chooser::set_conditional_function"
				"Could not update menu");
		}
		return (return_code);
	} /* Enumerator_chooser::set_conditional_function */

private:

	int is_item_in_chooser(typename Enumerator::Enumerator_type value)
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
============================================================================*/
	{
		int i, return_code;

		if ((value > 0) && (value <= number_of_items))
		{
			return_code = 1;
		}
		else
		{
			return_code=0;
		}

		return (return_code);
	} /* Enumerator_chooser::is_item_in_chooser */

	int build_items()
/*****************************************************************************
LAST MODIFIED : 8 February 2007

DESCRIPTION :
Updates the arrays of all the choosable objects and their names.
============================================================================*/
	{
		int return_code;

		if (item_names)
		{
			 // We only free the array, not the strings themselves for
			 // strings from an enumerator
			DEALLOCATE(item_names);
		}

		item_names = enumerator->get_valid_strings(&number_of_items,
			conditional_function, conditional_function_user_data);
		return_code = 1;

		return (return_code);
	}  /* Enumerator_chooser::build_items */

}; /* template < class Managed_object > class Enumerator_chooser */

#endif /* !defined (CHOOSE_ENUMERATOR_CLASS_H) */
<|endoftext|>