<commit_before>// Copyright (c) 2010 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.

#include "webkit/glue/plugins/plugin_list.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
#include "net/base/mime_util.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_switches.h"
#include "webkit/glue/webkit_glue.h"

namespace NPAPI {

base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED);

// static
PluginList* PluginList::Singleton() {
  return g_singleton.Pointer();
}

// static
bool PluginList::DebugPluginLoading() {
  return CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDebugPluginLoading);
}

bool PluginList::PluginsLoaded() {
  AutoLock lock(lock_);
  return plugins_loaded_;
}

void PluginList::RefreshPlugins() {
  AutoLock lock(lock_);
  plugins_need_refresh_ = true;
}

void PluginList::AddExtraPluginPath(const FilePath& plugin_path) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_paths_.push_back(plugin_path);
#endif
}

void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
  AutoLock lock(lock_);
  std::vector<FilePath>::iterator it =
      std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
                plugin_path);
  if (it != extra_plugin_paths_.end())
    extra_plugin_paths_.erase(it);
}

void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_dirs_.push_back(plugin_dir);
#endif
}

void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) {
  AutoLock lock(lock_);
  internal_plugins_.push_back(info);
}

void PluginList::UnregisterInternalPlugin(const FilePath& path) {
  AutoLock lock(lock_);
  for (size_t i = 0; i < internal_plugins_.size(); i++) {
    if (internal_plugins_[i].path == path) {
      internal_plugins_.erase(internal_plugins_.begin() + i);
      return;
    }
  }
  NOTREACHED();
}

bool PluginList::ReadPluginInfo(const FilePath& filename,
                                WebPluginInfo* info,
                                const PluginEntryPoints** entry_points) {
  {
    AutoLock lock(lock_);
    for (size_t i = 0; i < internal_plugins_.size(); ++i) {
      if (filename == internal_plugins_[i].path) {
        *entry_points = &internal_plugins_[i].entry_points;
        return CreateWebPluginInfo(internal_plugins_[i], info);
      }
    }
  }

  // Not an internal plugin.
  *entry_points = NULL;

  return PluginLib::ReadWebPluginInfo(filename, info);
}

bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
                                     WebPluginInfo* info) {
  std::vector<std::string> mime_types, file_extensions;
  std::vector<string16> descriptions;
  SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types);
  SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions);
  SplitString(WideToUTF16(pvi.type_descriptions), '|', &descriptions);

  info->mime_types.clear();

  if (mime_types.empty()) {
    LOG_IF(ERROR, PluginList::DebugPluginLoading())
        << "Plugin " << pvi.product_name << " has no MIME types, skipping";
    return false;
  }

  info->name = WideToUTF16(pvi.product_name);
  info->desc = WideToUTF16(pvi.file_description);
  info->version = WideToUTF16(pvi.file_version);
  info->path = pvi.path;
  info->enabled = true;

  for (size_t i = 0; i < mime_types.size(); ++i) {
    WebPluginMimeType mime_type;
    mime_type.mime_type = StringToLowerASCII(mime_types[i]);
    if (file_extensions.size() > i)
      SplitString(file_extensions[i], ',', &mime_type.file_extensions);

    if (descriptions.size() > i) {
      mime_type.description = descriptions[i];

      // On Windows, the description likely has a list of file extensions
      // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension
      // list from the description if it is present.
      size_t ext = mime_type.description.find(ASCIIToUTF16("(*"));
      if (ext != string16::npos) {
        if (ext > 1 && mime_type.description[ext -1] == ' ')
          ext--;

        mime_type.description.erase(ext);
      }
    }

    info->mime_types.push_back(mime_type);
  }

  return true;
}

PluginList::PluginList()
    : plugins_loaded_(false), plugins_need_refresh_(false) {
  PlatformInit();
}

void PluginList::LoadPlugins(bool refresh) {
  // Don't want to hold the lock while loading new plugins, so we don't block
  // other methods if they're called on other threads.
  std::vector<FilePath> extra_plugin_paths;
  std::vector<FilePath> extra_plugin_dirs;
  std::vector<PluginVersionInfo> internal_plugins;
  {
    AutoLock lock(lock_);
    if (plugins_loaded_ && !refresh && !plugins_need_refresh_)
      return;

    // Clear the refresh bit now, because it might get set again before we
    // reach the end of the method.
    plugins_need_refresh_ = false;
    extra_plugin_paths = extra_plugin_paths_;
    extra_plugin_dirs = extra_plugin_dirs_;
    internal_plugins = internal_plugins_;
  }

  base::TimeTicks start_time = base::TimeTicks::Now();

  std::vector<WebPluginInfo> new_plugins;
  std::set<FilePath> visited_plugins;

  std::vector<FilePath> directories_to_scan;
  GetPluginDirectories(&directories_to_scan);

  // Load internal plugins first so that, if both an internal plugin and a
  // "discovered" plugin want to handle the same type, the internal plugin
  // will have precedence.
  for (size_t i = 0; i < internal_plugins.size(); ++i) {
    if (internal_plugins[i].path.value() == kDefaultPluginLibraryName)
      continue;
    LoadPlugin(internal_plugins[i].path, &new_plugins);
  }

  for (size_t i = 0; i < extra_plugin_paths.size(); ++i) {
    const FilePath& path = extra_plugin_paths[i];
    if (visited_plugins.find(path) != visited_plugins.end())
      continue;
    LoadPlugin(path, &new_plugins);
    visited_plugins.insert(path);
  }

  for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) {
    LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins, &visited_plugins);
  }

  for (size_t i = 0; i < directories_to_scan.size(); ++i) {
    LoadPluginsFromDir(directories_to_scan[i], &new_plugins, &visited_plugins);
  }

#if defined OS_WIN
  LoadPluginsFromRegistry(&new_plugins, &visited_plugins);
#endif

  // Load the default plugin last.
  if (webkit_glue::IsDefaultPluginEnabled())
    LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);

  base::TimeTicks end_time = base::TimeTicks::Now();
  base::TimeDelta elapsed = end_time - start_time;
  DLOG(INFO) << "Loaded plugin list in " << elapsed.InMilliseconds() << " ms.";

  // Only update the data now since loading plugins can take a while.
  AutoLock lock(lock_);

  // Go through and mark new plugins in the disabled list as, well, disabled.
  for (std::vector<WebPluginInfo>::iterator it = new_plugins.begin();
       it != new_plugins.end();
       ++it) {
    if (disabled_plugins_.find(it->path) != disabled_plugins_.end())
      it->enabled = false;
  }

  plugins_ = new_plugins;
  plugins_loaded_ = true;
}

void PluginList::LoadPlugin(const FilePath& path,
                            std::vector<WebPluginInfo>* plugins) {
  LOG_IF(ERROR, PluginList::DebugPluginLoading())
      << "Loading plugin " << path.value();

  WebPluginInfo plugin_info;
  const PluginEntryPoints* entry_points;

  if (!ReadPluginInfo(path, &plugin_info, &entry_points))
    return;

  if (!ShouldLoadPlugin(plugin_info, plugins))
    return;

  if (path.value() != kDefaultPluginLibraryName
#if defined(OS_WIN) && !defined(NDEBUG)
      && path.BaseName().value() != L"npspy.dll"  // Make an exception for NPSPY
#endif
      ) {
    for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
      // TODO: don't load global handlers for now.
      // WebKit hands to the Plugin before it tries
      // to handle mimeTypes on its own.
      const std::string &mime_type = plugin_info.mime_types[i].mime_type;
      if (mime_type == "*" )
        return;
    }
  }

  plugins->push_back(plugin_info);
}

bool PluginList::FindPlugin(const std::string& mime_type,
                            bool allow_wildcard,
                            WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindDisabledPlugin(const std::string& mime_type,
                                    bool allow_wildcard,
                                    WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (!plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindPlugin(const GURL &url,
                            std::string* actual_mime_type,
                            WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  std::string path = url.path();
  std::string::size_type last_dot = path.rfind('.');
  if (last_dot == std::string::npos)
    return false;

  std::string extension = StringToLowerASCII(std::string(path, last_dot+1));

  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsExtension(plugins_[i], extension, actual_mime_type)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::SupportsType(const WebPluginInfo& info,
                              const std::string &mime_type,
                              bool allow_wildcard) {
  // Webkit will ask for a plugin to handle empty mime types.
  if (mime_type.empty())
    return false;

  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_info = info.mime_types[i];
    if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
      if (!allow_wildcard && mime_info.mime_type == "*") {
        continue;
      }
      return true;
    }
  }
  return false;
}

bool PluginList::SupportsExtension(const WebPluginInfo& info,
                                   const std::string &extension,
                                   std::string* actual_mime_type) {
  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_type = info.mime_types[i];
    for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
      if (mime_type.file_extensions[j] == extension) {
        if (actual_mime_type)
          *actual_mime_type = mime_type.mime_type;
        return true;
      }
    }
  }

  return false;
}

void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  AutoLock lock(lock_);
  *plugins = plugins_;
}

void PluginList::GetEnabledPlugins(bool refresh,
                                   std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  plugins->clear();
  AutoLock lock(lock_);
  for (std::vector<WebPluginInfo>::const_iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->enabled)
      plugins->push_back(*it);
  }
}

bool PluginList::GetPluginInfo(const GURL& url,
                               const std::string& mime_type,
                               bool allow_wildcard,
                               WebPluginInfo* info,
                               std::string* actual_mime_type) {
  bool found = FindPlugin(mime_type, allow_wildcard, info);
  if (!found || (info->path.value() == kDefaultPluginLibraryName)) {
    if (FindPlugin(url, actual_mime_type, info) ||
        FindDisabledPlugin(mime_type, allow_wildcard, info)) {
      found = true;
    }
  }

  return found;
}

bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path,
                                     WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].path == plugin_path) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::EnablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_enable = false;

  std::set<FilePath>::iterator entry = disabled_plugins_.find(filename);
  if (entry == disabled_plugins_.end())
    return did_enable;  // Early exit if plugin not in disabled list.

  disabled_plugins_.erase(entry);  // Remove from disabled list.

  // Set enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(!it->enabled);  // Should have been disabled.
      it->enabled = true;
      did_enable = true;
    }
  }

  return did_enable;
}

bool PluginList::DisablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_disable = false;

  if (disabled_plugins_.find(filename) != disabled_plugins_.end())
    return did_disable;  // Early exit if plugin already in disabled list.

  disabled_plugins_.insert(filename);  // Add to disabled list.

  // Unset enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(it->enabled);  // Should have been enabled.
      it->enabled = false;
      did_disable = true;
    }
  }

  return did_disable;
}

void PluginList::Shutdown() {
  // TODO
}

}  // namespace NPAPI
<commit_msg>Reduce console DLOG(INFO) spam in plugin_list<commit_after>// Copyright (c) 2010 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.

#include "webkit/glue/plugins/plugin_list.h"

#include <algorithm>

#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "googleurl/src/gurl.h"
#include "net/base/mime_util.h"
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_lib.h"
#include "webkit/glue/plugins/plugin_switches.h"
#include "webkit/glue/webkit_glue.h"

namespace NPAPI {

base::LazyInstance<PluginList> g_singleton(base::LINKER_INITIALIZED);

// static
PluginList* PluginList::Singleton() {
  return g_singleton.Pointer();
}

// static
bool PluginList::DebugPluginLoading() {
  return CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDebugPluginLoading);
}

bool PluginList::PluginsLoaded() {
  AutoLock lock(lock_);
  return plugins_loaded_;
}

void PluginList::RefreshPlugins() {
  AutoLock lock(lock_);
  plugins_need_refresh_ = true;
}

void PluginList::AddExtraPluginPath(const FilePath& plugin_path) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_paths_.push_back(plugin_path);
#endif
}

void PluginList::RemoveExtraPluginPath(const FilePath& plugin_path) {
  AutoLock lock(lock_);
  std::vector<FilePath>::iterator it =
      std::find(extra_plugin_paths_.begin(), extra_plugin_paths_.end(),
                plugin_path);
  if (it != extra_plugin_paths_.end())
    extra_plugin_paths_.erase(it);
}

void PluginList::AddExtraPluginDir(const FilePath& plugin_dir) {
  // Chrome OS only loads plugins from /opt/google/chrome/plugins.
#if !defined(OS_CHROMEOS)
  AutoLock lock(lock_);
  extra_plugin_dirs_.push_back(plugin_dir);
#endif
}

void PluginList::RegisterInternalPlugin(const PluginVersionInfo& info) {
  AutoLock lock(lock_);
  internal_plugins_.push_back(info);
}

void PluginList::UnregisterInternalPlugin(const FilePath& path) {
  AutoLock lock(lock_);
  for (size_t i = 0; i < internal_plugins_.size(); i++) {
    if (internal_plugins_[i].path == path) {
      internal_plugins_.erase(internal_plugins_.begin() + i);
      return;
    }
  }
  NOTREACHED();
}

bool PluginList::ReadPluginInfo(const FilePath& filename,
                                WebPluginInfo* info,
                                const PluginEntryPoints** entry_points) {
  {
    AutoLock lock(lock_);
    for (size_t i = 0; i < internal_plugins_.size(); ++i) {
      if (filename == internal_plugins_[i].path) {
        *entry_points = &internal_plugins_[i].entry_points;
        return CreateWebPluginInfo(internal_plugins_[i], info);
      }
    }
  }

  // Not an internal plugin.
  *entry_points = NULL;

  return PluginLib::ReadWebPluginInfo(filename, info);
}

bool PluginList::CreateWebPluginInfo(const PluginVersionInfo& pvi,
                                     WebPluginInfo* info) {
  std::vector<std::string> mime_types, file_extensions;
  std::vector<string16> descriptions;
  SplitString(WideToUTF8(pvi.mime_types), '|', &mime_types);
  SplitString(WideToUTF8(pvi.file_extensions), '|', &file_extensions);
  SplitString(WideToUTF16(pvi.type_descriptions), '|', &descriptions);

  info->mime_types.clear();

  if (mime_types.empty()) {
    LOG_IF(ERROR, PluginList::DebugPluginLoading())
        << "Plugin " << pvi.product_name << " has no MIME types, skipping";
    return false;
  }

  info->name = WideToUTF16(pvi.product_name);
  info->desc = WideToUTF16(pvi.file_description);
  info->version = WideToUTF16(pvi.file_version);
  info->path = pvi.path;
  info->enabled = true;

  for (size_t i = 0; i < mime_types.size(); ++i) {
    WebPluginMimeType mime_type;
    mime_type.mime_type = StringToLowerASCII(mime_types[i]);
    if (file_extensions.size() > i)
      SplitString(file_extensions[i], ',', &mime_type.file_extensions);

    if (descriptions.size() > i) {
      mime_type.description = descriptions[i];

      // On Windows, the description likely has a list of file extensions
      // embedded in it (e.g. "SurfWriter file (*.swr)"). Remove an extension
      // list from the description if it is present.
      size_t ext = mime_type.description.find(ASCIIToUTF16("(*"));
      if (ext != string16::npos) {
        if (ext > 1 && mime_type.description[ext -1] == ' ')
          ext--;

        mime_type.description.erase(ext);
      }
    }

    info->mime_types.push_back(mime_type);
  }

  return true;
}

PluginList::PluginList()
    : plugins_loaded_(false), plugins_need_refresh_(false) {
  PlatformInit();
}

void PluginList::LoadPlugins(bool refresh) {
  // Don't want to hold the lock while loading new plugins, so we don't block
  // other methods if they're called on other threads.
  std::vector<FilePath> extra_plugin_paths;
  std::vector<FilePath> extra_plugin_dirs;
  std::vector<PluginVersionInfo> internal_plugins;
  {
    AutoLock lock(lock_);
    if (plugins_loaded_ && !refresh && !plugins_need_refresh_)
      return;

    // Clear the refresh bit now, because it might get set again before we
    // reach the end of the method.
    plugins_need_refresh_ = false;
    extra_plugin_paths = extra_plugin_paths_;
    extra_plugin_dirs = extra_plugin_dirs_;
    internal_plugins = internal_plugins_;
  }

  std::vector<WebPluginInfo> new_plugins;
  std::set<FilePath> visited_plugins;

  std::vector<FilePath> directories_to_scan;
  GetPluginDirectories(&directories_to_scan);

  // Load internal plugins first so that, if both an internal plugin and a
  // "discovered" plugin want to handle the same type, the internal plugin
  // will have precedence.
  for (size_t i = 0; i < internal_plugins.size(); ++i) {
    if (internal_plugins[i].path.value() == kDefaultPluginLibraryName)
      continue;
    LoadPlugin(internal_plugins[i].path, &new_plugins);
  }

  for (size_t i = 0; i < extra_plugin_paths.size(); ++i) {
    const FilePath& path = extra_plugin_paths[i];
    if (visited_plugins.find(path) != visited_plugins.end())
      continue;
    LoadPlugin(path, &new_plugins);
    visited_plugins.insert(path);
  }

  for (size_t i = 0; i < extra_plugin_dirs.size(); ++i) {
    LoadPluginsFromDir(extra_plugin_dirs[i], &new_plugins, &visited_plugins);
  }

  for (size_t i = 0; i < directories_to_scan.size(); ++i) {
    LoadPluginsFromDir(directories_to_scan[i], &new_plugins, &visited_plugins);
  }

#if defined OS_WIN
  LoadPluginsFromRegistry(&new_plugins, &visited_plugins);
#endif

  // Load the default plugin last.
  if (webkit_glue::IsDefaultPluginEnabled())
    LoadPlugin(FilePath(kDefaultPluginLibraryName), &new_plugins);

  // Only update the data now since loading plugins can take a while.
  AutoLock lock(lock_);

  // Go through and mark new plugins in the disabled list as, well, disabled.
  for (std::vector<WebPluginInfo>::iterator it = new_plugins.begin();
       it != new_plugins.end();
       ++it) {
    if (disabled_plugins_.find(it->path) != disabled_plugins_.end())
      it->enabled = false;
  }

  plugins_ = new_plugins;
  plugins_loaded_ = true;
}

void PluginList::LoadPlugin(const FilePath& path,
                            std::vector<WebPluginInfo>* plugins) {
  LOG_IF(ERROR, PluginList::DebugPluginLoading())
      << "Loading plugin " << path.value();

  WebPluginInfo plugin_info;
  const PluginEntryPoints* entry_points;

  if (!ReadPluginInfo(path, &plugin_info, &entry_points))
    return;

  if (!ShouldLoadPlugin(plugin_info, plugins))
    return;

  if (path.value() != kDefaultPluginLibraryName
#if defined(OS_WIN) && !defined(NDEBUG)
      && path.BaseName().value() != L"npspy.dll"  // Make an exception for NPSPY
#endif
      ) {
    for (size_t i = 0; i < plugin_info.mime_types.size(); ++i) {
      // TODO: don't load global handlers for now.
      // WebKit hands to the Plugin before it tries
      // to handle mimeTypes on its own.
      const std::string &mime_type = plugin_info.mime_types[i].mime_type;
      if (mime_type == "*" )
        return;
    }
  }

  plugins->push_back(plugin_info);
}

