<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(port): the ifdefs in here are a first step towards trying to determine
// the correct abstraction for all the OS functionality required at this
// stage of process initialization. It should not be taken as a final
// abstraction.

#include "build/build_config.h"

#if defined(OS_WIN)
#include <algorithm>
#include <atlbase.h>
#include <atlapp.h>
#include <malloc.h>
#include <new.h>
#endif

#if defined(OS_LINUX)
#include <gtk/gtk.h>
#endif

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/icu_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/stats_table.h"
#include "base/string_util.h"
#if defined(OS_WIN)
#include "base/win_util.h"
#endif
#include "chrome/app/scoped_ole_initializer.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_counters.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/sandbox_init_wrapper.h"
#if defined(OS_WIN)
#include "sandbox/src/sandbox.h"
#include "tools/memory_watcher/memory_watcher.h"
#endif
#if defined(OS_MACOSX)
#include "third_party/WebKit/WebKit/mac/WebCoreSupport/WebSystemInterface.h"
#endif

extern int BrowserMain(const MainFunctionParams&);
extern int RendererMain(const MainFunctionParams&);
extern int PluginMain(const MainFunctionParams&);
extern int WorkerMain(const MainFunctionParams&);

#if defined(OS_WIN)
// TODO(erikkay): isn't this already defined somewhere?
#define DLLEXPORT __declspec(dllexport)

// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
extern "C" {
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo* sandbox_info,
                                 TCHAR* command_line);
}
#elif defined(OS_POSIX)
extern "C" {
int ChromeMain(int argc, const char** argv);
}
#endif

namespace {

#if defined(OS_WIN)
const wchar_t kProfilingDll[] = L"memory_watcher.dll";

// Load the memory profiling DLL.  All it needs to be activated
// is to be loaded.  Return true on success, false otherwise.
bool LoadMemoryProfiler() {
  HMODULE prof_module = LoadLibrary(kProfilingDll);
  return prof_module != NULL;
}

CAppModule _Module;

#pragma optimize("", off)
// Handlers for invalid parameter and pure call. They generate a breakpoint to
// tell breakpad that it needs to dump the process.
void InvalidParameter(const wchar_t* expression, const wchar_t* function,
                      const wchar_t* file, unsigned int line,
                      uintptr_t reserved) {
  __debugbreak();
}

void PureCall() {
  __debugbreak();
}

int OnNoMemory(size_t memory_size) {
  __debugbreak();
  // Return memory_size so it is not optimized out. Make sure the return value
  // is at least 1 so malloc/new is retried, especially useful when under a
  // debugger.
  return memory_size ? static_cast<int>(memory_size) : 1;
}

// Handlers to silently dump the current process when there is an assert in
// chrome.
void ChromeAssert(const std::string& str) {
  // Get the breakpad pointer from chrome.exe
  typedef void (__stdcall *DumpProcessFunction)();
  DumpProcessFunction DumpProcess = reinterpret_cast<DumpProcessFunction>(
      ::GetProcAddress(::GetModuleHandle(L"chrome.exe"), "DumpProcess"));
  if (DumpProcess)
    DumpProcess();
}

#pragma optimize("", on)

// Early versions of Chrome incorrectly registered a chromehtml: URL handler.
// Later versions fixed the registration but in some cases (e.g. Vista and non-
// admin installs) the fix could not be applied.  This prevents Chrome to be
// launched with the incorrect format.
// CORRECT: <broser.exe> -- "chromehtml:<url>"
// INVALID: <broser.exe> "chromehtml:<url>"
bool IncorrectChromeHtmlArguments(const std::wstring& command_line) {
  const wchar_t kChromeHtml[] = L"-- \"chromehtml:";
  const wchar_t kOffset = 5;  // Where chromehtml: starts in above
  std::wstring command_line_lower = command_line;

  // We are only searching for ASCII characters so this is OK.
  StringToLowerASCII(&command_line_lower);

  std::wstring::size_type pos = command_line_lower.find(
      kChromeHtml + kOffset);

  if (pos == std::wstring::npos)
    return false;

  // The browser is being launched with chromehtml: somewhere on the command
  // line.  We will not launch unless it's preceded by the -- switch terminator.
  if (pos >= kOffset) {
    if (equal(kChromeHtml, kChromeHtml + arraysize(kChromeHtml) - 1,
        command_line_lower.begin() + pos - kOffset)) {
      return false;
    }
  }

  return true;
}

#endif  // OS_WIN

// Register the invalid param handler and pure call handler to be able to
// notify breakpad when it happens.
void RegisterInvalidParamHandler() {
#if defined(OS_WIN)
  _set_invalid_parameter_handler(InvalidParameter);
  _set_purecall_handler(PureCall);
  // Gather allocation failure.
  _set_new_handler(&OnNoMemory);
  // Make sure malloc() calls the new handler too.
  _set_new_mode(1);
#endif
}

void SetupCRT(const CommandLine& parsed_command_line) {
#if defined(OS_WIN)
#ifdef _CRTDBG_MAP_ALLOC
  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
#else
  if (!parsed_command_line.HasSwitch(switches::kDisableBreakpad)) {
    _CrtSetReportMode(_CRT_ASSERT, 0);
  }
#endif

  // Enable the low fragmentation heap for the CRT heap. The heap is not changed
  // if the process is run under the debugger is enabled or if certain gflags
  // are set.
  bool use_lfh = false;
  if (parsed_command_line.HasSwitch(switches::kUseLowFragHeapCrt))
    use_lfh = parsed_command_line.GetSwitchValue(switches::kUseLowFragHeapCrt)
        != L"false";
  if (use_lfh) {
    void* crt_heap = reinterpret_cast<void*>(_get_heap_handle());
    ULONG enable_lfh = 2;
    HeapSetInformation(crt_heap, HeapCompatibilityInformation,
                       &enable_lfh, sizeof(enable_lfh));
  }
#endif
}

// Enable the heap profiler if the appropriate command-line switch is
// present, bailing out of the app we can't.
void EnableHeapProfiler(const CommandLine& parsed_command_line) {
#if defined(OS_WIN)
  if (parsed_command_line.HasSwitch(switches::kMemoryProfiling))
    if (!LoadMemoryProfiler())
      exit(-1);
#endif
}

void CommonSubprocessInit() {
  // Initialize ResourceBundle which handles files loaded from external
  // sources.  The language should have been passed in to us from the
  // browser process as a command line flag.
  ResourceBundle::InitSharedInstance(std::wstring());

#if defined(OS_WIN)
  // HACK: Let Windows know that we have started.  This is needed to suppress
  // the IDC_APPSTARTING cursor from being displayed for a prolonged period
  // while a subprocess is starting.
  PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
  MSG msg;
  PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
#endif
}

}  // namespace

#if defined(OS_WIN)
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo* sandbox_info,
                                 TCHAR* command_line) {
#elif defined(OS_POSIX)
int ChromeMain(int argc, const char** argv) {
#endif

#if defined(OS_MACOSX)
  DebugUtil::DisableOSCrashDumps();
#endif
  RegisterInvalidParamHandler();

  // The exit manager is in charge of calling the dtors of singleton objects.
  base::AtExitManager exit_manager;

  // We need this pool for all the objects created before we get to the
  // event loop, but we don't want to leave them hanging around until the
  // app quits. Each "main" needs to flush this pool right before it goes into
  // its main event loop to get rid of the cruft.
  base::ScopedNSAutoreleasePool autorelease_pool;

  // Initialize the command line.
#if defined(OS_WIN)
  CommandLine::Init(0, NULL);
#else
  CommandLine::Init(argc, argv);
#endif
  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();

#if defined(OS_WIN)
   // Must do this before any other usage of command line!
  if (::IncorrectChromeHtmlArguments(parsed_command_line.command_line_string()))
    return 1;
#endif

  int browser_pid;
  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);
  if (process_type.empty()) {
    browser_pid = base::GetCurrentProcId();
  } else {
    std::wstring channel_name =
      parsed_command_line.GetSwitchValue(switches::kProcessChannelID);

    browser_pid = StringToInt(WideToASCII(channel_name));
    DCHECK(browser_pid != 0);
  }
  SetupCRT(parsed_command_line);

  // Initialize the Chrome path provider.
  chrome::RegisterPathProvider();

  // Initialize the Stats Counters table.  With this initialized,
  // the StatsViewer can be utilized to read counters outside of
  // Chrome.  These lines can be commented out to effectively turn
  // counters 'off'.  The table is created and exists for the life
  // of the process.  It is not cleaned up.
  // TODO(port): we probably need to shut this down correctly to avoid
  // leaking shared memory regions on posix platforms.
  std::string statsfile =
      StringPrintf("%s-%d", chrome::kStatsFilename, browser_pid);
  StatsTable *stats_table = new StatsTable(statsfile,
      chrome::kStatsMaxThreads, chrome::kStatsMaxCounters);
  StatsTable::set_current(stats_table);

  StatsScope<StatsCounterTimer>
      startup_timer(chrome::Counters::chrome_main());

  // Enable the heap profiler as early as possible!
  EnableHeapProfiler(parsed_command_line);

  // Enable Message Loop related state asap.
  if (parsed_command_line.HasSwitch(switches::kMessageLoopHistogrammer))
    MessageLoop::EnableHistogrammer(true);

  // Checks if the sandbox is enabled in this process and initializes it if this
  // is the case. The crash handler depends on this so it has to be done before
  // its initialization.
  SandboxInitWrapper sandbox_wrapper;
#if defined(OS_WIN)
  sandbox_wrapper.SetServices(sandbox_info);
#endif
  sandbox_wrapper.InitializeSandbox(parsed_command_line, process_type);

#if defined(OS_WIN)
  _Module.Init(NULL, instance);
#endif

  // Notice a user data directory override if any
  const std::wstring user_data_dir =
      parsed_command_line.GetSwitchValue(switches::kUserDataDir);
  if (!user_data_dir.empty())
    PathService::Override(chrome::DIR_USER_DATA, user_data_dir);

  bool single_process =
#if defined (GOOGLE_CHROME_BUILD)
    // This is an unsupported and not fully tested mode, so don't enable it for
    // official Chrome builds.
    false;
#else
    parsed_command_line.HasSwitch(switches::kSingleProcess);
#endif
  if (single_process)
    RenderProcessHost::set_run_renderer_in_process(true);
#if defined(OS_MACOSX)
  // TODO(port-mac): This is from renderer_main_platform_delegate.cc.
  // shess tried to refactor things appropriately, but it sprawled out
  // of control because different platforms needed different styles of
  // initialization.  Try again once we understand the process
  // architecture needed and where it should live.
  if (single_process)
    InitWebCoreSystemInterface();
#endif

  bool icu_result = icu_util::Initialize();
  CHECK(icu_result);

  logging::OldFileDeletionState file_state =
      logging::APPEND_TO_OLD_LOG_FILE;
  if (process_type.empty()) {
    file_state = logging::DELETE_OLD_LOG_FILE;
  }
  logging::InitChromeLogging(parsed_command_line, file_state);

#ifdef NDEBUG
  if (parsed_command_line.HasSwitch(switches::kSilentDumpOnDCHECK) &&
      parsed_command_line.HasSwitch(switches::kEnableDCHECK)) {
#if defined(OS_WIN)
    logging::SetLogReportHandler(ChromeAssert);
#endif
  }
#endif  // NDEBUG

  if (!process_type.empty())
    CommonSubprocessInit();

  startup_timer.Stop();  // End of Startup Time Measurement.

  MainFunctionParams main_params(parsed_command_line, sandbox_wrapper,
                                 &autorelease_pool);

  // TODO(port): turn on these main() functions as they've been de-winified.
  int rv = -1;
  if (process_type == switches::kRendererProcess) {
    rv = RendererMain(main_params);
  } else if (process_type == switches::kPluginProcess) {
#if defined(OS_WIN)
    rv = PluginMain(main_params);
#endif
  } else if (process_type == switches::kWorkerProcess) {
#if defined(OS_WIN)
    rv = WorkerMain(main_params);
#endif
  } else if (process_type.empty()) {
#if defined(OS_LINUX)
    // gtk_init() can change |argc| and |argv|, but nobody else uses them.
    gtk_init(&argc, const_cast<char***>(&argv));
#endif

    ScopedOleInitializer ole_initializer;
    rv = BrowserMain(main_params);
  } else {
    NOTREACHED() << "Unknown process type";
  }

  if (!process_type.empty()) {
    ResourceBundle::CleanupSharedInstance();
  }

#if defined(OS_WIN)
#ifdef _CRTDBG_MAP_ALLOC
  _CrtDumpMemoryLeaks();
#endif  // _CRTDBG_MAP_ALLOC

  _Module.Term();
#endif

  logging::CleanupChromeLogging();

  return rv;
}
<commit_msg>Pipe fatal GTK messages through our logging system.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(port): the ifdefs in here are a first step towards trying to determine
// the correct abstraction for all the OS functionality required at this
// stage of process initialization. It should not be taken as a final
// abstraction.