bool PluginList::FindPlugin(const std::string& mime_type,
                            bool allow_wildcard,
                            WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindDisabledPlugin(const std::string& mime_type,
                                    bool allow_wildcard,
                                    WebPluginInfo* info) {
  DCHECK(mime_type == StringToLowerASCII(mime_type));

  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (!plugins_[i].enabled &&
        SupportsType(plugins_[i], mime_type, allow_wildcard)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::FindPlugin(const GURL &url,
                            std::string* actual_mime_type,
                            WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  std::string path = url.path();
  std::string::size_type last_dot = path.rfind('.');
  if (last_dot == std::string::npos)
    return false;

  std::string extension = StringToLowerASCII(std::string(path, last_dot+1));

  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].enabled &&
        SupportsExtension(plugins_[i], extension, actual_mime_type)) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::SupportsType(const WebPluginInfo& info,
                              const std::string &mime_type,
                              bool allow_wildcard) {
  // Webkit will ask for a plugin to handle empty mime types.
  if (mime_type.empty())
    return false;

  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_info = info.mime_types[i];
    if (net::MatchesMimeType(mime_info.mime_type, mime_type)) {
      if (!allow_wildcard && mime_info.mime_type == "*") {
        continue;
      }
      return true;
    }
  }
  return false;
}

bool PluginList::SupportsExtension(const WebPluginInfo& info,
                                   const std::string &extension,
                                   std::string* actual_mime_type) {
  for (size_t i = 0; i < info.mime_types.size(); ++i) {
    const WebPluginMimeType& mime_type = info.mime_types[i];
    for (size_t j = 0; j < mime_type.file_extensions.size(); ++j) {
      if (mime_type.file_extensions[j] == extension) {
        if (actual_mime_type)
          *actual_mime_type = mime_type.mime_type;
        return true;
      }
    }
  }

  return false;
}

void PluginList::GetPlugins(bool refresh, std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  AutoLock lock(lock_);
  *plugins = plugins_;
}

void PluginList::GetEnabledPlugins(bool refresh,
                                   std::vector<WebPluginInfo>* plugins) {
  LoadPlugins(refresh);

  plugins->clear();
  AutoLock lock(lock_);
  for (std::vector<WebPluginInfo>::const_iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->enabled)
      plugins->push_back(*it);
  }
}

bool PluginList::GetPluginInfo(const GURL& url,
                               const std::string& mime_type,
                               bool allow_wildcard,
                               WebPluginInfo* info,
                               std::string* actual_mime_type) {
  bool found = FindPlugin(mime_type, allow_wildcard, info);
  if (!found || (info->path.value() == kDefaultPluginLibraryName)) {
    if (FindPlugin(url, actual_mime_type, info) ||
        FindDisabledPlugin(mime_type, allow_wildcard, info)) {
      found = true;
    }
  }

  return found;
}

bool PluginList::GetPluginInfoByPath(const FilePath& plugin_path,
                                     WebPluginInfo* info) {
  LoadPlugins(false);
  AutoLock lock(lock_);
  for (size_t i = 0; i < plugins_.size(); ++i) {
    if (plugins_[i].path == plugin_path) {
      *info = plugins_[i];
      return true;
    }
  }

  return false;
}

bool PluginList::EnablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_enable = false;

  std::set<FilePath>::iterator entry = disabled_plugins_.find(filename);
  if (entry == disabled_plugins_.end())
    return did_enable;  // Early exit if plugin not in disabled list.

  disabled_plugins_.erase(entry);  // Remove from disabled list.

  // Set enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(!it->enabled);  // Should have been disabled.
      it->enabled = true;
      did_enable = true;
    }
  }

  return did_enable;
}

bool PluginList::DisablePlugin(const FilePath& filename) {
  AutoLock lock(lock_);

  bool did_disable = false;

  if (disabled_plugins_.find(filename) != disabled_plugins_.end())
    return did_disable;  // Early exit if plugin already in disabled list.

  disabled_plugins_.insert(filename);  // Add to disabled list.

  // Unset enabled flags if necessary.
  for (std::vector<WebPluginInfo>::iterator it = plugins_.begin();
       it != plugins_.end();
       ++it) {
    if (it->path == filename) {
      DCHECK(it->enabled);  // Should have been enabled.
      it->enabled = false;
      did_disable = true;
    }
  }

  return did_disable;
}

void PluginList::Shutdown() {
  // TODO
}

}  // namespace NPAPI
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Project OSRM contributors
All rights reserved.

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

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

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

*/

#ifndef API_GRAMMAR_HPP
#define API_GRAMMAR_HPP

#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_action.hpp>

namespace qi = boost::spirit::qi;

template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Iterator>
{
    explicit APIGrammar(HandlerT *h) : APIGrammar::base_type(api_call), handler(h)
    {
        api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
                   *(query) >> -(uturns);
        query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
                            language | instruction | geometry | alt_route | old_API | num_results |
                            matching_beta | gps_precision | classify | geometry_string));

        zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
               qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
        output = (-qi::lit('&')) >> qi::lit("output") >> '=' >>
                 string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
        jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
                stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
        checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
                   qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
        instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
                      qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
        geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
                   qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
        cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >>
              qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
        location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >>
                   (qi::double_ >> qi::lit(',') >>
                    qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
        hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
               stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
        timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
               qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
        u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
            qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
        uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
                 qi::bool_[boost::bind(&HandlerT::setAllUTurns, handler, ::_1)];
        language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >>
                   string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
        alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >>
                    qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
        old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >>
                  string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
        num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >>
                      qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
        matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
               qi::short_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
        gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
               qi::short_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
        classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
            qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
        geometry_string = (-qi::lit('&')) >> qi::lit("geometry_string") >> '=' >>
            stringforPolyline[boost::bind(&HandlerT::getCoordinatesFromGeometry, handler, ::_1)];

        string = +(qi::char_("a-zA-Z"));
        stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
        stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
                              (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
        stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
    }

    qi::rule<Iterator> api_call, query;
    qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
        hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
        uturns, old_API, num_results, matching_beta, gps_precision, classify, geometry_string, stringforPolyline;

    HandlerT *handler;
};

#endif /* API_GRAMMAR_HPP */
<commit_msg>changed parameter from geometry_string to locs<commit_after>/*

Copyright (c) 2013, Project OSRM contributors
All rights reserved.

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

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

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

*/

#ifndef API_GRAMMAR_HPP
#define API_GRAMMAR_HPP

#include <boost/bind.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_action.hpp>

namespace qi = boost::spirit::qi;

template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Iterator>
{
    explicit APIGrammar(HandlerT *h) : APIGrammar::base_type(api_call), handler(h)
    {
        api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
                   *(query) >> -(uturns);
        query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
                            language | instruction | geometry | alt_route | old_API | num_results |
                            matching_beta | gps_precision | classify | locs));

        zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
               qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
        output = (-qi::lit('&')) >> qi::lit("output") >> '=' >>
                 string[boost::bind(&HandlerT::setOutputFormat, handler, ::_1)];
        jsonp = (-qi::lit('&')) >> qi::lit("jsonp") >> '=' >>
                stringwithPercent[boost::bind(&HandlerT::setJSONpParameter, handler, ::_1)];
        checksum = (-qi::lit('&')) >> qi::lit("checksum") >> '=' >>
                   qi::uint_[boost::bind(&HandlerT::setChecksum, handler, ::_1)];
        instruction = (-qi::lit('&')) >> qi::lit("instructions") >> '=' >>
                      qi::bool_[boost::bind(&HandlerT::setInstructionFlag, handler, ::_1)];
        geometry = (-qi::lit('&')) >> qi::lit("geometry") >> '=' >>
                   qi::bool_[boost::bind(&HandlerT::setGeometryFlag, handler, ::_1)];
        cmp = (-qi::lit('&')) >> qi::lit("compression") >> '=' >>
              qi::bool_[boost::bind(&HandlerT::setCompressionFlag, handler, ::_1)];
        location = (-qi::lit('&')) >> qi::lit("loc") >> '=' >>
                   (qi::double_ >> qi::lit(',') >>
                    qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
        hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
               stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
        timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
               qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
        u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
            qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
        uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
                 qi::bool_[boost::bind(&HandlerT::setAllUTurns, handler, ::_1)];
        language = (-qi::lit('&')) >> qi::lit("hl") >> '=' >>
                   string[boost::bind(&HandlerT::setLanguage, handler, ::_1)];
        alt_route = (-qi::lit('&')) >> qi::lit("alt") >> '=' >>
                    qi::bool_[boost::bind(&HandlerT::setAlternateRouteFlag, handler, ::_1)];
        old_API = (-qi::lit('&')) >> qi::lit("geomformat") >> '=' >>
                  string[boost::bind(&HandlerT::setDeprecatedAPIFlag, handler, ::_1)];
        num_results = (-qi::lit('&')) >> qi::lit("num_results") >> '=' >>
                      qi::short_[boost::bind(&HandlerT::setNumberOfResults, handler, ::_1)];
        matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
               qi::short_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
        gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
               qi::short_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
        classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
            qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
        locs = (-qi::lit('&')) >> qi::lit("locs") >> '=' >>
            stringforPolyline[boost::bind(&HandlerT::getCoordinatesFromGeometry, handler, ::_1)];

        string = +(qi::char_("a-zA-Z"));
        stringwithDot = +(qi::char_("a-zA-Z0-9_.-"));
        stringwithPercent = +(qi::char_("a-zA-Z0-9_.-") | qi::char_('[') | qi::char_(']') |
                              (qi::char_('%') >> qi::char_("0-9A-Z") >> qi::char_("0-9A-Z")));
        stringforPolyline = +(qi::char_("a-zA-Z0-9_.-[]{}@?|\\%~`^"));
    }

    qi::rule<Iterator> api_call, query;
    qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
        hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
        uturns, old_API, num_results, matching_beta, gps_precision, classify, locs, stringforPolyline;

    HandlerT *handler;
};

#endif /* API_GRAMMAR_HPP */
<|endoftext|>


<commit_before>//! Copyright (c) 2014 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include "global.h"
#include "player.h"

Player::Player(void) {
  ResetPlayer();
}

Player::~Player(void) {
}

void Player::ResetPlayer(void) {
  state_  = PLAYERSTATE_OFFLINE;
  connid_ = INVAL_CONNECTOR;

  data_.account         = "";
  data_.user_id         = GameData::INVAL_USERID;
  data_.user_name       = "";
  data_.gender          = GameData::GENDERTYPE_UNKNOWN;
  data_.face            = GameData::DEFAULT_FACEID;
  data_.level           = 0;
  data_.exp             = 0;
  data_.scores          = 0;
  data_.coins           = 0;
  data_.win_count       = 0;
  data_.lost_count      = 0;
  data_.flee_count      = 0;
  data_.win_streak      = 0;
  data_.play_time       = 0;
  data_.lost_count      = 0;
  data_.reg_time        = 0;
  data_.reg_addr        = 0;
  data_.last_login_time = 0;
  data_.last_login_addr = 0;
}
<commit_msg>fixed bug of ResetPlayer<commit_after>//! Copyright (c) 2014 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include "global.h"
#include "player.h"

Player::Player(void) {
  ResetPlayer();
}

Player::~Player(void) {
}

void Player::ResetPlayer(void) {
  state_  = PLAYERSTATE_OFFLINE;
  connid_ = INVAL_CONNECTOR;

  data_.account         = "";
  data_.user_id         = GameData::INVAL_USERID;
  data_.user_name       = "";
  data_.gender          = GameData::GENDERTYPE_UNKNOWN;
  data_.face            = GameData::DEFAULT_FACEID;
  data_.level           = 0;
  data_.exp             = 0;
  data_.scores          = 0;
  data_.coins           = 0;
  data_.win_count       = 0;
  data_.lost_count      = 0;
  data_.flee_count      = 0;
  data_.win_streak      = 0;
  data_.play_time       = 0;
  data_.login_count     = 0;
  data_.reg_time        = 0;
  data_.reg_addr        = 0;
  data_.last_login_time = 0;
  data_.last_login_addr = 0;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_SCAL_FUN_LOG1M_HPP
#define STAN_MATH_PRIM_SCAL_FUN_LOG1M_HPP

#include <stan/math/prim/scal/fun/log1p.hpp>
#include <stan/math/prim/scal/err/check_less_or_equal.hpp>

namespace stan {
namespace math {

/**
 * Return the natural logarithm of one minus the specified value.
 *
 * The main use of this function is to cut down on intermediate
 * values during algorithmic differentiation.
 *
 *
   \f[
   \mbox{log1m}(x) =
   \begin{cases}
     \ln(1-x) & \mbox{if } x \leq 1 \\
     \textrm{NaN} & \mbox{if } x > 1\\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{log1m}(x)}{\partial x} =
   \begin{cases}
     -\frac{1}{1-x} & \mbox{if } x \leq 1 \\
     \textrm{NaN} & \mbox{if } x > 1\\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN}
   \end{cases}
   \f]
 *
 * @param[in] x Argument.
 * @return Natural log of one minus the argument.
 * @throw std::domain_error If the argument is greater than 1.
 * @throw std::overflow_error If the computation overflows.
 */
inline double log1m(double x) {
  if (!is_nan(x))
    check_less_or_equal("log1m", "x", x, 1);
  return stan::math::log1p(-x);
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>Add missing header.<commit_after>#ifndef STAN_MATH_PRIM_SCAL_FUN_LOG1M_HPP
#define STAN_MATH_PRIM_SCAL_FUN_LOG1M_HPP

#include <stan/math/prim/scal/fun/log1p.hpp>
#include <stan/math/prim/scal/fun/is_nan.hpp>
#include <stan/math/prim/scal/err/check_less_or_equal.hpp>

namespace stan {
namespace math {

/**
 * Return the natural logarithm of one minus the specified value.
 *
 * The main use of this function is to cut down on intermediate
 * values during algorithmic differentiation.
 *
 *
   \f[
   \mbox{log1m}(x) =
   \begin{cases}
     \ln(1-x) & \mbox{if } x \leq 1 \\
     \textrm{NaN} & \mbox{if } x > 1\\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN}
   \end{cases}
   \f]

   \f[
   \frac{\partial\, \mbox{log1m}(x)}{\partial x} =
   \begin{cases}
     -\frac{1}{1-x} & \mbox{if } x \leq 1 \\
     \textrm{NaN} & \mbox{if } x > 1\\[6pt]
     \textrm{NaN} & \mbox{if } x = \textrm{NaN}
   \end{cases}
   \f]
 *
 * @param[in] x Argument.
 * @return Natural log of one minus the argument.
 * @throw std::domain_error If the argument is greater than 1.
 * @throw std::overflow_error If the computation overflows.
 */
inline double log1m(double x) {
  if (!is_nan(x))
    check_less_or_equal("log1m", "x", x, 1);
  return stan::math::log1p(-x);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#include "mainwindow.hpp"

#include "drape_surface.hpp"

#include <QtWidgets/QWidget>

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent)
{
  resize(600, 400);
  DrapeSurface * surface = new DrapeSurface();
  m_surface = QWidget::createWindowContainer(surface, this);
  setCentralWidget(m_surface);
}

MainWindow::~MainWindow()
{
}

void MainWindow::closeEvent(QCloseEvent * closeEvent)
{
  delete m_surface;
}
<commit_msg>[codereview]<commit_after>#include "mainwindow.hpp"

#include "drape_surface.hpp"

#include <QtWidgets/QWidget>

MainWindow::MainWindow(QWidget *parent)
  : QMainWindow(parent)
  , m_surface(NULL)
{
  resize(600, 400);
  DrapeSurface * surface = new DrapeSurface();
  m_surface = QWidget::createWindowContainer(surface, this);
  setCentralWidget(m_surface);
}

MainWindow::~MainWindow()
{
  ASSERT(m_surface == NULL, ());
}

void MainWindow::closeEvent(QCloseEvent * closeEvent)
{
  delete m_surface;
  m_surface = NULL;
}
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName			:    NFCLogModule.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-12-15
//    @Module           :    NFCLogModule
//    @Desc             :
// -------------------------------------------------------------------------

#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <stdarg.h>
#include "NFCLogModule.h"
#include "easylogging++.h"

INITIALIZE_EASYLOGGINGPP

unsigned int NFCLogModule::idx = 0;

bool NFCLogModule::CheckLogFileExist(const char* filename)
{
    std::stringstream stream;
    stream << filename << "." << ++idx;
    std::fstream file;
    file.open(stream.str(), std::ios::in);
    if (file)
    {
        return CheckLogFileExist(filename);
    }

    return false;
}

void NFCLogModule::rolloutHandler(const char* filename, std::size_t size)
{
    std::stringstream stream;
    if (!CheckLogFileExist(filename))
    {
        stream << filename << "." << idx;
        rename(filename, stream.str().c_str());
    }
}

NFCLogModule::NFCLogModule(NFIPluginManager* p)
{
    pPluginManager = p;
}

bool NFCLogModule::Init()
{
    mnLogCountTotal = 0;

    el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
    el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
#if NF_PLATFORM == NF_PLATFORM_WIN
    el::Configurations conf("log_win.conf");
#else
    el::Configurations conf("log.conf");
#endif
    el::Loggers::reconfigureAllLoggers(conf);
    el::Helpers::installPreRollOutCallback(rolloutHandler);

    return true;
}

bool NFCLogModule::Shut()
{
    el::Helpers::uninstallPreRollOutCallback();

    return true;
}

bool NFCLogModule::BeforeShut()
{
    return true;

}

bool NFCLogModule::AfterInit()
{
    return true;

}

bool NFCLogModule::Execute()
{
    return true;

}

bool NFCLogModule::Log(const NF_LOG_LEVEL nll, const char* format, ...)
{
    mnLogCountTotal++;

    char szBuffer[1024 * 10] = {0};

    va_list args;
    va_start(args, format);
    vsnprintf(szBuffer, sizeof(szBuffer) - 1, format, args);
    va_end(args);

    switch (nll)
    {
        case NFILogModule::NLL_DEBUG_NORMAL:
            LOG(DEBUG) << mnLogCountTotal << " | " << szBuffer;
            break;
        case NFILogModule::NLL_INFO_NORMAL:
            LOG(INFO) << mnLogCountTotal << " | " << szBuffer;
            break;
        case NFILogModule::NLL_WARING_NORMAL:
            LOG(WARNING) << mnLogCountTotal << " | " << szBuffer;
            break;
        case NFILogModule::NLL_ERROR_NORMAL:
        {
            LOG(ERROR) << mnLogCountTotal << " | " << szBuffer;
            //LogStack();
        }
        break;
        case NFILogModule::NLL_FATAL_NORMAL:
            LOG(FATAL) << mnLogCountTotal << " | " << szBuffer;
            break;
        default:
            LOG(INFO) << mnLogCountTotal << " | " << szBuffer;
            break;
    }

    return true;
}

bool NFCLogModule::LogElement(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strElement, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[ELEMENT] Indent[%s] Element[%s] %s %s %d", ident.ToString().c_str(), strElement.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[ELEMENT] Indent[%s] Element[%s] %s", ident.ToString().c_str(), strElement.c_str(), strDesc.c_str());
    }

    return true;
}

bool NFCLogModule::LogProperty(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strProperty, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[PROPERTY] Indent[%s] Property[%s] %s %s %d", ident.ToString().c_str(), strProperty.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[PROPERTY] Indent[%s] Property[%s] %s", ident.ToString().c_str(), strProperty.c_str(), strDesc.c_str());
    }

    return true;

}

bool NFCLogModule::LogRecord(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strRecord, const std::string& strDesc, const int nRow, const int nCol, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] Row[%d] Col[%d] %s %s %d", ident.ToString().c_str(), strRecord.c_str(), nRow, nCol, strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] Row[%d] Col[%d] %s", ident.ToString().c_str(), strRecord.c_str(), nRow, nCol, strDesc.c_str());
    }

    return true;

}