#include "build/build_config.h"

#if defined(OS_WIN)
#include <algorithm>
#include <atlbase.h>
#include <atlapp.h>
#include <malloc.h>
#include <new.h>
#endif

#if defined(OS_LINUX)
#include <gtk/gtk.h>
#endif

#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/icu_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/scoped_nsautorelease_pool.h"
#include "base/stats_table.h"
#include "base/string_util.h"
#if defined(OS_WIN)
#include "base/win_util.h"
#endif
#include "chrome/app/scoped_ole_initializer.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_counters.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/sandbox_init_wrapper.h"
#if defined(OS_WIN)
#include "sandbox/src/sandbox.h"
#include "tools/memory_watcher/memory_watcher.h"
#endif
#if defined(OS_MACOSX)
#include "third_party/WebKit/WebKit/mac/WebCoreSupport/WebSystemInterface.h"
#endif

extern int BrowserMain(const MainFunctionParams&);
extern int RendererMain(const MainFunctionParams&);
extern int PluginMain(const MainFunctionParams&);
extern int WorkerMain(const MainFunctionParams&);

#if defined(OS_WIN)
// TODO(erikkay): isn't this already defined somewhere?
#define DLLEXPORT __declspec(dllexport)

// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
extern "C" {
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo* sandbox_info,
                                 TCHAR* command_line);
}
#elif defined(OS_POSIX)
extern "C" {
int ChromeMain(int argc, const char** argv);
}
#endif

namespace {

#if defined(OS_WIN)
const wchar_t kProfilingDll[] = L"memory_watcher.dll";

// Load the memory profiling DLL.  All it needs to be activated
// is to be loaded.  Return true on success, false otherwise.
bool LoadMemoryProfiler() {
  HMODULE prof_module = LoadLibrary(kProfilingDll);
  return prof_module != NULL;
}

CAppModule _Module;

#pragma optimize("", off)
// Handlers for invalid parameter and pure call. They generate a breakpoint to
// tell breakpad that it needs to dump the process.
void InvalidParameter(const wchar_t* expression, const wchar_t* function,
                      const wchar_t* file, unsigned int line,
                      uintptr_t reserved) {
  __debugbreak();
}

void PureCall() {
  __debugbreak();
}

int OnNoMemory(size_t memory_size) {
  __debugbreak();
  // Return memory_size so it is not optimized out. Make sure the return value
  // is at least 1 so malloc/new is retried, especially useful when under a
  // debugger.
  return memory_size ? static_cast<int>(memory_size) : 1;
}

// Handlers to silently dump the current process when there is an assert in
// chrome.
void ChromeAssert(const std::string& str) {
  // Get the breakpad pointer from chrome.exe
  typedef void (__stdcall *DumpProcessFunction)();
  DumpProcessFunction DumpProcess = reinterpret_cast<DumpProcessFunction>(
      ::GetProcAddress(::GetModuleHandle(L"chrome.exe"), "DumpProcess"));
  if (DumpProcess)
    DumpProcess();
}

#pragma optimize("", on)

// Early versions of Chrome incorrectly registered a chromehtml: URL handler.
// Later versions fixed the registration but in some cases (e.g. Vista and non-
// admin installs) the fix could not be applied.  This prevents Chrome to be
// launched with the incorrect format.
// CORRECT: <broser.exe> -- "chromehtml:<url>"
// INVALID: <broser.exe> "chromehtml:<url>"
bool IncorrectChromeHtmlArguments(const std::wstring& command_line) {
  const wchar_t kChromeHtml[] = L"-- \"chromehtml:";
  const wchar_t kOffset = 5;  // Where chromehtml: starts in above
  std::wstring command_line_lower = command_line;

  // We are only searching for ASCII characters so this is OK.
  StringToLowerASCII(&command_line_lower);

  std::wstring::size_type pos = command_line_lower.find(
      kChromeHtml + kOffset);

  if (pos == std::wstring::npos)
    return false;

  // The browser is being launched with chromehtml: somewhere on the command
  // line.  We will not launch unless it's preceded by the -- switch terminator.
  if (pos >= kOffset) {
    if (equal(kChromeHtml, kChromeHtml + arraysize(kChromeHtml) - 1,
        command_line_lower.begin() + pos - kOffset)) {
      return false;
    }
  }

  return true;
}

#endif  // OS_WIN

#if defined(OS_LINUX)
static void GtkFatalLogHandler(const gchar* log_domain,
                               GLogLevelFlags log_level,
                               const gchar* message,
                               gpointer userdata) {
  if (!log_domain)
    log_domain = "<all>";
  if (!message)
    message = "<no message>";

  NOTREACHED() << "GTK: (" << log_domain << "): " << message;
}
#endif

// Register the invalid param handler and pure call handler to be able to
// notify breakpad when it happens.
void RegisterInvalidParamHandler() {
#if defined(OS_WIN)
  _set_invalid_parameter_handler(InvalidParameter);
  _set_purecall_handler(PureCall);
  // Gather allocation failure.
  _set_new_handler(&OnNoMemory);
  // Make sure malloc() calls the new handler too.
  _set_new_mode(1);
#endif
}

void SetupCRT(const CommandLine& parsed_command_line) {
#if defined(OS_WIN)
#ifdef _CRTDBG_MAP_ALLOC
  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
#else
  if (!parsed_command_line.HasSwitch(switches::kDisableBreakpad)) {
    _CrtSetReportMode(_CRT_ASSERT, 0);
  }
#endif

  // Enable the low fragmentation heap for the CRT heap. The heap is not changed
  // if the process is run under the debugger is enabled or if certain gflags
  // are set.
  bool use_lfh = false;
  if (parsed_command_line.HasSwitch(switches::kUseLowFragHeapCrt))
    use_lfh = parsed_command_line.GetSwitchValue(switches::kUseLowFragHeapCrt)
        != L"false";
  if (use_lfh) {
    void* crt_heap = reinterpret_cast<void*>(_get_heap_handle());
    ULONG enable_lfh = 2;
    HeapSetInformation(crt_heap, HeapCompatibilityInformation,
                       &enable_lfh, sizeof(enable_lfh));
  }
#endif
}

// Enable the heap profiler if the appropriate command-line switch is
// present, bailing out of the app we can't.
void EnableHeapProfiler(const CommandLine& parsed_command_line) {
#if defined(OS_WIN)
  if (parsed_command_line.HasSwitch(switches::kMemoryProfiling))
    if (!LoadMemoryProfiler())
      exit(-1);
#endif
}

void CommonSubprocessInit() {
  // Initialize ResourceBundle which handles files loaded from external
  // sources.  The language should have been passed in to us from the
  // browser process as a command line flag.
  ResourceBundle::InitSharedInstance(std::wstring());

#if defined(OS_WIN)
  // HACK: Let Windows know that we have started.  This is needed to suppress
  // the IDC_APPSTARTING cursor from being displayed for a prolonged period
  // while a subprocess is starting.
  PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
  MSG msg;
  PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
#endif
}

}  // namespace

#if defined(OS_WIN)
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo* sandbox_info,
                                 TCHAR* command_line) {
#elif defined(OS_POSIX)
int ChromeMain(int argc, const char** argv) {
#endif

#if defined(OS_MACOSX)
  DebugUtil::DisableOSCrashDumps();
#endif
  RegisterInvalidParamHandler();

  // The exit manager is in charge of calling the dtors of singleton objects.
  base::AtExitManager exit_manager;

  // We need this pool for all the objects created before we get to the
  // event loop, but we don't want to leave them hanging around until the
  // app quits. Each "main" needs to flush this pool right before it goes into
  // its main event loop to get rid of the cruft.
  base::ScopedNSAutoreleasePool autorelease_pool;

  // Initialize the command line.
#if defined(OS_WIN)
  CommandLine::Init(0, NULL);
#else
  CommandLine::Init(argc, argv);
#endif
  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();

#if defined(OS_WIN)
   // Must do this before any other usage of command line!
  if (::IncorrectChromeHtmlArguments(parsed_command_line.command_line_string()))
    return 1;
#endif

  int browser_pid;
  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);
  if (process_type.empty()) {
    browser_pid = base::GetCurrentProcId();
  } else {
    std::wstring channel_name =
      parsed_command_line.GetSwitchValue(switches::kProcessChannelID);

    browser_pid = StringToInt(WideToASCII(channel_name));
    DCHECK(browser_pid != 0);
  }
  SetupCRT(parsed_command_line);

  // Initialize the Chrome path provider.
  chrome::RegisterPathProvider();

  // Initialize the Stats Counters table.  With this initialized,
  // the StatsViewer can be utilized to read counters outside of
  // Chrome.  These lines can be commented out to effectively turn
  // counters 'off'.  The table is created and exists for the life
  // of the process.  It is not cleaned up.
  // TODO(port): we probably need to shut this down correctly to avoid
  // leaking shared memory regions on posix platforms.
  std::string statsfile =
      StringPrintf("%s-%d", chrome::kStatsFilename, browser_pid);
  StatsTable *stats_table = new StatsTable(statsfile,
      chrome::kStatsMaxThreads, chrome::kStatsMaxCounters);
  StatsTable::set_current(stats_table);

  StatsScope<StatsCounterTimer>
      startup_timer(chrome::Counters::chrome_main());

  // Enable the heap profiler as early as possible!
  EnableHeapProfiler(parsed_command_line);

  // Enable Message Loop related state asap.
  if (parsed_command_line.HasSwitch(switches::kMessageLoopHistogrammer))
    MessageLoop::EnableHistogrammer(true);

  // Checks if the sandbox is enabled in this process and initializes it if this
  // is the case. The crash handler depends on this so it has to be done before
  // its initialization.
  SandboxInitWrapper sandbox_wrapper;
#if defined(OS_WIN)
  sandbox_wrapper.SetServices(sandbox_info);
#endif
  sandbox_wrapper.InitializeSandbox(parsed_command_line, process_type);

#if defined(OS_WIN)
  _Module.Init(NULL, instance);
#endif

  // Notice a user data directory override if any
  const std::wstring user_data_dir =
      parsed_command_line.GetSwitchValue(switches::kUserDataDir);
  if (!user_data_dir.empty())
    PathService::Override(chrome::DIR_USER_DATA, user_data_dir);

  bool single_process =
#if defined (GOOGLE_CHROME_BUILD)
    // This is an unsupported and not fully tested mode, so don't enable it for
    // official Chrome builds.
    false;
#else
    parsed_command_line.HasSwitch(switches::kSingleProcess);
#endif
  if (single_process)
    RenderProcessHost::set_run_renderer_in_process(true);
#if defined(OS_MACOSX)
  // TODO(port-mac): This is from renderer_main_platform_delegate.cc.
  // shess tried to refactor things appropriately, but it sprawled out
  // of control because different platforms needed different styles of
  // initialization.  Try again once we understand the process
  // architecture needed and where it should live.
  if (single_process)
    InitWebCoreSystemInterface();
#endif

  bool icu_result = icu_util::Initialize();
  CHECK(icu_result);

  logging::OldFileDeletionState file_state =
      logging::APPEND_TO_OLD_LOG_FILE;
  if (process_type.empty()) {
    file_state = logging::DELETE_OLD_LOG_FILE;
  }
  logging::InitChromeLogging(parsed_command_line, file_state);

#ifdef NDEBUG
  if (parsed_command_line.HasSwitch(switches::kSilentDumpOnDCHECK) &&
      parsed_command_line.HasSwitch(switches::kEnableDCHECK)) {
#if defined(OS_WIN)
    logging::SetLogReportHandler(ChromeAssert);
#endif
  }
#endif  // NDEBUG

  if (!process_type.empty())
    CommonSubprocessInit();

  startup_timer.Stop();  // End of Startup Time Measurement.

  MainFunctionParams main_params(parsed_command_line, sandbox_wrapper,
                                 &autorelease_pool);

  // TODO(port): turn on these main() functions as they've been de-winified.
  int rv = -1;
  if (process_type == switches::kRendererProcess) {
    rv = RendererMain(main_params);
  } else if (process_type == switches::kPluginProcess) {
#if defined(OS_WIN)
    rv = PluginMain(main_params);
#endif
  } else if (process_type == switches::kWorkerProcess) {
#if defined(OS_WIN)
    rv = WorkerMain(main_params);
#endif
  } else if (process_type.empty()) {
#if defined(OS_LINUX)
    // gtk_init() can change |argc| and |argv|, but nobody else uses them.
    gtk_init(&argc, const_cast<char***>(&argv));
    // Register GTK assertions to go through our logging system.
    g_log_set_handler(NULL,  // All logging domains.
                      static_cast<GLogLevelFlags>(G_LOG_FLAG_RECURSION |
                                                  G_LOG_FLAG_FATAL |
                                                  G_LOG_LEVEL_ERROR |
                                                  G_LOG_LEVEL_CRITICAL |
                                                  G_LOG_LEVEL_WARNING),
                      GtkFatalLogHandler,
                      NULL);
#endif

    ScopedOleInitializer ole_initializer;
    rv = BrowserMain(main_params);
  } else {
    NOTREACHED() << "Unknown process type";
  }

  if (!process_type.empty()) {
    ResourceBundle::CleanupSharedInstance();
  }

#if defined(OS_WIN)
#ifdef _CRTDBG_MAP_ALLOC
  _CrtDumpMemoryLeaks();
#endif  // _CRTDBG_MAP_ALLOC

  _Module.Term();
#endif

  logging::CleanupChromeLogging();

  return rv;
}
<|endoftext|>


<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2015, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "TerminalWidget.h"

#include <QProcessEnvironment>
#include <QDebug>
#include <QApplication>
#include <QScrollBar>

TerminalWidget::TerminalWidget(QWidget *parent, QString dir) : QTextEdit(parent){
  //Setup the text widget
  this->setLineWrapMode(QTextEdit::WidgetWidth);
  //this->setReadOnly(true); //the key event catch will do the process/widget forwarding
  //this->setPlainText("WARNING: This utility is still incomplete and does not function properly yet");

  //Create/open the TTY port
  PROC = new TTYProcess(this);
  qDebug() << "Open new TTY";
  //int fd;
  bool ok = PROC->startTTY( QProcessEnvironment::systemEnvironment().value("SHELL","/bin/sh") );
  qDebug() << " - opened:" << ok;
  this->setEnabled(PROC->isOpen());

  //Connect the signals/slots
  connect(PROC, SIGNAL(readyRead()), this, SLOT(UpdateText()) );
  connect(PROC, SIGNAL(processClosed()), this, SLOT(ShellClosed()) );

}

TerminalWidget::~TerminalWidget(){
  aboutToClose();
}

void TerminalWidget::aboutToClose(){
  if(PROC->isOpen()){ PROC->closeTTY(); } //TTY PORT
}

// ==================
//          PRIVATE
// ==================
void TerminalWidget::applyData(QByteArray data){
  //Quick global replacement (this widget reads both as newlines)
  data = data.replace("\r\n","\n");
  //Iterate through the data and apply it when possible
  for(int i=0; i<data.size(); i++){
    if( data.at(i)=='\b' ){
      //Simple cursor backward 1 (NOT backspace in this context!!)
      //this->textCursor().deletePreviousChar();
      this->moveCursor(QTextCursor::Left, QTextCursor::MoveAnchor);
    }else if( data.at(i)=='\x1B' ){
      //ANSI Control Code start
      //Look for the end of the code
      int end = -1;
      for(int j=1; j<(data.size()-i) && end<0; j++){
        if(QChar(data.at(i+j)).isLetter()){ end = j; }
      }
      if(end<0){ return; } //skip everything else - no end to code found
      applyANSI(data.mid(i+1, end));
      i+=end; //move the final loop along - already handled these bytes

    }else{
      //Special Check: if inserting text within a line, clear the rest of this line first
      if(i==0 && this->textCursor().position() < this->document()->characterCount()-1){
        applyANSI("[K");
      }
      //Plaintext character - just add it here
      this->insertPlainText( QChar(data.at(i)) );
    }

  } //end loop over data
}

void TerminalWidget::applyANSI(QByteArray code){
  //Note: the first byte is often the "[" character
  //qDebug() << "Handle ANSI:" << code;
  //CURSOR MOVEMENT
  if( code.endsWith("A") ){ //Move Up
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::Up, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("B")){ //Move Down
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("C")){ //Move Forward
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    for(int i=0; i<num; i++){ this->moveCursor(QTextCursor::Right, QTextCursor::MoveAnchor); }
    //this->textCursor().movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("D")){ //Move Back
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    for(int i=0; i<num; i++){ this->moveCursor(QTextCursor::Left, QTextCursor::MoveAnchor); }
    //this->textCursor().movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("E")){ //Move Next/down Lines (go to beginning)
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::NextRow, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("F")){ //Move Previous/up Lines (go to beginning)
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::PreviousRow, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("G")){ //Move to specific column
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().setPosition(num);
  }else if(code.endsWith("H") || code.endsWith("f") ){ //Move to specific position (row/column)
    int mid = code.indexOf(";");
    if(mid>0){
      int numR, numC; numR = numC = 1;
      if(mid >=3){ numR = code.mid(1,mid-1).toInt(); }
      if(mid < code.size()-1){ numC = code.mid(mid+1,code.size()-mid-1).toInt(); }
      //this->textCursor().setPosition(
      qDebug() << "Set Text Position (absolute):" << "Row:" << numR << "Col:" << numC;
      // TO-DO
    }

   // DISPLAY CLEAR CODES
  }else if(code.endsWith("J")){ //ED - Erase Display

  }else if(code.endsWith("K")){ //EL - Erase in Line
    int num = 0;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    qDebug() << "Erase Number" << num;
    //Now determine what should be cleared based on code
    if(num==1){

    }else if(num==2){

    }else{
      //Clear from current cursor to end of line
      for(int i=this->textCursor().position(); i<this->document()->characterCount()+1; i++){
      //while(this->document()->characterAt(this->textCursor().position())!=QChar('\n') && this->textCursor().position() < this->document()->characterCount()){
	if(this->document()->characterAt(this->textCursor().position())=='\n'){ break; }
        this->textCursor().deleteChar();
      }
    }
  }
}

//Outgoing Data parsing
void TerminalWidget::sendKeyPress(int key){
  QByteArray ba;
  //Check for special keys
  switch(key){
    case Qt::Key_Delete:
	ba.append("\x7F");
        break;
    case Qt::Key_Backspace:
	ba.append("\x08");
        break;
    case Qt::Key_Left:
	ba.append("\x1b[D");
        break;
    case Qt::Key_Right:
	ba.append("\x1b[C");
        break;
    case Qt::Key_Up:
        ba.append("\x1b[A");
        break;
    case Qt::Key_Down:
        ba.append("\x1b[B");
        break;
  }

  //qDebug() << "Forward Input:" << txt << ev->key() << ba;
  if(!ba.isEmpty()){ PROC->writeTTY(ba); }
}

// ==================
//    PRIVATE SLOTS
// ==================
void TerminalWidget::UpdateText(){
  //read the data from the process
  //qDebug() << "UpdateText";
  if(!PROC->isOpen()){ return; }
  applyData(PROC->readTTY());
  //adjust the scrollbar as needed
  this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum());
}

void TerminalWidget::ShellClosed(){
  emit ProcessClosed(this->whatsThis());
}

// ==================
//       PROTECTED
// ==================
void TerminalWidget::keyPressEvent(QKeyEvent *ev){

  if(ev->text().isEmpty() || ev->text()=="\b" ){
    sendKeyPress(ev->key());
  }else{
    QByteArray ba; ba.append(ev->text()); //avoid any byte conversions
    PROC->writeTTY(ba);
  }

  ev->ignore();
}

void TerminalWidget::mousePressEvent(QMouseEvent *ev){
  this->setFocus();
  Q_UNUSED(ev);
}

void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *ev){
  Q_UNUSED(ev);
}

void TerminalWidget::contextMenuEvent(QContextMenuEvent *ev){
  Q_UNUSED(ev);
}

void TerminalWidget::resizeEvent(QResizeEvent *ev){
  if(!PROC->isOpen()){ return; }
  QSize pix = ev->size(); //pixels
  QSize chars;
    chars.setWidth( pix.width()/this->fontMetrics().width("W") );
    chars.setHeight( pix.height()/this->fontMetrics().lineSpacing() );

  PROC->setTerminalSize(chars,pix);
  QTextEdit::resizeEvent(ev);
}
<commit_msg>Finish getting the special keys handled in lumina-terminal. Now the terminal is completely functional - I just have other special ANSI codes (colors for particular text) to implement still (but this is just for appearance-sake).<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2015, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "TerminalWidget.h"

#include <QProcessEnvironment>
#include <QDebug>
#include <QApplication>
#include <QScrollBar>

TerminalWidget::TerminalWidget(QWidget *parent, QString dir) : QTextEdit(parent){
  //Setup the text widget
  this->setLineWrapMode(QTextEdit::WidgetWidth);
  //this->setReadOnly(true); //the key event catch will do the process/widget forwarding
  //this->setPlainText("WARNING: This utility is still incomplete and does not function properly yet");

  //Create/open the TTY port
  PROC = new TTYProcess(this);
  qDebug() << "Open new TTY";
  //int fd;
  bool ok = PROC->startTTY( QProcessEnvironment::systemEnvironment().value("SHELL","/bin/sh") );
  qDebug() << " - opened:" << ok;
  this->setEnabled(PROC->isOpen());

  //Connect the signals/slots
  connect(PROC, SIGNAL(readyRead()), this, SLOT(UpdateText()) );
  connect(PROC, SIGNAL(processClosed()), this, SLOT(ShellClosed()) );

}

TerminalWidget::~TerminalWidget(){
  aboutToClose();
}

void TerminalWidget::aboutToClose(){
  if(PROC->isOpen()){ PROC->closeTTY(); } //TTY PORT
}

// ==================
//          PRIVATE
// ==================
void TerminalWidget::applyData(QByteArray data){
  //Quick global replacement (this widget reads both as newlines)
  data = data.replace("\r\n","\n");
  //Iterate through the data and apply it when possible
  for(int i=0; i<data.size(); i++){
    if( data.at(i)=='\b' ){
      //Simple cursor backward 1 (NOT backspace in this context!!)
      //this->textCursor().deletePreviousChar();
      this->moveCursor(QTextCursor::Left, QTextCursor::MoveAnchor);
    }else if( data.at(i)=='\x1B' ){
      //ANSI Control Code start
      //Look for the end of the code
      int end = -1;
      for(int j=1; j<(data.size()-i) && end<0; j++){
        if(QChar(data.at(i+j)).isLetter()){ end = j; }
      }
      if(end<0){ return; } //skip everything else - no end to code found
      applyANSI(data.mid(i+1, end));
      i+=end; //move the final loop along - already handled these bytes

    }else{
      //Special Check: if inserting text within a line, clear the rest of this line first
      if(i==0 && this->textCursor().position() < this->document()->characterCount()-1){
        applyANSI("[K");
      }
      //Plaintext character - just add it here
      this->insertPlainText( QChar(data.at(i)) );
    }

  } //end loop over data
}