bool NFCLogModule::LogRecord(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strRecord, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] %s %s %d", ident.ToString().c_str(), strRecord.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] %s", ident.ToString().c_str(), strRecord.c_str(), strDesc.c_str());
    }

    return true;
}

bool NFCLogModule::LogObject(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[OBJECT] Indent[%s] %s %s %d", ident.ToString().c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[OBJECT] Indent[%s] %s", ident.ToString().c_str(), strDesc.c_str());
    }

    return true;

}

void NFCLogModule::LogStack()
{

    //To Add
    /*
    #ifdef NF_DEBUG_MODE
    time_t t = time(0);
    char szDmupName[MAX_PATH];
    tm* ptm = localtime(&t);

    sprintf(szDmupName, "%d_%d_%d_%d_%d_%d.dmp",  ptm->tm_year + 1900, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    // 创建Dump文件
    HANDLE hDumpFile = CreateFile(szDmupName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // Dump信息
    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
    //dumpInfo.ExceptionPointers = pException;
    dumpInfo.ThreadId = GetCurrentThreadId();
    dumpInfo.ClientPointers = TRUE;

    // 写入Dump文件内容
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

    CloseHandle(hDumpFile);

    #endif
    */
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strInfo, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %s %s %d", ident.ToString().c_str(), strInfo.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s %s", ident.ToString().c_str(), strInfo.c_str(), strDesc.c_str());
    }

    return true;
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strInfo, const int nDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %d %s %d", ident.ToString().c_str(), strInfo.c_str(), nDesc, func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s %d", ident.ToString().c_str(), strInfo.c_str(), nDesc);
    }

    return true;
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::ostringstream& stream, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %s %d", ident.ToString().c_str(), stream.str(), func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s", ident.ToString().c_str(), stream.str());
    }

    return true;
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strInfo, const char* func /*= ""*/, int line /*= 0*/)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %s %d", ident.ToString().c_str(), strInfo.c_str(), func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s", ident.ToString().c_str(), strInfo.c_str());
    }

    return true;
}

bool NFCLogModule::LogDebugFunctionDump(const NFGUID ident, const int nMsg, const std::string& strArg,  const char* func /*= ""*/, const int line /*= 0*/)
{
    //#ifdef NF_DEBUG_MODE
    LogNormal(NFILogModule::NLL_WARING_NORMAL, ident, strArg + "MsgID:", nMsg, func, line);
    //#endif
    return true;
}

bool NFCLogModule::ChangeLogLevel(const std::string& strLevel)
{
    el::Level logLevel = el::LevelHelper::convertFromString(strLevel.c_str());
    el::Logger* pLogger = el::Loggers::getLogger("default");
    if (NULL == pLogger)
    {
        return false;
    }

    el::Configurations* pConfigurations = pLogger->configurations();
    el::base::TypedConfigurations* pTypeConfigurations = pLogger->typedConfigurations();
    if (NULL == pConfigurations)
    {
        return false;
    }

    // log级别为debug, info, warning, error, fatal(级别逐渐提高)
    // 当传入为info时，则高于(包含)info的级别会输出
    // !!!!!! NOTICE:故意没有break，请千万注意 !!!!!!
    switch (logLevel)
    {
        case el::Level::Fatal:
        {
            el::Configuration errorConfiguration(el::Level::Error, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&errorConfiguration);
        }
        case el::Level::Error:
        {
            el::Configuration warnConfiguration(el::Level::Warning, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&warnConfiguration);
        }
        case el::Level::Warning:
        {
            el::Configuration infoConfiguration(el::Level::Info, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&infoConfiguration);
        }
        case el::Level::Info:
        {
            el::Configuration debugConfiguration(el::Level::Debug, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&debugConfiguration);

        }
        case el::Level::Debug:
            break;
        default:
            break;
    }

    el::Loggers::reconfigureAllLoggers(*pConfigurations);
    LogNormal(NFILogModule::NLL_INFO_NORMAL, NFGUID(), "[Log] Change log level", strLevel, __FUNCTION__, __LINE__);
    return true;
}
<commit_msg>log bug fix<commit_after>// -------------------------------------------------------------------------
//    @FileName			:    NFCLogModule.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2012-12-15
//    @Module           :    NFCLogModule
//    @Desc             :
// -------------------------------------------------------------------------

#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <stdarg.h>
#include "NFCLogModule.h"
#include "easylogging++.h"

INITIALIZE_EASYLOGGINGPP

unsigned int NFCLogModule::idx = 0;

bool NFCLogModule::CheckLogFileExist(const char* filename)
{
    std::stringstream stream;
    stream << filename << "." << ++idx;
    std::fstream file;
    file.open(stream.str(), std::ios::in);
    if (file)
    {
        return CheckLogFileExist(filename);
    }

    return false;
}

void NFCLogModule::rolloutHandler(const char* filename, std::size_t size)
{
    std::stringstream stream;
    if (!CheckLogFileExist(filename))
    {
        stream << filename << "." << idx;
        rename(filename, stream.str().c_str());
    }
}

NFCLogModule::NFCLogModule(NFIPluginManager* p)
{
    pPluginManager = p;
}

bool NFCLogModule::Init()
{
    mnLogCountTotal = 0;

    el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
    el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
#if NF_PLATFORM == NF_PLATFORM_WIN
    el::Configurations conf("log_win.conf");
#else
    el::Configurations conf("log.conf");
#endif
    el::Loggers::reconfigureAllLoggers(conf);
    el::Helpers::installPreRollOutCallback(rolloutHandler);

    return true;
}

bool NFCLogModule::Shut()
{
    el::Helpers::uninstallPreRollOutCallback();

    return true;
}

bool NFCLogModule::BeforeShut()
{
    return true;

}

bool NFCLogModule::AfterInit()
{
    return true;

}

bool NFCLogModule::Execute()
{
    return true;

}

bool NFCLogModule::Log(const NF_LOG_LEVEL nll, const char* format, ...)
{
    mnLogCountTotal++;

    char szBuffer[1024 * 10] = {0};

    va_list args;
    va_start(args, format);
    vsnprintf(szBuffer, sizeof(szBuffer) - 1, format, args);
    va_end(args);

    switch (nll)
    {
        case NFILogModule::NLL_DEBUG_NORMAL:
            LOG(DEBUG) << mnLogCountTotal << " | " << szBuffer;
            break;
        case NFILogModule::NLL_INFO_NORMAL:
            LOG(INFO) << mnLogCountTotal << " | " << szBuffer;
            break;
        case NFILogModule::NLL_WARING_NORMAL:
            LOG(WARNING) << mnLogCountTotal << " | " << szBuffer;
            break;
        case NFILogModule::NLL_ERROR_NORMAL:
        {
            LOG(ERROR) << mnLogCountTotal << " | " << szBuffer;
            //LogStack();
        }
        break;
        case NFILogModule::NLL_FATAL_NORMAL:
            LOG(FATAL) << mnLogCountTotal << " | " << szBuffer;
            break;
        default:
            LOG(INFO) << mnLogCountTotal << " | " << szBuffer;
            break;
    }

    return true;
}

bool NFCLogModule::LogElement(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strElement, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[ELEMENT] Indent[%s] Element[%s] %s %s %d", ident.ToString().c_str(), strElement.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[ELEMENT] Indent[%s] Element[%s] %s", ident.ToString().c_str(), strElement.c_str(), strDesc.c_str());
    }

    return true;
}

bool NFCLogModule::LogProperty(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strProperty, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[PROPERTY] Indent[%s] Property[%s] %s %s %d", ident.ToString().c_str(), strProperty.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[PROPERTY] Indent[%s] Property[%s] %s", ident.ToString().c_str(), strProperty.c_str(), strDesc.c_str());
    }

    return true;

}

bool NFCLogModule::LogRecord(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strRecord, const std::string& strDesc, const int nRow, const int nCol, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] Row[%d] Col[%d] %s %s %d", ident.ToString().c_str(), strRecord.c_str(), nRow, nCol, strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] Row[%d] Col[%d] %s", ident.ToString().c_str(), strRecord.c_str(), nRow, nCol, strDesc.c_str());
    }

    return true;

}

bool NFCLogModule::LogRecord(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strRecord, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] %s %s %d", ident.ToString().c_str(), strRecord.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[RECORD] Indent[%s] Record[%s] %s", ident.ToString().c_str(), strRecord.c_str(), strDesc.c_str());
    }

    return true;
}

bool NFCLogModule::LogObject(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "[OBJECT] Indent[%s] %s %s %d", ident.ToString().c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "[OBJECT] Indent[%s] %s", ident.ToString().c_str(), strDesc.c_str());
    }

    return true;

}

void NFCLogModule::LogStack()
{

    //To Add
    /*
    #ifdef NF_DEBUG_MODE
    time_t t = time(0);
    char szDmupName[MAX_PATH];
    tm* ptm = localtime(&t);

    sprintf(szDmupName, "%d_%d_%d_%d_%d_%d.dmp",  ptm->tm_year + 1900, ptm->tm_mon, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
    // 创建Dump文件
    HANDLE hDumpFile = CreateFile(szDmupName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    // Dump信息
    MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
    //dumpInfo.ExceptionPointers = pException;
    dumpInfo.ThreadId = GetCurrentThreadId();
    dumpInfo.ClientPointers = TRUE;

    // 写入Dump文件内容
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);

    CloseHandle(hDumpFile);

    #endif
    */
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strInfo, const std::string& strDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %s %s %d", ident.ToString().c_str(), strInfo.c_str(), strDesc.c_str(), func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s %s", ident.ToString().c_str(), strInfo.c_str(), strDesc.c_str());
    }

    return true;
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strInfo, const int nDesc, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %d %s %d", ident.ToString().c_str(), strInfo.c_str(), nDesc, func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s %d", ident.ToString().c_str(), strInfo.c_str(), nDesc);
    }

    return true;
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::ostringstream& stream, const char* func, int line)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %s %d", ident.ToString().c_str(), stream.str().c_str(), func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s", ident.ToString().c_str(), stream.str().c_str());
    }

    return true;
}

bool NFCLogModule::LogNormal(const NF_LOG_LEVEL nll, const NFGUID ident, const std::string& strInfo, const char* func /*= ""*/, int line /*= 0*/)
{
    if (line > 0)
    {
        Log(nll, "Indent[%s] %s %s %d", ident.ToString().c_str(), strInfo.c_str(), func, line);
    }
    else
    {
        Log(nll, "Indent[%s] %s", ident.ToString().c_str(), strInfo.c_str());
    }

    return true;
}

bool NFCLogModule::LogDebugFunctionDump(const NFGUID ident, const int nMsg, const std::string& strArg,  const char* func /*= ""*/, const int line /*= 0*/)
{
    //#ifdef NF_DEBUG_MODE
    LogNormal(NFILogModule::NLL_WARING_NORMAL, ident, strArg + "MsgID:", nMsg, func, line);
    //#endif
    return true;
}

bool NFCLogModule::ChangeLogLevel(const std::string& strLevel)
{
    el::Level logLevel = el::LevelHelper::convertFromString(strLevel.c_str());
    el::Logger* pLogger = el::Loggers::getLogger("default");
    if (NULL == pLogger)
    {
        return false;
    }

    el::Configurations* pConfigurations = pLogger->configurations();
    el::base::TypedConfigurations* pTypeConfigurations = pLogger->typedConfigurations();
    if (NULL == pConfigurations)
    {
        return false;
    }

    // log级别为debug, info, warning, error, fatal(级别逐渐提高)
    // 当传入为info时，则高于(包含)info的级别会输出
    // !!!!!! NOTICE:故意没有break，请千万注意 !!!!!!
    switch (logLevel)
    {
        case el::Level::Fatal:
        {
            el::Configuration errorConfiguration(el::Level::Error, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&errorConfiguration);
        }
        case el::Level::Error:
        {
            el::Configuration warnConfiguration(el::Level::Warning, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&warnConfiguration);
        }
        case el::Level::Warning:
        {
            el::Configuration infoConfiguration(el::Level::Info, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&infoConfiguration);
        }
        case el::Level::Info:
        {
            el::Configuration debugConfiguration(el::Level::Debug, el::ConfigurationType::Enabled, "false");
            pConfigurations->set(&debugConfiguration);

        }
        case el::Level::Debug:
            break;
        default:
            break;
    }

    el::Loggers::reconfigureAllLoggers(*pConfigurations);
    LogNormal(NFILogModule::NLL_INFO_NORMAL, NFGUID(), "[Log] Change log level", strLevel, __FUNCTION__, __LINE__);
    return true;
}
<|endoftext|>


<commit_before>// This file is part of MLDB. Copyright 2015 Datacratic. All rights reserved.

/** nlp.cc
    Francois Maillet, 20 octobre 2015
    Copyright (c) 2015 Datacratic Inc.  All rights reserved.

*/

#include "nlp.h"
#include "mldb/server/mldb_server.h"
#include "mldb/types/basic_value_descriptions.h"
#include "mldb/types/any_impl.h"
#include "mldb/sql/tokenize.h"
#include "mldb/base/parse_context.h"

using namespace std;

namespace Datacratic {
namespace MLDB {

DEFINE_STRUCTURE_DESCRIPTION(Words);

WordsDescription::WordsDescription()
{
    addField("words", &Words::words,
             "Row-valued bag of words where keys are words and values are "
             "counts or weights");
}

DEFINE_STRUCTURE_DESCRIPTION(Document);

DocumentDescription::DocumentDescription()
{
    addField("document", &Document::document,
             "String-valued value containing the text of the document");
}

/*****************************************************************************/
/* APPLY STOP WORDS FUNCTION CONFIG                                          */
/*****************************************************************************/

DEFINE_STRUCTURE_DESCRIPTION(ApplyStopWordsFunctionConfig);

ApplyStopWordsFunctionConfigDescription::
ApplyStopWordsFunctionConfigDescription()
{
}

/*****************************************************************************/
/* APPLY STOP WORDS FUNCTION                                                 */
/*****************************************************************************/

ApplyStopWordsFunction::
ApplyStopWordsFunction(MldbServer * owner,
                       PolyConfig config,
                       const std::function<bool (const Json::Value &)> & onProgress)
    : BaseT(owner)
{
    //functionConfig = config.params.convert<ApplyStopWordsFunctionConfig>();

    stopwords = {{"english", {"a's","able","about","above","according","accordingly","across","actually","after","afterwards","again","against","ain't","all","allow","allows","almost","alone","along","already","also","although","always","am","among","amongst","an","and","another","any","anybody","anyhow","anyone","anything","anyway","anyways","anywhere","apart","appear","appreciate","appropriate","are","aren't","around","as","aside","ask","asking","associated","at","available","away","awfully","be","became","because","become","becomes","becoming","been","before","beforehand","behind","being","believe","below","beside","besides","best","better","between","beyond","both","brief","but","by","c'mon","c's","came","can","can't","cannot","cant","cause","causes","certain","certainly","changes","clearly","co","com","come","comes","concerning","consequently","consider","considering","contain","containing","contains","corresponding","could","couldn't","course","currently","definitely","described","despite","did","didn't","different","do","does","doesn't","doing","don't","done","down","downwards","during","each","edu","eg","eight","either","else","elsewhere","enough","entirely","especially","et","etc","even","ever","every","everybody","everyone","everything","everywhere","ex","exactly","example","except","far","few","fifth","first","five","followed","following","follows","for","former","formerly","forth","four","from","further","furthermore","get","gets","getting","given","gives","go","goes","going","gone","got","gotten","greetings","had","hadn't","happens","hardly","has","hasn't","have","haven't","having","he","he's","hello","help","hence","her","here","here's","hereafter","hereby","herein","hereupon","hers","herself","hi","him","himself","his","hither","hopefully","how","howbeit","however","i'd","i'll","i'm","i've","ie","if","ignored","immediate","in","inasmuch","inc","indeed","indicate","indicated","indicates","inner","insofar","instead","into","inward","is","isn't","it","it'd","it'll","it's","its","itself","just","keep","keeps","kept","know","known","knows","last","lately","later","latter","latterly","least","less","lest","let","let's","like","liked","likely","little","look","looking","looks","ltd","mainly","many","may","maybe","me","mean","meanwhile","merely","might","more","moreover","most","mostly","much","must","my","myself","name","namely","nd","near","nearly","necessary","need","needs","neither","never","nevertheless","new","next","nine","no","nobody","non","none","noone","nor","normally","not","nothing","novel","now","nowhere","obviously","of","off","often","oh","ok","okay","old","on","once","one","ones","only","onto","or","other","others","otherwise","ought","our","ours","ourselves","out","outside","over","overall","own","particular","particularly","per","perhaps","placed","please","plus","possible","presumably","probably","provides","que","quite","qv","rather","rd","re","really","reasonably","regarding","regardless","regards","relatively","respectively","right","said","same","saw","say","saying","says","second","secondly","see","seeing","seem","seemed","seeming","seems","seen","self","selves","sensible","sent","serious","seriously","seven","several","shall","she","should","shouldn't","since","six","so","some","somebody","somehow","someone","something","sometime","sometimes","somewhat","somewhere","soon","sorry","specified","specify","specifying","still","sub","such","sup","sure","t's","take","taken","tell","tends","th","than","thank","thanks","thanx","that","that's","thats","the","their","theirs","them","themselves","then","thence","there","there's","thereafter","thereby","therefore","therein","theres","thereupon","these","they","they'd","they'll","they're","they've","think","third","this","thorough","thoroughly","those","though","three","through","throughout","thru","thus","to","together","too","took","toward","towards","tried","tries","truly","try","trying","twice","two","un","under","unfortunately","unless","unlikely","until","unto","up","upon","us","use","used","useful","uses","using","usually","value","various","very","via","viz","vs","want","wants","was","wasn't","way","we","we'd","we'll","we're","we've","welcome","well","went","were","weren't","what","what's","whatever","when","whence","whenever","where","where's","whereafter","whereas","whereby","wherein","whereupon","wherever","whether","which","while","whither","who","who's","whoever","whole","whom","whose","why","will","willing","wish","with","within","without","won't","wonder","would","wouldn't","yes","yet","you","you'd","you'll","you're","you've","your","yours","yourself","yourselves","zero"}}};

    auto it = stopwords.find(functionConfig.language);
    if(it == stopwords.end())
        throw ML::Exception("Unsupported language: " + functionConfig.language);

    selected_stopwords = &(it->second);
}

Words
ApplyStopWordsFunction::
call(Words input) const
{
    RowValue rtnRow;
    auto onAtom = [&] (const Path & columnName,
                       const Path & prefix,
                       const CellValue & val,
                       Date ts)
        {
            if(columnName.size() != 1) {
                rtnRow.push_back(make_tuple(columnName, val, ts));
                return true;
            }

            const string colStr = columnName.toSimpleName().stealRawString();

            if(!selected_stopwords->count(colStr)) {
                rtnRow.push_back(make_tuple(columnName, val, ts));
            }

            return true;
        };

    input.words.forEachAtom(onAtom);

    Words result;
    result.words = std::move(rtnRow);
    return result;
}

static RegisterFunctionType<ApplyStopWordsFunction, ApplyStopWordsFunctionConfig>
regAppylStopWordsFunction(builtinPackage(),
                          "filter_stopwords",
                          "Apply a list of stop words to column names",
                          "functions/FilterStopWords.md.html",
                          nullptr,
                          { MldbEntity::INTERNAL_ENTITY });

/*****************************************************************************/
/* STEMMER FUNCTION CONFIG                                                   */
/*****************************************************************************/

DEFINE_STRUCTURE_DESCRIPTION(StemmerFunctionConfig);

StemmerFunctionConfigDescription::
StemmerFunctionConfigDescription()
{
    addField("language", &StemmerFunctionConfig::language,
             "Stemming algorithm to use", string("english"));
}

/*****************************************************************************/
/* STEMMER FUNCTION                                                          */
/*****************************************************************************/

StemmerFunction::
StemmerFunction(MldbServer * owner,
                PolyConfig config,
                const std::function<bool (const Json::Value &)> & onProgress)
    : BaseT(owner)
{
    functionConfig = config.params.convert<StemmerFunctionConfig>();

    //this is just to verify the language at creation time
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    if (!stemmer) {
        throw ML::Exception(ML::format("language `%s' not available for stemming in "
                "encoding `%s'", functionConfig.language, "utf8"));
    }
}

Words
StemmerFunction::
call(Words input) const
{
    // the sb_stemmer object is not thread safe
    // but this allocation is not very expensive as profiled
    // compared to actually doing the stemming
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    map<PathElement, pair<double, Date> > accum;

    auto onAtom = [&] (const Path & columnName,
                       const Path & prefix,
                       const CellValue & val,
                       Date ts)
        {
            string str = columnName.toSimpleName().stealRawString();
            // cerr << "got: " << str << endl;
            const sb_symbol * stemmed = sb_stemmer_stem(stemmer.get(),
                    (const unsigned char*)str.c_str(), str.size());

            if (stemmed == nullptr) {
                throw ML::Exception("Out of memory when stemming");
            }

            // Cast the cell value as a double before we accumulate them
            double val_as_double;
            if (val.isString())
                val_as_double = 1;
            else
                val_as_double = val.toDouble();

            PathElement col(string((const char*)stemmed));

            auto it = accum.find(col);
            if(it == accum.end()) {
                accum.emplace(col, std::move(make_pair(val_as_double, ts)));
            }
            else {
                it->second.first += val_as_double;
                if(it->second.second > ts)
                    it->second.second = ts;
            }

            return true;
        };

    input.words.forEachAtom(onAtom);

    RowValue rtnRow;
    rtnRow.reserve(accum.size());
    for(auto & r: accum) {
        rtnRow.emplace_back(r.first, std::move(r.second.first),
                            r.second.second);
    }

    Words result;
    result.words = std::move(rtnRow);
    return result;
}

static RegisterFunctionType<StemmerFunction, StemmerFunctionConfig>
regStemmerFunction(builtinPackage(),
                   "stemmer",
                   "Apply a stemming algorithm column names",
                   "functions/Stemmer.md.html");

/*****************************************************************************/
/* STEMMER ON DOCUMENT FUNCTION                                              */
/*****************************************************************************/

StemmerOnDocumentFunction::
StemmerOnDocumentFunction(MldbServer * owner,
                          PolyConfig config,
                          const std::function<bool (const Json::Value &)> & onProgress)
    : BaseT(owner)
{
    functionConfig = config.params.convert<StemmerFunctionConfig>();

    //this is just to verify the language at creation time
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    if (!stemmer) {
        throw ML::Exception(ML::format("language `%s' not available for stemming in "
                "encoding `%s'", functionConfig.language, "utf8"));
    }
}

Document
StemmerOnDocumentFunction::
call(Document doc) const
{
    // the sb_stemmer object is not thread safe
    // but this allocation is not very expensive as profiled
    // compared to actually doing the stemming
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    Utf8String accum;

    auto onGram = [&](Utf8String& word) -> bool
    {
        const string& str = word.rawString();

        const sb_symbol * stemmed = sb_stemmer_stem(stemmer.get(),
                    (const unsigned char*)str.c_str(), str.size());

        if (stemmed == NULL) {
            throw ML::Exception("Out of memory when stemming");
        }

        Utf8String out((const char*)stemmed);

        if (accum.empty())
          accum = out;
        else
          accum += " " + out;

        return true;
    };

    Utf8String text = doc.document.toUtf8String();
    ML::Parse_Context pcontext(text.rawData(), text.rawData(), text.rawLength());

    tokenize_exec(onGram, pcontext, " ", "", 0);

    Document result;
    result.document = ExpressionValue(std::move(accum),
                                      doc.document.getEffectiveTimestamp());
    return result;
}

static RegisterFunctionType<StemmerOnDocumentFunction, StemmerFunctionConfig>
regStemmerOnDocumentFunction(builtinPackage(),
                   "stemmerdoc",
                   "Apply a stemming algorithm on a single document",
                   "functions/Stemmer.md.html");

} // namespace MLDB
} // namespace Datacratic
<commit_msg>reverting commit which causes crash (MLDB-1689)<commit_after>// This file is part of MLDB. Copyright 2015 Datacratic. All rights reserved.