void TerminalWidget::applyANSI(QByteArray code){
  //Note: the first byte is often the "[" character
  //qDebug() << "Handle ANSI:" << code;
  //CURSOR MOVEMENT
  if( code.endsWith("A") ){ //Move Up
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::Up, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("B")){ //Move Down
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("C")){ //Move Forward
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    for(int i=0; i<num; i++){ this->moveCursor(QTextCursor::Right, QTextCursor::MoveAnchor); }
    //this->textCursor().movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("D")){ //Move Back
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    for(int i=0; i<num; i++){ this->moveCursor(QTextCursor::Left, QTextCursor::MoveAnchor); }
    //this->textCursor().movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("E")){ //Move Next/down Lines (go to beginning)
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::NextRow, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("F")){ //Move Previous/up Lines (go to beginning)
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().movePosition(QTextCursor::PreviousRow, QTextCursor::MoveAnchor, num);
  }else if(code.endsWith("G")){ //Move to specific column
    int num = 1;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    this->textCursor().setPosition(num);
  }else if(code.endsWith("H") || code.endsWith("f") ){ //Move to specific position (row/column)
    int mid = code.indexOf(";");
    if(mid>0){
      int numR, numC; numR = numC = 1;
      if(mid >=3){ numR = code.mid(1,mid-1).toInt(); }
      if(mid < code.size()-1){ numC = code.mid(mid+1,code.size()-mid-1).toInt(); }
      //this->textCursor().setPosition(
      qDebug() << "Set Text Position (absolute):" << "Row:" << numR << "Col:" << numC;
      // TO-DO
    }

   // DISPLAY CLEAR CODES
  }else if(code.endsWith("J")){ //ED - Erase Display

  }else if(code.endsWith("K")){ //EL - Erase in Line
    int num = 0;
    if(code.size()>2){ num = code.mid(1, code.size()-2).toInt(); } //everything in the middle
    qDebug() << "Erase Number" << num;
    //Now determine what should be cleared based on code
    if(num==1){
      //Clear from current cursor to beginning of line
      for(int i=this->textCursor().position(); i>=0; i--){
	if(this->document()->characterAt(this->textCursor().position())=='\n'){ break; }
        this->textCursor().deleteChar();
      }
    }else if(num==2){
      //Clear the entire line
      //  rewind the starting point to the beginning of the line
      int start = this->document()->find("\n", this->textCursor().position(), QTextDocument::FindBackward).position();
      for(int i=start+1; i<this->document()->characterCount()+1; i++){
	if(this->document()->characterAt(this->textCursor().position())=='\n'){ break; }
        this->textCursor().deleteChar();
      }
    }else{
      //Clear from current cursor to end of line
      for(int i=this->textCursor().position(); i<this->document()->characterCount()+1; i++){
	if(this->document()->characterAt(this->textCursor().position())=='\n'){ break; }
        this->textCursor().deleteChar();
      }
    }
  }
}

//Outgoing Data parsing
void TerminalWidget::sendKeyPress(int key){
  QByteArray ba;
  //Check for special keys
  switch(key){
    case Qt::Key_Delete:
	ba.append("\x7F");
        break;
    case Qt::Key_Backspace:
	ba.append("\x08");
        break;
    case Qt::Key_Left:
	ba.append("\x1b[D");
        break;
    case Qt::Key_Right:
	ba.append("\x1b[C");
        break;
    case Qt::Key_Up:
        ba.append("\x1b[A");
        break;
    case Qt::Key_Down:
        ba.append("\x1b[B");
        break;
  }

  //qDebug() << "Forward Input:" << txt << ev->key() << ba;
  if(!ba.isEmpty()){ PROC->writeTTY(ba); }
}

// ==================
//    PRIVATE SLOTS
// ==================
void TerminalWidget::UpdateText(){
  //read the data from the process
  //qDebug() << "UpdateText";
  if(!PROC->isOpen()){ return; }
  applyData(PROC->readTTY());
  //adjust the scrollbar as needed
  this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum());
}

void TerminalWidget::ShellClosed(){
  emit ProcessClosed(this->whatsThis());
}

// ==================
//       PROTECTED
// ==================
void TerminalWidget::keyPressEvent(QKeyEvent *ev){

  if(ev->text().isEmpty() || ev->text()=="\b" ){
    sendKeyPress(ev->key());
  }else{
    QByteArray ba; ba.append(ev->text()); //avoid any byte conversions
    PROC->writeTTY(ba);
  }

  ev->ignore();
}

void TerminalWidget::mousePressEvent(QMouseEvent *ev){
  this->setFocus();
  Q_UNUSED(ev);
}

void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *ev){
  Q_UNUSED(ev);
}

void TerminalWidget::contextMenuEvent(QContextMenuEvent *ev){
  Q_UNUSED(ev);
}

void TerminalWidget::resizeEvent(QResizeEvent *ev){
  if(!PROC->isOpen()){ return; }
  QSize pix = ev->size(); //pixels
  QSize chars;
    chars.setWidth( pix.width()/this->fontMetrics().width("W") );
    chars.setHeight( pix.height()/this->fontMetrics().lineSpacing() );

  PROC->setTerminalSize(chars,pix);
  QTextEdit::resizeEvent(ev);
}
<|endoftext|>


<commit_before><commit_msg>Eliminate memory leak due to circular shared_ptr<commit_after><|endoftext|>


<commit_before><commit_msg>More VS fixes (huehue)<commit_after><|endoftext|>


<commit_before>
//Implementations of the AST objects
//Much of the logic of creating these comes from bison grammar

#include "node.h"

void Node::describe() {
	printf("Found generic node object with no fields\n");
}

void Expression::describe() {
	printf("Found generic Expression object with no fields\n");
}

void Statement::describe() {
	printf("Found generic statement object with no fields\n");
}

Integer::Integer(int64_t value) {
	this->value = value;
}

void Integer::describe() {
	printf("Found Literal Integer: %i\n", (int)value);
}

Float::Float(double value) {
	this->value = value;
}

void Float::describe() {
	printf("Found Float: %f\n", value);
}

Identifier::Identifier(char* name) {
	size_t length = strlen(name);
	this->name = (char*)GC_MALLOC(length+1);
	memcpy(this->name,name,length);
	//It's good practice to keep our own copy
}

void Identifier::describe() {
	printf("Found Identifier: %s\n",name);
}

NullaryOperator::NullaryOperator(int64_t op) {
	this->op = op;
}

void NullaryOperator::describe() {
	printf("Found Nullary Operator\n");
}

UnaryOperator::UnaryOperator(int64_t op, Expression* exp) {
	this->op = op;
	this->exp = exp;
}

void UnaryOperator::describe() {
	printf("Found Unary Operator\n");
}

BinaryOperator::BinaryOperator(Expression* left, int64_t op, Expression* right) {
	this->op = op;
	this->left = left;
	this->right = right;
}

void BinaryOperator::describe() {
	printf("Found Binary Operator %d\n",(int)this->op);
}

Assignment::Assignment(Identifier* left, Expression* right) {
	this->left = left;
	this->right = right;
}

void Assignment::describe() {
	printf("Found Assignment: %s\n",left->name);
}

Block::Block(vector<Statement*, gc_allocator<Statement*>>* statements) {
	this->statements = statements;
}

void Block::describe() {
	printf("Found Block\n");
}

Block::Block() {
	this->statements = NULL;
}

FunctionCall::FunctionCall(Identifier* ident, vector<Expression*, gc_allocator<Expression*>>* args) {
	this->ident = ident;
	this->args = args;
}

void FunctionCall::describe() {
	printf("Found Function Call: %s\n",ident->name);
}

Keyword::Keyword(char* name) {
	size_t length = strlen(name);
	this->name = (char*)GC_MALLOC(length+1);
	memcpy(this->name,name,length);
}

void Keyword::describe() {
	printf("Found Keyword: %s\n",name);
}

VariableDefinition::VariableDefinition(Keyword* type, Identifier* ident, Expression* exp) {
	this->type = type;
	this->ident = ident;
	this->exp = exp;
}

void VariableDefinition::describe() {
	printf("Found Variable Declaration: type='%s' identifier='%s'\n",type->name,
		ident->name);
}

FunctionDefinition::FunctionDefinition(Keyword* type, Identifier* ident, vector<VariableDefinition*, gc_allocator<VariableDefinition*>>* args,
	 Block* block) {
	this->type = type;
	this->ident = ident;
	this->args = args;
	this->block = block;
}

void FunctionDefinition::describe() {
	printf("Found Function Definition: %s\n",ident->name);
}

ExpressionStatement::ExpressionStatement(Expression* exp) {
	this->exp = exp;
}

void ExpressionStatement::describe() {
	printf("Expression(s) converted into statements\n");
}

ReturnStatement::ReturnStatement(Expression* exp) {
	this->exp = exp;
}

void ReturnStatement::describe() {
	if (exp) {
	  printf("Found return statement with expression\n");
	} else {
	  printf("Found return statement, statement returns void\n");
	}
}

AssignStatement::AssignStatement(Expression* target,Expression* valxp) {
	this->target = target;
	this->valxp = valxp;
}

void AssignStatement::describe() {
	printf("Found Assignment Statement\n");
}

StructureDefinition::StructureDefinition(Identifier* ident,Block* block) {
	this->ident = ident;
	this->block = block;
}

void StructureDefinition::describe() {
	printf("Found Structure Definition: %s\n",ident->name);
}

StructureDeclaration::StructureDeclaration(Identifier* type,Identifier* ident) {
	this->type = type;
	this->ident = ident;
}

void StructureDeclaration::describe() {
	printf("Found Structure Declaration: type='%s' identifier='%s'\n",
		type->name,ident->name);
}

<commit_msg>Changes to output messages, use GC_MALLOC_ATMOC<commit_after>
//Implementations of the AST objects
//Much of the logic of creating these comes from bison grammar

#include "node.h"

void Node::describe() {
	printf("---Found generic node object with no fields.");
	printf("---This SHOULD BE AN ERROR.");
}

void Expression::describe() {
	printf("---Found generic Expression object with no fields\n");
}

void Statement::describe() {
	printf("---Found generic statement object with no fields\n");
}

Integer::Integer(int64_t value) {
	this->value = value;
}

void Integer::describe() {
	printf("---Found Literal Integer: %i\n", (int)value);
}

Float::Float(double value) {
	this->value = value;
}

void Float::describe() {
	printf("---Found Float: %f\n", value);
}

Identifier::Identifier(char* name) {
	size_t length = strlen(name);
	this->name = (char*)GC_MALLOC_ATOMIC(length+1);
	memcpy(this->name,name,length);
	//Its good practice to keep our own copy
}

void Identifier::describe() {
	printf("---Found Identifier: %s\n",name);
}

NullaryOperator::NullaryOperator(int64_t op) {
	this->op = op;
}

void NullaryOperator::describe() {
	printf("---Found Nullary Operator\n");
}

UnaryOperator::UnaryOperator(int64_t op, Expression* exp) {
	this->op = op;
	this->exp = exp;
}

void UnaryOperator::describe() {
	printf("---Found Unary Operator\n");
}

BinaryOperator::BinaryOperator(Expression* left, int64_t op, Expression* right) {
	this->op = op;
	this->left = left;
	this->right = right;
}

void BinaryOperator::describe() {
	printf("---Found Binary Operator %d\n",(int)this->op);
}

Assignment::Assignment(Identifier* left, Expression* right) {
	this->left = left;
	this->right = right;
}

void Assignment::describe() {
	printf("---Found Assignment: %s\n",left->name);
}

Block::Block(vector<Statement*, gc_allocator<Statement*>>* statements) {
	this->statements = statements;
}

void Block::describe() {
	printf("---Found Block\n");
}

Block::Block() {
	this->statements = NULL;
}

FunctionCall::FunctionCall(Identifier* ident, vector<Expression*, gc_allocator<Expression*>>* args) {
	this->ident = ident;
	this->args = args;
}

void FunctionCall::describe() {
	printf("---Found Function Call: %s\n",ident->name);
}

Keyword::Keyword(char* name) {
	size_t length = strlen(name);
	this->name = (char*)GC_MALLOC_ATOMIC(length+1);
	memcpy(this->name,name,length);
}

void Keyword::describe() {
	printf("---Found Keyword: %s\n",name);
}

VariableDefinition::VariableDefinition(Keyword* type, Identifier* ident, Expression* exp) {
	this->type = type;
	this->ident = ident;
	this->exp = exp;
}

void VariableDefinition::describe() {
	printf("---Found Variable Declaration: type='%s' identifier='%s'\n",
		type->name,ident->name);
}

FunctionDefinition::FunctionDefinition(Keyword* type, Identifier* ident,
	 vector<VariableDefinition*, gc_allocator<VariableDefinition*>>* args,
	 Block* block) {
	this->type = type;
	this->ident = ident;
	this->args = args;
	this->block = block;
}

void FunctionDefinition::describe() {
	printf("---Found Function Definition: %s\n",ident->name);
}

ExpressionStatement::ExpressionStatement(Expression* exp) {
	this->exp = exp;
}

void ExpressionStatement::describe() {
	printf("---Expression(s) converted into statements\n");
}

ReturnStatement::ReturnStatement(Expression* exp) {
	this->exp = exp;
}

void ReturnStatement::describe() {
	if (exp) {
	  printf("---Found return statement with expression\n");
	} else {
	  printf("---Found return statement, statement returns void\n");
	}
}

AssignStatement::AssignStatement(Expression* target,Expression* valxp) {
	this->target = target;
	this->valxp = valxp;
}

void AssignStatement::describe() {
	printf("---Found Assignment Statement\n");
}

StructureDefinition::StructureDefinition(Identifier* ident,Block* block) {
	this->ident = ident;
	this->block = block;
}

void StructureDefinition::describe() {
	printf("---Found Structure Definition: %s\n",ident->name);
}

StructureDeclaration::StructureDeclaration(Identifier* type,Identifier* ident) {
	this->type = type;
	this->ident = ident;
}

void StructureDeclaration::describe() {
	printf("---Found Structure Declaration: type='%s' identifier='%s'\n",
		type->name,ident->name);
}

<|endoftext|>


<commit_before>#include "BaseCorrespondenceFilter.hpp"

namespace registration {

BaseCorrespondenceFilter::BaseCorrespondenceFilter()
{
    //ctor
}

BaseCorrespondenceFilter::~BaseCorrespondenceFilter()
{
    //dtor
}

void BaseCorrespondenceFilter::set_output(FeatureMat * const ioCorrespondingFeatures,
                                    VecDynFloat * const ioCorrespondingFlags)
{
    _ioCorrespondingFeatures = ioCorrespondingFeatures;
    _ioCorrespondingFlags = ioCorrespondingFlags;

}//end set_output

void BaseCorrespondenceFilter::_affinity_to_correspondences(){
    /*
    # GOAL
    This function computes all the corresponding features and flags,
    when the affinity for a set of features and flags is given.

    # PARAMETERS
    -_flagRoundingLimit:
    Flags are binary. Anything over this double is rounded up, whereas anything
    under it is rounded down. A suggested cut-off is 0.9, which means that if
    an element flagged zero contributes 10 percent or to the affinity, the
    corresponding element should be flagged a zero as well.

    # RESULT
    -outCorrespondingFeatures
    -outCorrespondingFlags
    */

    //# Simple computation of corresponding features and flags
    *_ioCorrespondingFeatures = _affinity * (*_inTargetFeatures);
    *_ioCorrespondingFlags = _affinity * (*_inTargetFlags);

    //# Flag correction.
    //## Flags are binary. We will round them down if lower than the flag
    //## rounding limit (see explanation in parameter description).
    if (_flagThreshold >= 1.0f) {std::cerr << "corresponding flag threshold equals " << _flagThreshold << " but has to be between 0.0 and 1.0!" <<std::endl;}
    for (size_t i = 0 ; i < _numFloatingElements ; i++) {
        if ((*_ioCorrespondingFlags)[i] > _flagThreshold){
            (*_ioCorrespondingFlags)[i] = 1.0;
        }
        else {
            (*_ioCorrespondingFlags)[i] = 0.0;
        }
    }
}

}//namespace registration
<commit_msg>Floating and corresponding flags are always merged now, also for non-symmetric correspondences.<commit_after>#include "BaseCorrespondenceFilter.hpp"

namespace registration {

BaseCorrespondenceFilter::BaseCorrespondenceFilter()
{
    //ctor
}

BaseCorrespondenceFilter::~BaseCorrespondenceFilter()
{
    //dtor
}

void BaseCorrespondenceFilter::set_output(FeatureMat * const ioCorrespondingFeatures,
                                    VecDynFloat * const ioCorrespondingFlags)
{
    _ioCorrespondingFeatures = ioCorrespondingFeatures;
    _ioCorrespondingFlags = ioCorrespondingFlags;

}//end set_output

void BaseCorrespondenceFilter::_affinity_to_correspondences(){
    /*
    # GOAL
    This function computes all the corresponding features and flags,
    when the affinity for a set of features and flags is given.

    # PARAMETERS
    -_flagRoundingLimit:
    Flags are binary. Anything over this double is rounded up, whereas anything
    under it is rounded down. A suggested cut-off is 0.9, which means that if
    an element flagged zero contributes 10 percent or to the affinity, the
    corresponding element should be flagged a zero as well.

    # RESULT
    -outCorrespondingFeatures
    -outCorrespondingFlags
    */

    //# Simple computation of corresponding features and flags
    *_ioCorrespondingFeatures = _affinity * (*_inTargetFeatures);
    *_ioCorrespondingFlags = _affinity * (*_inTargetFlags);

    //# Flag correction.
    //## Flags are binary. We will round them down if lower than the flag
    //## rounding limit (see explanation in parameter description).
    if (_flagThreshold >= 1.0f) {std::cerr << "corresponding flag threshold equals " << _flagThreshold << " but has to be between 0.0 and 1.0!" <<std::endl;}
    for (size_t i = 0 ; i < _numFloatingElements ; i++) {
        if ((*_ioCorrespondingFlags)[i] > _flagThreshold){
            (*_ioCorrespondingFlags)[i] = 1.0;
        }
        else {
            (*_ioCorrespondingFlags)[i] = 0.0;
        }
    }

    //# Merge corresponding and floating flags
    (*_ioCorrespondingFlags) = (*_ioCorrespondingFlags).cwiseProduct(*_inFloatingFlags);
}

}//namespace registration
<|endoftext|>


<commit_before>/** @package TBTKTools
 *  @file main.cpp
 *  @brief Estimates the DOS using random smapling of LDOS.
 *
 *  Reads model from text file and estimates the DOS using the
 *  ChebyshevSolver.
 *
 *  Takes filename of file to parse as first argument.
 *
 *  @author Kristofer Björsnon
 */

#include "Model.h"
#include "FileParser.h"
#include "ChebyshevSolver.h"
#include "CPropertyExtractor.h"
#include "DOS.h"
#include "FileWriter.h"
#include "Util.h"
#include "GPUResourceManager.h"
#include "Streams.h"

#include <complex>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <getopt.h>

using namespace std;
using namespace TBTK;

const complex<double> i(0, 1);
int main(int argc, char **argv){
	Util::Streams::openLog();
	int isVerbose		= false;
	int forceGPU		= false;
	int forceCPU		= false;
	int numSamples		= 100;
	int scaleFactor		= 20;
	int numCoefficients	= 5000;
	int energyResolution	= 10000;

	while(true){
		static struct option long_options[] = {
			//Sets flags.
			{"verbose",		no_argument,		&isVerbose,	1},
			{"use-gpu",		no_argument,		&forceGPU,	1},
			{"use-cpu",		no_argument,		&forceCPU,	1},
			//Does not set flags.
			{"scale-factor",	required_argument,	0,		's'},
			{"coefficients",	required_argument,	0,		'c'},
			{"energy-resolution",	required_argument,	0,		'r'},
			{"samples",		required_argument,	0,		'S'},
			{0,			0,			0,		0}
		};

		int option_index = 0;
		int c = getopt_long(argc, argv, "s:c:r:S:", long_options, &option_index);
		if(c == -1)
			break;

		switch(c){
		case 0:
			//If the option sets a flag, do nothing.
			if(long_options[option_index].flag != 0)
				break;
			cout << "option " << long_options[option_index].name;
			if(optarg)
				cout << " with argument " << optarg;
			cout << "\n";
			break;
		case 's':
			scaleFactor = atof(optarg);
			break;
		case 'c':
			numCoefficients = atoi(optarg);
			break;
		case 'r':
			energyResolution = atoi(optarg);
			break;
		case 'S':
			numSamples = atoi(optarg);
			break;
		default:
			cout << "Error: Unknown argument.\n";
			exit(1);
		}
	}

	//Supress output if not verbose
	if(!isVerbose){
		Util::Streams::setStdMuteOut();
		Util::Streams::setStdMuteErr();
	}

	//Get input file name
	if(argc != optind+1){
		cout << "Input file missing.\n";
		exit(1);
	}
	string fileName = argv[optind];

	//Use GPU if devices
	bool useGPU;
	if(GPUResourceManager::getInstance().getNumDevices() > 0)
		useGPU = true;
	else
		useGPU = false;

	if(forceGPU && forceCPU){
		Util::Streams::err << "Error: --use-cpu and --use-gpu cannot be simultaneously specified.\n";
		exit(1);
	}
	if(forceGPU)
		useGPU = true;
	if(forceCPU)
		useGPU = false;

	//Parse model from file and setup output target
	Model *model = FileParser::readModel(fileName);
	model->constructCOO();

	FileWriter::setFileName("TBTKResults.h5");

	//Setup ChebyshevSolver and corresponding PropertyExtractor
	ChebyshevSolver cSolver;
	cSolver.setModel(model);
	cSolver.setScaleFactor(scaleFactor);

	CPropertyExtractor pe(
		&cSolver,
		numCoefficients,
		energyResolution,
		useGPU,
		false,
		true,
		-scaleFactor,
		scaleFactor
	);

	//Initialize randomization and dos
	srand(time(NULL));
	double *dosData = new double[energyResolution];
	for(int n = 0; n < energyResolution; n++)
		dosData[n] = 0.;

	//Main loop: Repeatedly calculate LDOS for random sites
	for(int n = 0; n < numSamples; n++){
		//Print progress
		cout << "." << flush;
		if(n%10 == 9)
			cout << " ";
		if(n%50 == 49)
			cout << "\n";

		//Get new random index
		int b = rand()%model->getBasisSize();
		Index index = model->getAmplitudeSet()->tree.getPhysicalIndex(b);

		//Calculate LDOS
		Property::LDOS *ldos = pe.calculateLDOS(
			index,
			index.getUnitRange()
		);

		//Add calculated LDOS to total DOS
		const double *data = ldos->getData();
		for(int e = 0; e < energyResolution; e++)
			dosData[e] += data[e]/(double)numSamples;

		//Free memory
		delete ldos;

	}
	cout << "\n";

	//Write DOS to file
	Property::DOS dos(-scaleFactor, scaleFactor, energyResolution, dosData);
	FileWriter::writeDOS(&dos);

	delete [] dosData;

	Util::Streams::closeLog();
	return 0;
}
<commit_msg>Updated EstimateDOS to use TBTKAssert and TBTKExit<commit_after>/** @package TBTKTools
 *  @file main.cpp
 *  @brief Estimates the DOS using random smapling of LDOS.
 *
 *  Reads model from text file and estimates the DOS using the
 *  ChebyshevSolver.
 *
 *  Takes filename of file to parse as first argument.
 *
 *  @author Kristofer Björsnon
 */