/** nlp.cc
    Francois Maillet, 20 octobre 2015
    Copyright (c) 2015 Datacratic Inc.  All rights reserved.

*/

#include "nlp.h"
#include "mldb/server/mldb_server.h"
#include "mldb/types/basic_value_descriptions.h"
#include "mldb/types/any_impl.h"
#include "mldb/sql/tokenize.h"
#include "mldb/base/parse_context.h"

using namespace std;

namespace Datacratic {
namespace MLDB {

DEFINE_STRUCTURE_DESCRIPTION(Words);

WordsDescription::WordsDescription()
{
    addField("words", &Words::words,
             "Row-valued bag of words where keys are words and values are "
             "counts or weights");
}

DEFINE_STRUCTURE_DESCRIPTION(Document);

DocumentDescription::DocumentDescription()
{
    addField("document", &Document::document,
             "String-valued value containing the text of the document");
}

/*****************************************************************************/
/* APPLY STOP WORDS FUNCTION CONFIG                                          */
/*****************************************************************************/

DEFINE_STRUCTURE_DESCRIPTION(ApplyStopWordsFunctionConfig);

ApplyStopWordsFunctionConfigDescription::
ApplyStopWordsFunctionConfigDescription()
{
}

/*****************************************************************************/
/* APPLY STOP WORDS FUNCTION                                                 */
/*****************************************************************************/

ApplyStopWordsFunction::
ApplyStopWordsFunction(MldbServer * owner,
                       PolyConfig config,
                       const std::function<bool (const Json::Value &)> & onProgress)
    : BaseT(owner)
{
    //functionConfig = config.params.convert<ApplyStopWordsFunctionConfig>();

    stopwords = {{"english", {"a's","able","about","above","according","accordingly","across","actually","after","afterwards","again","against","ain't","all","allow","allows","almost","alone","along","already","also","although","always","am","among","amongst","an","and","another","any","anybody","anyhow","anyone","anything","anyway","anyways","anywhere","apart","appear","appreciate","appropriate","are","aren't","around","as","aside","ask","asking","associated","at","available","away","awfully","be","became","because","become","becomes","becoming","been","before","beforehand","behind","being","believe","below","beside","besides","best","better","between","beyond","both","brief","but","by","c'mon","c's","came","can","can't","cannot","cant","cause","causes","certain","certainly","changes","clearly","co","com","come","comes","concerning","consequently","consider","considering","contain","containing","contains","corresponding","could","couldn't","course","currently","definitely","described","despite","did","didn't","different","do","does","doesn't","doing","don't","done","down","downwards","during","each","edu","eg","eight","either","else","elsewhere","enough","entirely","especially","et","etc","even","ever","every","everybody","everyone","everything","everywhere","ex","exactly","example","except","far","few","fifth","first","five","followed","following","follows","for","former","formerly","forth","four","from","further","furthermore","get","gets","getting","given","gives","go","goes","going","gone","got","gotten","greetings","had","hadn't","happens","hardly","has","hasn't","have","haven't","having","he","he's","hello","help","hence","her","here","here's","hereafter","hereby","herein","hereupon","hers","herself","hi","him","himself","his","hither","hopefully","how","howbeit","however","i'd","i'll","i'm","i've","ie","if","ignored","immediate","in","inasmuch","inc","indeed","indicate","indicated","indicates","inner","insofar","instead","into","inward","is","isn't","it","it'd","it'll","it's","its","itself","just","keep","keeps","kept","know","known","knows","last","lately","later","latter","latterly","least","less","lest","let","let's","like","liked","likely","little","look","looking","looks","ltd","mainly","many","may","maybe","me","mean","meanwhile","merely","might","more","moreover","most","mostly","much","must","my","myself","name","namely","nd","near","nearly","necessary","need","needs","neither","never","nevertheless","new","next","nine","no","nobody","non","none","noone","nor","normally","not","nothing","novel","now","nowhere","obviously","of","off","often","oh","ok","okay","old","on","once","one","ones","only","onto","or","other","others","otherwise","ought","our","ours","ourselves","out","outside","over","overall","own","particular","particularly","per","perhaps","placed","please","plus","possible","presumably","probably","provides","que","quite","qv","rather","rd","re","really","reasonably","regarding","regardless","regards","relatively","respectively","right","said","same","saw","say","saying","says","second","secondly","see","seeing","seem","seemed","seeming","seems","seen","self","selves","sensible","sent","serious","seriously","seven","several","shall","she","should","shouldn't","since","six","so","some","somebody","somehow","someone","something","sometime","sometimes","somewhat","somewhere","soon","sorry","specified","specify","specifying","still","sub","such","sup","sure","t's","take","taken","tell","tends","th","than","thank","thanks","thanx","that","that's","thats","the","their","theirs","them","themselves","then","thence","there","there's","thereafter","thereby","therefore","therein","theres","thereupon","these","they","they'd","they'll","they're","they've","think","third","this","thorough","thoroughly","those","though","three","through","throughout","thru","thus","to","together","too","took","toward","towards","tried","tries","truly","try","trying","twice","two","un","under","unfortunately","unless","unlikely","until","unto","up","upon","us","use","used","useful","uses","using","usually","value","various","very","via","viz","vs","want","wants","was","wasn't","way","we","we'd","we'll","we're","we've","welcome","well","went","were","weren't","what","what's","whatever","when","whence","whenever","where","where's","whereafter","whereas","whereby","wherein","whereupon","wherever","whether","which","while","whither","who","who's","whoever","whole","whom","whose","why","will","willing","wish","with","within","without","won't","wonder","would","wouldn't","yes","yet","you","you'd","you'll","you're","you've","your","yours","yourself","yourselves","zero"}}};

    auto it = stopwords.find(functionConfig.language);
    if(it == stopwords.end())
        throw ML::Exception("Unsupported language: " + functionConfig.language);

    selected_stopwords = &(it->second);
}

Words
ApplyStopWordsFunction::
call(Words input) const
{
    RowValue rtnRow;
    auto onAtom = [&] (const Path & columnName,
                       const Path & prefix,
                       const CellValue & val,
                       Date ts)
        {
            const string colStr = columnName.toSimpleName().stealRawString();

            if(!selected_stopwords->count(colStr)) {
                rtnRow.push_back(make_tuple(columnName, val, ts));
            }

            return true;
        };

    input.words.forEachAtom(onAtom);

    Words result;
    result.words = std::move(rtnRow);
    return result;
}

static RegisterFunctionType<ApplyStopWordsFunction, ApplyStopWordsFunctionConfig>
regAppylStopWordsFunction(builtinPackage(),
                          "filter_stopwords",
                          "Apply a list of stop words to column names",
                          "functions/FilterStopWords.md.html",
                          nullptr,
                          { MldbEntity::INTERNAL_ENTITY });

/*****************************************************************************/
/* STEMMER FUNCTION CONFIG                                                   */
/*****************************************************************************/

DEFINE_STRUCTURE_DESCRIPTION(StemmerFunctionConfig);

StemmerFunctionConfigDescription::
StemmerFunctionConfigDescription()
{
    addField("language", &StemmerFunctionConfig::language,
             "Stemming algorithm to use", string("english"));
}

/*****************************************************************************/
/* STEMMER FUNCTION                                                          */
/*****************************************************************************/

StemmerFunction::
StemmerFunction(MldbServer * owner,
                PolyConfig config,
                const std::function<bool (const Json::Value &)> & onProgress)
    : BaseT(owner)
{
    functionConfig = config.params.convert<StemmerFunctionConfig>();

    //this is just to verify the language at creation time
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    if (!stemmer) {
        throw ML::Exception(ML::format("language `%s' not available for stemming in "
                "encoding `%s'", functionConfig.language, "utf8"));
    }
}

Words
StemmerFunction::
call(Words input) const
{
    // the sb_stemmer object is not thread safe
    // but this allocation is not very expensive as profiled
    // compared to actually doing the stemming
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    map<PathElement, pair<double, Date> > accum;

    auto onAtom = [&] (const Path & columnName,
                       const Path & prefix,
                       const CellValue & val,
                       Date ts)
        {
            string str = columnName.toSimpleName().stealRawString();
            // cerr << "got: " << str << endl;
            const sb_symbol * stemmed = sb_stemmer_stem(stemmer.get(),
                    (const unsigned char*)str.c_str(), str.size());

            if (stemmed == nullptr) {
                throw ML::Exception("Out of memory when stemming");
            }

            // Cast the cell value as a double before we accumulate them
            double val_as_double;
            if (val.isString())
                val_as_double = 1;
            else
                val_as_double = val.toDouble();

            PathElement col(string((const char*)stemmed));

            auto it = accum.find(col);
            if(it == accum.end()) {
                accum.emplace(col, std::move(make_pair(val_as_double, ts)));
            }
            else {
                it->second.first += val_as_double;
                if(it->second.second > ts)
                    it->second.second = ts;
            }

            return true;
        };

    input.words.forEachAtom(onAtom);

    RowValue rtnRow;
    rtnRow.reserve(accum.size());
    for(auto & r: accum) {
        rtnRow.emplace_back(r.first, std::move(r.second.first),
                            r.second.second);
    }

    Words result;
    result.words = std::move(rtnRow);
    return result;
}

static RegisterFunctionType<StemmerFunction, StemmerFunctionConfig>
regStemmerFunction(builtinPackage(),
                   "stemmer",
                   "Apply a stemming algorithm column names",
                   "functions/Stemmer.md.html");

/*****************************************************************************/
/* STEMMER ON DOCUMENT FUNCTION                                              */
/*****************************************************************************/

StemmerOnDocumentFunction::
StemmerOnDocumentFunction(MldbServer * owner,
                          PolyConfig config,
                          const std::function<bool (const Json::Value &)> & onProgress)
    : BaseT(owner)
{
    functionConfig = config.params.convert<StemmerFunctionConfig>();

    //this is just to verify the language at creation time
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    if (!stemmer) {
        throw ML::Exception(ML::format("language `%s' not available for stemming in "
                "encoding `%s'", functionConfig.language, "utf8"));
    }
}

Document
StemmerOnDocumentFunction::
call(Document doc) const
{
    // the sb_stemmer object is not thread safe
    // but this allocation is not very expensive as profiled
    // compared to actually doing the stemming
    std::unique_ptr<sb_stemmer> stemmer(sb_stemmer_new(functionConfig.language.c_str(), "UTF_8"));

    Utf8String accum;

    auto onGram = [&](Utf8String& word) -> bool
    {
        const string& str = word.rawString();

        const sb_symbol * stemmed = sb_stemmer_stem(stemmer.get(),
                    (const unsigned char*)str.c_str(), str.size());

        if (stemmed == NULL) {
            throw ML::Exception("Out of memory when stemming");
        }

        Utf8String out((const char*)stemmed);

        if (accum.empty())
          accum = out;
        else
          accum += " " + out;

        return true;
    };

    Utf8String text = doc.document.toUtf8String();
    ML::Parse_Context pcontext(text.rawData(), text.rawData(), text.rawLength());

    tokenize_exec(onGram, pcontext, " ", "", 0);

    Document result;
    result.document = ExpressionValue(std::move(accum),
                                      doc.document.getEffectiveTimestamp());
    return result;
}

static RegisterFunctionType<StemmerOnDocumentFunction, StemmerFunctionConfig>
regStemmerOnDocumentFunction(builtinPackage(),
                   "stemmerdoc",
                   "Apply a stemming algorithm on a single document",
                   "functions/Stemmer.md.html");

} // namespace MLDB
} // namespace Datacratic
<|endoftext|>