#include "Model.h"
#include "FileParser.h"
#include "ChebyshevSolver.h"
#include "CPropertyExtractor.h"
#include "DOS.h"
#include "FileWriter.h"
#include "Util.h"
#include "GPUResourceManager.h"
#include "Streams.h"

#include <complex>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <getopt.h>

using namespace std;
using namespace TBTK;

const complex<double> i(0, 1);
int main(int argc, char **argv){
	Util::Streams::openLog();
	int isVerbose		= false;
	int forceGPU		= false;
	int forceCPU		= false;
	int numSamples		= 100;
	int scaleFactor		= 20;
	int numCoefficients	= 5000;
	int energyResolution	= 10000;

	while(true){
		static struct option long_options[] = {
			//Sets flags.
			{"verbose",		no_argument,		&isVerbose,	1},
			{"use-gpu",		no_argument,		&forceGPU,	1},
			{"use-cpu",		no_argument,		&forceCPU,	1},
			//Does not set flags.
			{"scale-factor",	required_argument,	0,		's'},
			{"coefficients",	required_argument,	0,		'c'},
			{"energy-resolution",	required_argument,	0,		'r'},
			{"samples",		required_argument,	0,		'S'},
			{0,			0,			0,		0}
		};

		int option_index = 0;
		int c = getopt_long(argc, argv, "s:c:r:S:", long_options, &option_index);
		if(c == -1)
			break;

		switch(c){
		case 0:
			//If the option sets a flag, do nothing.
			if(long_options[option_index].flag != 0)
				break;
			cout << "option " << long_options[option_index].name;
			if(optarg)
				cout << " with argument " << optarg;
			cout << "\n";
			break;
		case 's':
			scaleFactor = atof(optarg);
			break;
		case 'c':
			numCoefficients = atoi(optarg);
			break;
		case 'r':
			energyResolution = atoi(optarg);
			break;
		case 'S':
			numSamples = atoi(optarg);
			break;
		default:
			TBTKExit(
				"EstimateDOS",
				"Unknown argument.",
				""
			);
		}
	}

	//Supress output if not verbose
	if(!isVerbose)
		Util::Streams::setStdMuteOut();

	//Get input file name
	TBTKAssert(
		argc == optind+1,
		"EstimateDOS",
		"Input file missing.",
		""
	);
	string fileName = argv[optind];

	//Use GPU if devices
	bool useGPU;
	if(GPUResourceManager::getInstance().getNumDevices() > 0)
		useGPU = true;
	else
		useGPU = false;

	TBTKAssert(
		!(forceGPU && forceCPU),
		"EstimateDOS",
		"--use-cpu and --use-gpu cannot be simultaneously specified.",
		""
	);
	if(forceGPU)
		useGPU = true;
	if(forceCPU)
		useGPU = false;

	//Parse model from file and setup output target
	Model *model = FileParser::readModel(fileName);
	model->constructCOO();

	FileWriter::setFileName("TBTKResults.h5");

	//Setup ChebyshevSolver and corresponding PropertyExtractor
	ChebyshevSolver cSolver;
	cSolver.setModel(model);
	cSolver.setScaleFactor(scaleFactor);

	CPropertyExtractor pe(
		&cSolver,
		numCoefficients,
		energyResolution,
		useGPU,
		false,
		true,
		-scaleFactor,
		scaleFactor
	);

	//Initialize randomization and dos
	srand(time(NULL));
	double *dosData = new double[energyResolution];
	for(int n = 0; n < energyResolution; n++)
		dosData[n] = 0.;

	//Main loop: Repeatedly calculate LDOS for random sites
	for(int n = 0; n < numSamples; n++){
		//Print progress
		cout << "." << flush;
		if(n%10 == 9)
			cout << " ";
		if(n%50 == 49)
			cout << "\n";

		//Get new random index
		int b = rand()%model->getBasisSize();
		Index index = model->getAmplitudeSet()->tree.getPhysicalIndex(b);

		//Calculate LDOS
		Property::LDOS *ldos = pe.calculateLDOS(
			index,
			index.getUnitRange()
		);

		//Add calculated LDOS to total DOS
		const double *data = ldos->getData();
		for(int e = 0; e < energyResolution; e++)
			dosData[e] += data[e]/(double)numSamples;

		//Free memory
		delete ldos;

	}
	cout << "\n";

	//Write DOS to file
	Property::DOS dos(-scaleFactor, scaleFactor, energyResolution, dosData);
	FileWriter::writeDOS(&dos);

	delete [] dosData;

	Util::Streams::closeLog();
	return 0;
}
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::type_void_adapter

namespace abc {

/*! DOC:3395 Move constructors and exceptions

In this section, “move constructor” will strictly refer to class::class(class &&).

All classes must provide move constructors and assignment operators if the copy constructor would
result in execution of exception-prone code (e.g. resource allocation).

Because move constructors are employed widely in container classes that need to provide strong
exception guarantee (fully transacted operation) even in case of moves, move constructors must not
throw exceptions. This requirement is relaxed for moves that involve two different classes, since
these will not be used by container classes.
*/

//! Encapsulates raw constructors, destructors and assignment operators for a type.
struct type_void_adapter {
public:
   /*! Prototype of a function that copies items from one array to another.

   @param pDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param pSrcBegin
      Pointer to the first item to copy.
   @param pSrcEnd
      Pointer to beyond the last item to copy.
   */
   typedef void (* copy_fn)(void * pDstBegin, void const * pSrcBegin, void const * pSrcEnd);

   /*! Prototype of a function that destructs a range of items in an array.

   @param pBegin
      Pointer to the first item to destruct.
   @param pEnd
      Pointer to beyond the last item to destruct.
   */
   typedef void (* destr_fn)(void const * pBegin, void const * pEnd);

   /*! Prototype of a function that compares two values for equality.

   @param p1
      Pointer to the first item.
   @param p2
      Pointer to the second item.
   @return
      true if the items are equal, or false otherwise.
   */
   typedef bool (* equal_fn)(void const * p1, void const * p2);

   /*! Prototype of a function that moves items from one array to another.

   @param pDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param pSrcBegin
      Pointer to the first item to move.
   @param pSrcEnd
      Pointer to beyond the last item to move.
   */
   typedef void (* move_fn)(void * pDstBegin, void * pSrcBegin, void * pSrcEnd);

public:
   //! Size of a variable of this type, in bytes.
   std::size_t cb;
   //! Function to copy items from one array to another.
   copy_fn copy_constr;
   //! Function to destruct items in an array.
   destr_fn destruct;
   //! Function to compare two items for equality.
   equal_fn equal;
   //! Function to move items from one array to another.
   move_fn move_constr;

public:
   //! Constructor.
   type_void_adapter() :
      cb(0),
      copy_constr(nullptr),
      destruct(nullptr),
      equal(nullptr),
      move_constr(nullptr) {
   }