<commit_before>#include "log.hpp"
#include "gtest/gtest.h"

TEST(Log, Uninitialized) {
	EXPECT_FALSE(Log::LogEvent(0,"Bad Msg, Uninitialized Logger"));
	EXPECT_FALSE(Log::Finalize());
}

TEST(Log, PreExisting) {
	Log::Initialize(0);
	EXPECT_FALSE(Log::Initialize(0));
	Log::Finalize();
}

TEST(Log, Correct) {
	EXPECT_TRUE(Log::Initialize(0));
	EXPECT_TRUE(Log::LogEvent(0,"This should work"));
	EXPECT_TRUE(Log::LogEvent(1,"This should work"));
	EXPECT_TRUE(Log::LogEvent(2,"This should work"));
	EXPECT_TRUE(Log::Finalize());
	EXPECT_TRUE(Log::Initialize(1));
	EXPECT_TRUE(Log::LogEvent(0,"This should work"));
	EXPECT_TRUE(Log::LogEvent(1,"This should work"));
	EXPECT_TRUE(Log::LogEvent(2,"This should work"));
	EXPECT_TRUE(Log::Finalize());
	EXPECT_TRUE(Log::Initialize(2));
	EXPECT_TRUE(Log::LogEvent(0,"This should work"));
	EXPECT_TRUE(Log::LogEvent(1,"This should work"));
	EXPECT_TRUE(Log::LogEvent(2,"This should work"));
	EXPECT_TRUE(Log::Finalize());
}
<commit_msg>log test update<commit_after>#include "log.hpp"
#include "gtest/gtest.h"

TEST(Log, Uninitialized) {
	EXPECT_FALSE(Log::LogEvent(0,"Bad Msg, Uninitialized Logger"));
	EXPECT_FALSE(Log::Finalize());
}

TEST(Log, PreExisting) {
	Log::Initialize(0);
	EXPECT_FALSE(Log::Initialize(0));
	Log::Finalize();
}

TEST(Log, Correct) {
	EXPECT_TRUE(Log::Initialize(0));
	EXPECT_TRUE(Log::LogEvent(0,"This should work"));
	EXPECT_TRUE(Log::LogEvent(1,"This should work"));
	EXPECT_TRUE(Log::LogEvent(2,"This should work"));
	EXPECT_TRUE(Log::LogEvent(3,"This should work"));
	EXPECT_TRUE(Log::Finalize());

	EXPECT_TRUE(Log::Initialize(1));
	EXPECT_TRUE(Log::LogEvent(0,"This should work"));
	EXPECT_TRUE(Log::LogEvent(1,"This should work"));
	EXPECT_TRUE(Log::LogEvent(2,"This should work"));
	EXPECT_TRUE(Log::LogEvent(3,"This should work"));
	EXPECT_TRUE(Log::Finalize());

	EXPECT_TRUE(Log::Initialize(2));
	EXPECT_TRUE(Log::LogEvent(0,"This should work"));
	EXPECT_TRUE(Log::LogEvent(1,"This should work"));
	EXPECT_TRUE(Log::LogEvent(2,"This should work"));
	EXPECT_TRUE(Log::LogEvent(3,"This should work"));
	EXPECT_TRUE(Log::Finalize());
}
<|endoftext|>