   //! Initializes this->copy_constr.
   template <typename T>
   void set_copy_fn() {
      copy_constr = reinterpret_cast<copy_fn>(_typed_copy_constr<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!copy_constr) {
         _typed_copy_constr<typename std::remove_cv<T>::type>(nullptr, nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->destruct.
   template <typename T>
   void set_destr_fn() {
      destruct = reinterpret_cast<destr_fn>(_typed_destruct<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!destruct) {
         _typed_destruct<typename std::remove_cv<T>::type>(nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->equal.
   template <typename T>
   void set_equal_fn() {
      equal = reinterpret_cast<equal_fn>(_typed_equal<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!equal) {
         _typed_equal<typename std::remove_cv<T>::type>(nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->move_constr.
   template <typename T>
   void set_move_fn() {
      move_constr = reinterpret_cast<move_fn>(_typed_move_constr<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!move_constr) {
         _typed_move_constr<typename std::remove_cv<T>::type>(nullptr, nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->cb.
   template <typename T>
   void set_size() {
      cb = sizeof(T);
   }

private:
   /*! Copies a range of items from one array to another, overwriting any existing contents in the
   destination.

   @param ptDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param ptSrcBegin
      Pointer to the first item to copy.
   @param ptSrcEnd
      Pointer to beyond the last item to copy.
   */
#if ABC_HOST_MSC
   /* MSC applies SFINAE too late, and when asked to get the address of the *one and only* valid
   version of _typed_copy_constr() (see non-MSC code in the #else branch), it will raise an error
   saying it doesn’t know which one to choose. */
   template <typename T>
   static void _typed_copy_constr(T * ptDstBegin, T const * ptSrcBegin, T const * ptSrcEnd) {
      if (std::has_trivial_copy_constructor<T>::value) {
         // No constructor, fastest copy possible.
         memory::copy(ptDstBegin, ptSrcBegin, static_cast<std::size_t>(ptSrcEnd - ptSrcBegin));
      } else {
         // Assume that since it’s not trivial, it can throw exceptions, so perform a transactional
         // copy.
         T * ptDst = ptDstBegin;
         try {
            for (T const * ptSrc = ptSrcBegin; ptSrc < ptSrcEnd; ++ptSrc, ++ptDst) {
               ::new(ptDst) T(*ptSrc);
            }
         } catch (...) {
            // Undo (destruct) all the copies instantiated.
            while (--ptDst >= ptDstBegin) {
               ptDst->~T();
            }
            throw;
         }
      }
   }
#else //if ABC_HOST_MSC
   // Only enabled if the copy constructor is trivial.
   template <typename T>
   static void _typed_copy_constr(
      typename std::enable_if<std::has_trivial_copy_constructor<T>::value, T *>::type ptDstBegin,
      T const * ptSrcBegin, T const * ptSrcEnd
   ) {
      // No constructor, fastest copy possible.
      memory::copy(ptDstBegin, ptSrcBegin, static_cast<std::size_t>(ptSrcEnd - ptSrcBegin));
   }
   // Only enabled if the copy constructor is not trivial.
   template <typename T>
   static void _typed_copy_constr(
      typename std::enable_if<!std::has_trivial_copy_constructor<T>::value, T *>::type ptDstBegin,
      T const * ptSrcBegin, T const * ptSrcEnd
   ) {
      // Assume that since it’s not trivial, it can throw exceptions, so perform a transactional
      // copy.
      T * ptDst = ptDstBegin;
      try {
         for (T const * ptSrc = ptSrcBegin; ptSrc < ptSrcEnd; ++ptSrc, ++ptDst) {
            ::new(ptDst) T(*ptSrc);
         }
      } catch (...) {
         // Undo (destruct) all the copies instantiated.
         while (--ptDst >= ptDstBegin) {
            ptDst->~T();
         }
         throw;
      }
   }
#endif //if ABC_HOST_MSC … else

   /*! Destructs a range of items in an array.

   @param ptBegin
      Pointer to the first item to destruct.
   @param ptEnd
      Pointer to beyond the last item to destruct.
   */
   template <typename T>
   static void _typed_destruct(T const * ptBegin, T const * ptEnd) {
#ifdef ABC_CXX_STL_CXX11_TYPE_TRAITS
      if (!std::is_trivially_destructible<T>::value) {
#else
      if (!std::has_trivial_destructor<T>::value) {
#endif
         // The destructor is not a no-op.
         for (T const * pt = ptBegin; pt < ptEnd; ++pt) {
            pt->~T();
         }
      }
   }

   /*! Compares two values for equality.

   @param pt1
      Pointer to the first item.
   @param pt2
      Pointer to the second item.
   @return
      true if the items are equal, or false otherwise.
   */
   template <typename T>
   static bool _typed_equal(T const * pt1, T const * pt2) {
      return *pt1 == *pt2;
   }

   /*! Moves a range of items from one array to another, overwriting any existing contents in the
   destination.

   @param ptDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param ptSrcBegin
      Pointer to the first item to copy.
   @param ptSrcEnd
      Pointer to beyond the last item to copy.
   */
   template <typename T>
   static void _typed_move_constr(T * ptDstBegin, T * ptSrcBegin, T * ptSrcEnd) {
      for (T * ptSrc = ptSrcBegin, * ptDst = ptDstBegin; ptSrc < ptSrcEnd; ++ptSrc, ++ptDst) {
         ::new(ptDst) T(std::move(*ptSrc));
      }
   }
};

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Support C++11 type traits in more places<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error "Please #include <abaclade.hxx> instead of this file"
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::type_void_adapter

namespace abc {

/*! DOC:3395 Move constructors and exceptions

In this section, “move constructor” will strictly refer to class::class(class &&).

All classes must provide move constructors and assignment operators if the copy constructor would
result in execution of exception-prone code (e.g. resource allocation).

Because move constructors are employed widely in container classes that need to provide strong
exception guarantee (fully transacted operation) even in case of moves, move constructors must not
throw exceptions. This requirement is relaxed for moves that involve two different classes, since
these will not be used by container classes.
*/

//! Encapsulates raw constructors, destructors and assignment operators for a type.
struct type_void_adapter {
public:
   /*! Prototype of a function that copies items from one array to another.

   @param pDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param pSrcBegin
      Pointer to the first item to copy.
   @param pSrcEnd
      Pointer to beyond the last item to copy.
   */
   typedef void (* copy_fn)(void * pDstBegin, void const * pSrcBegin, void const * pSrcEnd);

   /*! Prototype of a function that destructs a range of items in an array.

   @param pBegin
      Pointer to the first item to destruct.
   @param pEnd
      Pointer to beyond the last item to destruct.
   */
   typedef void (* destr_fn)(void const * pBegin, void const * pEnd);

   /*! Prototype of a function that compares two values for equality.

   @param p1
      Pointer to the first item.
   @param p2
      Pointer to the second item.
   @return
      true if the items are equal, or false otherwise.
   */
   typedef bool (* equal_fn)(void const * p1, void const * p2);

   /*! Prototype of a function that moves items from one array to another.

   @param pDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param pSrcBegin
      Pointer to the first item to move.
   @param pSrcEnd
      Pointer to beyond the last item to move.
   */
   typedef void (* move_fn)(void * pDstBegin, void * pSrcBegin, void * pSrcEnd);

public:
   //! Size of a variable of this type, in bytes.
   std::size_t cb;
   //! Function to copy items from one array to another.
   copy_fn copy_constr;
   //! Function to destruct items in an array.
   destr_fn destruct;
   //! Function to compare two items for equality.
   equal_fn equal;
   //! Function to move items from one array to another.
   move_fn move_constr;

public:
   //! Constructor.
   type_void_adapter() :
      cb(0),
      copy_constr(nullptr),
      destruct(nullptr),
      equal(nullptr),
      move_constr(nullptr) {
   }

   //! Initializes this->copy_constr.
   template <typename T>
   void set_copy_fn() {
      copy_constr = reinterpret_cast<copy_fn>(_typed_copy_constr<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!copy_constr) {
         _typed_copy_constr<typename std::remove_cv<T>::type>(nullptr, nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->destruct.
   template <typename T>
   void set_destr_fn() {
      destruct = reinterpret_cast<destr_fn>(_typed_destruct<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!destruct) {
         _typed_destruct<typename std::remove_cv<T>::type>(nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->equal.
   template <typename T>
   void set_equal_fn() {
      equal = reinterpret_cast<equal_fn>(_typed_equal<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!equal) {
         _typed_equal<typename std::remove_cv<T>::type>(nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->move_constr.
   template <typename T>
   void set_move_fn() {
      move_constr = reinterpret_cast<move_fn>(_typed_move_constr<typename std::remove_cv<T>::type>);
#if ABC_HOST_GCC && ABC_HOST_GCC < 40700
      // Force instantiating the template, even if (obviously) never executed.
      if (!move_constr) {
         _typed_move_constr<typename std::remove_cv<T>::type>(nullptr, nullptr, nullptr);
      }
#endif
   }

   //! Initializes this->cb.
   template <typename T>
   void set_size() {
      cb = sizeof(T);
   }

private:
   /*! Copies a range of items from one array to another, overwriting any existing contents in the
   destination.

   @param ptDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param ptSrcBegin
      Pointer to the first item to copy.
   @param ptSrcEnd
      Pointer to beyond the last item to copy.
   */
#if ABC_HOST_MSC
   /* MSC applies SFINAE too late, and when asked to get the address of the *one and only* valid
   version of _typed_copy_constr() (see non-MSC code in the #else branch), it will raise an error
   saying it doesn’t know which one to choose. */
   template <typename T>
   static void _typed_copy_constr(T * ptDstBegin, T const * ptSrcBegin, T const * ptSrcEnd) {
      if (std::has_trivial_copy_constructor<T>::value) {
         // No constructor, fastest copy possible.
         memory::copy(ptDstBegin, ptSrcBegin, static_cast<std::size_t>(ptSrcEnd - ptSrcBegin));
      } else {
         // Assume that since it’s not trivial, it can throw exceptions, so perform a transactional
         // copy.
         T * ptDst = ptDstBegin;
         try {
            for (T const * ptSrc = ptSrcBegin; ptSrc < ptSrcEnd; ++ptSrc, ++ptDst) {
               ::new(ptDst) T(*ptSrc);
            }
         } catch (...) {
            // Undo (destruct) all the copies instantiated.
            while (--ptDst >= ptDstBegin) {
               ptDst->~T();
            }
            throw;
         }
      }
   }
#else //if ABC_HOST_MSC
   // Only enabled if the copy constructor is trivial.
   template <typename T>
   static void _typed_copy_constr(
      typename std::enable_if<
#ifdef ABC_CXX_STL_CXX11_TYPE_TRAITS
         std::is_trivially_copy_constructible<T>::value,
#else
         std::has_trivial_copy_constructor<T>::value,
#endif
      T *>::type ptDstBegin, T const * ptSrcBegin, T const * ptSrcEnd
   ) {
      // No constructor, fastest copy possible.
      memory::copy(ptDstBegin, ptSrcBegin, static_cast<std::size_t>(ptSrcEnd - ptSrcBegin));
   }
   // Only enabled if the copy constructor is not trivial.
   template <typename T>
   static void _typed_copy_constr(
      typename std::enable_if<
#ifdef ABC_CXX_STL_CXX11_TYPE_TRAITS
         !std::is_trivially_copy_constructible<T>::value,
#else
         !std::has_trivial_copy_constructor<T>::value,
#endif
      T * >::type ptDstBegin, T const * ptSrcBegin, T const * ptSrcEnd
   ) {
      // Assume that since it’s not trivial, it can throw exceptions, so perform a transactional
      // copy.
      T * ptDst = ptDstBegin;
      try {
         for (T const * ptSrc = ptSrcBegin; ptSrc < ptSrcEnd; ++ptSrc, ++ptDst) {
            ::new(ptDst) T(*ptSrc);
         }
      } catch (...) {
         // Undo (destruct) all the copies instantiated.
         while (--ptDst >= ptDstBegin) {
            ptDst->~T();
         }
         throw;
      }
   }
#endif //if ABC_HOST_MSC … else

   /*! Destructs a range of items in an array.

   @param ptBegin
      Pointer to the first item to destruct.
   @param ptEnd
      Pointer to beyond the last item to destruct.
   */
   template <typename T>
   static void _typed_destruct(T const * ptBegin, T const * ptEnd) {
#ifdef ABC_CXX_STL_CXX11_TYPE_TRAITS
      if (!std::is_trivially_destructible<T>::value) {
#else
      if (!std::has_trivial_destructor<T>::value) {
#endif
         // The destructor is not a no-op.
         for (T const * pt = ptBegin; pt < ptEnd; ++pt) {
            pt->~T();
         }
      }
   }

   /*! Compares two values for equality.

   @param pt1
      Pointer to the first item.
   @param pt2
      Pointer to the second item.
   @return
      true if the items are equal, or false otherwise.
   */
   template <typename T>
   static bool _typed_equal(T const * pt1, T const * pt2) {
      return *pt1 == *pt2;
   }

   /*! Moves a range of items from one array to another, overwriting any existing contents in the
   destination.

   @param ptDstBegin
      Pointer to the start of the destination array. The items are supposed to be uninitialized.
   @param ptSrcBegin
      Pointer to the first item to copy.
   @param ptSrcEnd
      Pointer to beyond the last item to copy.
   */
   template <typename T>
   static void _typed_move_constr(T * ptDstBegin, T * ptSrcBegin, T * ptSrcEnd) {
      for (T * ptSrc = ptSrcBegin, * ptDst = ptDstBegin; ptSrc < ptSrcEnd; ++ptSrc, ++ptDst) {
         ::new(ptDst) T(std::move(*ptSrc));
      }
   }
};

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include <sstream>

#include <pcl/features/fpfh.h>
#include <pcl/io/pcd_io.h>
#include <pcl/keypoints/uniform_sampling.h>
#include <pcl/common/time.h>

#include "proctor/detector.h"
#include "proctor/proctor.h"
#include "proctor/proposer.h"
#include "proctor/registration_proposer.h"
#include "proctor/detector_visualizer.h"

namespace pcl {
  namespace proctor {
    /** create the viewports to be used by top candidates */
    class create_viewports {
    public:
      create_viewports(PointCloud<PointNormal>::ConstPtr sentinel) : sentinel(sentinel) {}
      void operator()(visualization::PCLVisualizer &v) {
        for (int ci = 0; ci < Detector::num_registration; ci++) {
          int vp;
          v.createViewPort(double(ci) / Detector::num_registration, 0, double(ci + 1) / Detector::num_registration, 1, vp);
          {
            stringstream ss;
            ss << "candidate_" << ci;
            v.addPointCloud(sentinel, visualization::PointCloudColorHandlerCustom<PointNormal>(sentinel, 0xc0, 0x00, 0x40), ss.str(), vp);
          }
          {
            stringstream ss;
            ss << "aligned_" << ci;
            v.addPointCloud(sentinel, visualization::PointCloudColorHandlerCustom<PointNormal>(sentinel, 0xc0, 0x00, 0x40), ss.str(), vp);
          }
        }
      }
    private:
      PointCloud<PointNormal>::ConstPtr sentinel;
    };

    /** show a candidate model as the specified candidate */
    class show_candidate {
    public:
      show_candidate(int ci, PointCloud<PointNormal>::ConstPtr candidate) : ci(ci), candidate(candidate) {}
      void operator()(visualization::PCLVisualizer &v) {
        {
          stringstream ss;
          ss << "candidate_" << ci;
          v.updatePointCloud(candidate, visualization::PointCloudColorHandlerCustom<PointNormal>(candidate, 0xc0, 0x00, 0x40), ss.str());
        }
        {
          stringstream ss;
          ss << "aligned_" << ci;
          v.updatePointCloud(candidate, visualization::PointCloudColorHandlerCustom<PointNormal>(candidate, 0xc0, 0x00, 0x40), ss.str());
        }
      }
    private:
      int ci;
      PointCloud<PointNormal>::ConstPtr candidate;
    };

    /** show an aligned point cloud in the specified viewport */
    class show_aligned {
    public:
      show_aligned(int ci, PointCloud<PointNormal>::ConstPtr aligned) : ci(ci), aligned(aligned) {}
      void operator()(visualization::PCLVisualizer &v) {
        stringstream ss;
        ss << "aligned_" << ci;
        v.updatePointCloud(aligned, visualization::PointCloudColorHandlerCustom<PointNormal>(aligned, 0xff, 0xff, 0xff), ss.str());
      }
    private:
      int ci;
      PointCloud<PointNormal>::ConstPtr aligned;
    };

    class visualization_callback {
    public:
      visualization_callback(int ci, visualization::CloudViewer *vis) : ci(ci), vis(vis) {}
      void operator()(const PointCloud<PointNormal> &cloud_src,
                      const vector<int> &indices_src,
                      const PointCloud<PointNormal> &cloud_tgt,
                      const vector<int> &indices_tgt) {
        // make a copy of the cloud. expensive.
        PointCloud<PointNormal>::ConstPtr aligned (new PointCloud<PointNormal>(cloud_src));
        vis->runOnVisualizationThreadOnce(show_aligned(ci, aligned));
      }
    private:
      int ci;
      visualization::CloudViewer *vis;
    };

    /** Detector */
    const double Detector::keypoint_separation = 0.1;
    const int Detector::max_votes = 100;
    const int Detector::num_registration = 4;

    /* Trains a single model */
    void Detector::train(Scene &scene) {
      srand(0);
      if (detector_vis_) {
        detector_vis_->addCloud(scene.id, scene.cloud);
      }

      IndicesPtr keypoints = computeKeypoints(scene.cloud);
      PointCloud<Detector::Signature>::Ptr features = obtainFeatures(scene, keypoints, false);

      Entry e;
      e.cloud = scene.cloud;
      e.indices = keypoints;
      e.features = features;
      e.tree = KdTree<Signature>::Ptr(new KdTreeFLANN<Signature>());
      e.tree->setInputCloud(e.features);

      (*database_)[scene.id] = e;
    }

    std::string Detector::query(Scene &scene, float *classifier, double *registration) {
      cout << "detector testing " << scene.id << endl;

      Entry e;
      e.cloud = scene.cloud;
      timer.start();
      e.indices = computeKeypoints(e.cloud);
      timer.stop(KEYPOINTS_TESTING);
      timer.start();
      e.features = obtainFeatures(scene, e.indices, true);
      timer.stop(COMPUTE_FEATURES_TESTING);

      memset(classifier, 0, Config::num_models * sizeof(*classifier));
      clock_t totalTime = 0;
      float time = 0;

      StopWatch s;

      std::vector<std::string> all_ids;
      for (std::map<std::string, Entry>::iterator db_it = database_->begin(); db_it != database_->end(); db_it++)
      {
        all_ids.push_back((*db_it).first);
      }

      std::vector<std::string> proposed;
      proposer_->setDatabase(database_);
      proposer_->getProposed(num_registration, e, all_ids, proposed);

      RegistrationProposer reg_proposer;
      std::vector<std::string> picked;
      reg_proposer.setDatabase(database_);
      reg_proposer.getProposed(1, e, proposed, picked);

      return picked[0];
    }

    void Detector::enableVisualization(DetectorVisualizer *vis) {
      detector_vis_ = vis;
    }

    void Detector::printTimer() {
      printf(
        "select training keypoints: %10.3f sec\n"
        "obtain training features:  %10.3f sec\n"
        "build feature tree:        %10.3f sec\n"
        "select testing keypoints:  %10.3f sec\n"
        "compute testing features:  %10.3f sec\n"
        "voting classifier:         %10.3f sec\n"
        "initial alignment:         %10.3f sec\n"
        "ICP:                       %10.3f sec\n",
        timer[KEYPOINTS_TRAINING],
        timer[OBTAIN_FEATURES_TRAINING],
        timer[BUILD_TREE],
        timer[KEYPOINTS_TESTING],
        timer[COMPUTE_FEATURES_TESTING],
        timer[VOTING_CLASSIFIER],
        timer[IA_RANSAC],
        timer[ICP]
      );
    }

    IndicesPtr Detector::computeKeypoints(PointCloud<PointNormal>::Ptr cloud) {
      IndicesPtr indices (new vector<int>());
      PointCloud<int> leaves;
      UniformSampling<PointNormal> us;
      us.setRadiusSearch(keypoint_separation);
      us.setInputCloud(cloud);
      us.compute(leaves);
      indices->assign(leaves.points.begin(), leaves.points.end()); // can't use operator=, probably because of different allocators

      return indices;
    }

    PointCloud<Detector::Signature>::Ptr Detector::computeFeatures(PointCloud<PointNormal>::Ptr cloud, IndicesPtr indices) {
      cout << "computing features on " << indices->size() << " points" << endl;
      PointCloud<Signature>::Ptr features (new PointCloud<Signature>());
      FPFHEstimation<PointNormal, PointNormal, Signature> fpfh;
      fpfh.setRadiusSearch(0.1);
      fpfh.setInputCloud(cloud);
      fpfh.setIndices(indices);
      search::KdTree<PointNormal>::Ptr kdt (new search::KdTree<PointNormal>());
      fpfh.setSearchMethod(kdt);
      fpfh.setInputNormals(cloud);
      fpfh.compute(*features);
      if (features->points.size() != indices->size())
        cout << "got " << features->points.size() << " features from " << indices->size() << " points" << endl;
      return features;
    }

    // TODO Enum for is_test_phase
    PointCloud<Detector::Signature>::Ptr Detector::obtainFeatures(Scene &scene, IndicesPtr indices, bool is_test_phase, bool cache) {
      if (cache == false)
      {
        PointCloud<Signature>::Ptr features = computeFeatures(scene.cloud, indices);
        return features;
      }
      else
      {
        std::string name_str = std::string("feature_") + scene.id;

        if (is_test_phase) {
          name_str += "_test";
        }
        else {
          name_str += "_train";
        }

        name_str += ".pcd";

        const char *name = name_str.c_str();

        if (ifstream(name)) {
          PointCloud<Signature>::Ptr features (new PointCloud<Signature>());
          io::loadPCDFile(name, *features);
          //if (features->points.size() != indices->size())
          //cout << "got " << features->points.size() << " features from " << indices->size() << " points" << endl;
          return features;
        } else {
          PointCloud<Signature>::Ptr features = computeFeatures(scene.cloud, indices);
          io::savePCDFileBinary(name, *features);
          return features;
        }
      }
    }
  }
}
<commit_msg>Remove old visualization code.<commit_after>#include <sstream>

#include <pcl/features/fpfh.h>
#include <pcl/io/pcd_io.h>
#include <pcl/keypoints/uniform_sampling.h>
#include <pcl/common/time.h>

#include "proctor/detector.h"
#include "proctor/proctor.h"
#include "proctor/proposer.h"
#include "proctor/registration_proposer.h"
#include "proctor/detector_visualizer.h"

namespace pcl {
  namespace proctor {
    /** Detector */
    const double Detector::keypoint_separation = 0.1;
    const int Detector::max_votes = 100;
    const int Detector::num_registration = 4;

    /* Trains a single model */
    void Detector::train(Scene &scene) {
      srand(0);
      if (detector_vis_) {
        detector_vis_->addCloud(scene.id, scene.cloud);
      }

      IndicesPtr keypoints = computeKeypoints(scene.cloud);
      PointCloud<Detector::Signature>::Ptr features = obtainFeatures(scene, keypoints, false);

      Entry e;
      e.cloud = scene.cloud;
      e.indices = keypoints;
      e.features = features;
      e.tree = KdTree<Signature>::Ptr(new KdTreeFLANN<Signature>());
      e.tree->setInputCloud(e.features);

      (*database_)[scene.id] = e;
    }

    std::string Detector::query(Scene &scene, float *classifier, double *registration) {
      cout << "detector testing " << scene.id << endl;

      Entry e;
      e.cloud = scene.cloud;
      timer.start();
      e.indices = computeKeypoints(e.cloud);
      timer.stop(KEYPOINTS_TESTING);
      timer.start();
      e.features = obtainFeatures(scene, e.indices, true);
      timer.stop(COMPUTE_FEATURES_TESTING);

      memset(classifier, 0, Config::num_models * sizeof(*classifier));
      clock_t totalTime = 0;
      float time = 0;

      StopWatch s;

      std::vector<std::string> all_ids;
      for (std::map<std::string, Entry>::iterator db_it = database_->begin(); db_it != database_->end(); db_it++)
      {
        all_ids.push_back((*db_it).first);
      }

      std::vector<std::string> proposed;
      proposer_->setDatabase(database_);
      proposer_->getProposed(num_registration, e, all_ids, proposed);

      RegistrationProposer reg_proposer;
      std::vector<std::string> picked;
      reg_proposer.setDatabase(database_);
      reg_proposer.getProposed(1, e, proposed, picked);

      return picked[0];
    }

    void Detector::enableVisualization(DetectorVisualizer *vis) {
      detector_vis_ = vis;
    }

    void Detector::printTimer() {
      printf(
        "select training keypoints: %10.3f sec\n"
        "obtain training features:  %10.3f sec\n"
        "build feature tree:        %10.3f sec\n"
        "select testing keypoints:  %10.3f sec\n"
        "compute testing features:  %10.3f sec\n"
        "voting classifier:         %10.3f sec\n"
        "initial alignment:         %10.3f sec\n"
        "ICP:                       %10.3f sec\n",
        timer[KEYPOINTS_TRAINING],
        timer[OBTAIN_FEATURES_TRAINING],
        timer[BUILD_TREE],
        timer[KEYPOINTS_TESTING],
        timer[COMPUTE_FEATURES_TESTING],
        timer[VOTING_CLASSIFIER],
        timer[IA_RANSAC],
        timer[ICP]
      );
    }

    IndicesPtr Detector::computeKeypoints(PointCloud<PointNormal>::Ptr cloud) {
      IndicesPtr indices (new vector<int>());
      PointCloud<int> leaves;
      UniformSampling<PointNormal> us;
      us.setRadiusSearch(keypoint_separation);
      us.setInputCloud(cloud);
      us.compute(leaves);
      indices->assign(leaves.points.begin(), leaves.points.end()); // can't use operator=, probably because of different allocators

      return indices;
    }

    PointCloud<Detector::Signature>::Ptr Detector::computeFeatures(PointCloud<PointNormal>::Ptr cloud, IndicesPtr indices) {
      cout << "computing features on " << indices->size() << " points" << endl;
      PointCloud<Signature>::Ptr features (new PointCloud<Signature>());
      FPFHEstimation<PointNormal, PointNormal, Signature> fpfh;
      fpfh.setRadiusSearch(0.1);
      fpfh.setInputCloud(cloud);
      fpfh.setIndices(indices);
      search::KdTree<PointNormal>::Ptr kdt (new search::KdTree<PointNormal>());
      fpfh.setSearchMethod(kdt);
      fpfh.setInputNormals(cloud);
      fpfh.compute(*features);
      if (features->points.size() != indices->size())
        cout << "got " << features->points.size() << " features from " << indices->size() << " points" << endl;
      return features;
    }

    // TODO Enum for is_test_phase
    PointCloud<Detector::Signature>::Ptr Detector::obtainFeatures(Scene &scene, IndicesPtr indices, bool is_test_phase, bool cache) {
      if (cache == false)
      {
        PointCloud<Signature>::Ptr features = computeFeatures(scene.cloud, indices);
        return features;
      }
      else
      {
        std::string name_str = std::string("feature_") + scene.id;

        if (is_test_phase) {
          name_str += "_test";
        }
        else {
          name_str += "_train";
        }

        name_str += ".pcd";

        const char *name = name_str.c_str();

        if (ifstream(name)) {
          PointCloud<Signature>::Ptr features (new PointCloud<Signature>());
          io::loadPCDFile(name, *features);
          //if (features->points.size() != indices->size())
          //cout << "got " << features->points.size() << " features from " << indices->size() << " points" << endl;
          return features;
        } else {
          PointCloud<Signature>::Ptr features = computeFeatures(scene.cloud, indices);
          io::savePCDFileBinary(name, *features);
          return features;
        }
      }
    }
  }
}
<|endoftext|>