<commit_before>// Copyright (c) 2011 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 "chrome/browser/ui/webui/options/core_options_handler.h"

#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/user_metrics.h"
#include "content/common/content_notification_types.h"
#include "content/common/notification_details.h"
#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

DictionaryValue* CreateValueForPref(const PrefService::Preference* pref) {
  DictionaryValue* dict = new DictionaryValue;
  dict->Set("value", pref->GetValue()->DeepCopy());
  if (pref->IsManaged()) {
    dict->SetString("controlledBy", "policy");
  } else if (pref->IsExtensionControlled()) {
    dict->SetString("controlledBy", "extension");
  }
  dict->SetBoolean("disabled", !pref->IsUserModifiable());
  return dict;
}

}  // namespace

CoreOptionsHandler::CoreOptionsHandler()
    : handlers_host_(NULL) {
}

CoreOptionsHandler::~CoreOptionsHandler() {}

void CoreOptionsHandler::Initialize() {
  clear_plugin_lso_data_enabled_.Init(prefs::kClearPluginLSODataEnabled,
                                      g_browser_process->local_state(),
                                      this);
  UpdateClearPluginLSOData();
}

void CoreOptionsHandler::GetLocalizedValues(
    DictionaryValue* localized_strings) {
  DCHECK(localized_strings);
  // Main
  localized_strings->SetString("title",
      l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));

  // Managed prefs
  localized_strings->SetString("policyManagedPrefsBannerText",
      l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_MANAGED_PREFS));
  localized_strings->SetString("extensionManagedPrefsBannerText",
      l10n_util::GetStringUTF16(IDS_OPTIONS_EXTENSION_MANAGED_PREFS));
  localized_strings->SetString("policyAndExtensionManagedPrefsBannerText",
      l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_EXTENSION_MANAGED_PREFS));

  // Search
  RegisterTitle(localized_strings, "searchPage", IDS_OPTIONS_SEARCH_PAGE_TITLE);
  localized_strings->SetString("searchPlaceholder",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PLACEHOLDER));
  localized_strings->SetString("searchPageNoMatches",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_NO_MATCHES));
  localized_strings->SetString("searchPageHelpLabel",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_LABEL));
  localized_strings->SetString("searchPageHelpTitle",
      l10n_util::GetStringFUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_TITLE,
          l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
  localized_strings->SetString("searchPageHelpURL",
      google_util::AppendGoogleLocaleParam(
          GURL(chrome::kChromeHelpURL)).spec());

  // Common
  localized_strings->SetString("ok",
      l10n_util::GetStringUTF16(IDS_OK));
  localized_strings->SetString("cancel",
      l10n_util::GetStringUTF16(IDS_CANCEL));
  localized_strings->SetString("learnMore",
      l10n_util::GetStringUTF16(IDS_LEARN_MORE));
  localized_strings->SetString("close",
      l10n_util::GetStringUTF16(IDS_CLOSE));
}

void CoreOptionsHandler::Uninitialize() {
  std::string last_pref;
  for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin();
       iter != pref_callback_map_.end();
       ++iter) {
    if (last_pref != iter->first) {
      StopObservingPref(iter->first);
      last_pref = iter->first;
    }
  }
}

WebUIMessageHandler* CoreOptionsHandler::Attach(WebUI* web_ui) {
  WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
  DCHECK(web_ui_);
  registrar_.Init(web_ui_->GetProfile()->GetPrefs());
  return result;
}

void CoreOptionsHandler::Observe(int type,
                                 const NotificationSource& source,
                                 const NotificationDetails& details) {
  if (type == chrome::NOTIFICATION_PREF_CHANGED)
    NotifyPrefChanged(Details<std::string>(details).ptr());
}

void CoreOptionsHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("coreOptionsInitialize",
      NewCallback(this, &CoreOptionsHandler::HandleInitialize));
  web_ui_->RegisterMessageCallback("fetchPrefs",
      NewCallback(this, &CoreOptionsHandler::HandleFetchPrefs));
  web_ui_->RegisterMessageCallback("observePrefs",
      NewCallback(this, &CoreOptionsHandler::HandleObservePrefs));
  web_ui_->RegisterMessageCallback("setBooleanPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetBooleanPref));
  web_ui_->RegisterMessageCallback("setIntegerPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetIntegerPref));
  web_ui_->RegisterMessageCallback("setDoublePref",
      NewCallback(this, &CoreOptionsHandler::HandleSetDoublePref));
  web_ui_->RegisterMessageCallback("setStringPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetStringPref));
  web_ui_->RegisterMessageCallback("setListPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetListPref));
  web_ui_->RegisterMessageCallback("clearPref",
      NewCallback(this, &CoreOptionsHandler::HandleClearPref));
  web_ui_->RegisterMessageCallback("coreOptionsUserMetricsAction",
      NewCallback(this, &CoreOptionsHandler::HandleUserMetricsAction));
}

void CoreOptionsHandler::HandleInitialize(const ListValue* args) {
  DCHECK(handlers_host_);
  handlers_host_->InitializeHandlers();
}

Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) {
  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();

  const PrefService::Preference* pref =
      pref_service->FindPreference(pref_name.c_str());
  if (!pref)
    return Value::CreateNullValue();

  return CreateValueForPref(pref);
}

void CoreOptionsHandler::ObservePref(const std::string& pref_name) {
  registrar_.Add(pref_name.c_str(), this);
}

void CoreOptionsHandler::SetPref(const std::string& pref_name,
                                 const Value* value,
                                 const std::string& metric) {
  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();

  switch (value->GetType()) {
    case Value::TYPE_BOOLEAN:
    case Value::TYPE_INTEGER:
    case Value::TYPE_DOUBLE:
    case Value::TYPE_STRING:
      pref_service->Set(pref_name.c_str(), *value);
      break;

    default:
      NOTREACHED();
      return;
  }

  pref_service->ScheduleSavePersistentPrefs();
  ProcessUserMetric(value, metric);
}

void CoreOptionsHandler::ClearPref(const std::string& pref_name,
                                   const std::string& metric) {
  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
  pref_service->ClearPref(pref_name.c_str());
  pref_service->ScheduleSavePersistentPrefs();

  if (!metric.empty())
    UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
}

void CoreOptionsHandler::ProcessUserMetric(const Value* value,
                                           const std::string& metric) {
  if (metric.empty())
    return;

  std::string metric_string = metric;
  if (value->IsType(Value::TYPE_BOOLEAN)) {
    bool bool_value;
    CHECK(value->GetAsBoolean(&bool_value));
    metric_string += bool_value ? "_Enable" : "_Disable";
  }

  UserMetricsRecordAction(UserMetricsAction(metric_string.c_str()));
}

void CoreOptionsHandler::StopObservingPref(const std::string& path) {
  registrar_.Remove(path.c_str(), this);
}

void CoreOptionsHandler::HandleFetchPrefs(const ListValue* args) {
  // First param is name of callback function, so, there needs to be at least
  // one more element for the actual preference identifier.
  DCHECK_GE(static_cast<int>(args->GetSize()), 2);

  // Get callback JS function name.
  Value* callback;
  if (!args->Get(0, &callback) || !callback->IsType(Value::TYPE_STRING))
    return;

  string16 callback_function;
  if (!callback->GetAsString(&callback_function))
    return;

  // Get the list of name for prefs to build the response dictionary.
  DictionaryValue result_value;
  Value* list_member;

  for (size_t i = 1; i < args->GetSize(); i++) {
    if (!args->Get(i, &list_member))
      break;

    if (!list_member->IsType(Value::TYPE_STRING))
      continue;

    std::string pref_name;
    if (!list_member->GetAsString(&pref_name))
      continue;

    result_value.Set(pref_name.c_str(), FetchPref(pref_name));
  }
  web_ui_->CallJavascriptFunction(UTF16ToASCII(callback_function),
                                  result_value);
}

void CoreOptionsHandler::HandleObservePrefs(const ListValue* args) {
  // First param is name is JS callback function name, the rest are pref
  // identifiers that we are observing.
  DCHECK_GE(static_cast<int>(args->GetSize()), 2);

  // Get preference change callback function name.
  string16 callback_func_name;
  if (!args->GetString(0, &callback_func_name))
    return;

  // Get all other parameters - pref identifiers.
  for (size_t i = 1; i < args->GetSize(); i++) {
    Value* list_member;
    if (!args->Get(i, &list_member))
      break;

    // Just ignore bad pref identifiers for now.
    std::string pref_name;
    if (!list_member->IsType(Value::TYPE_STRING) ||
        !list_member->GetAsString(&pref_name))
      continue;

    if (pref_callback_map_.find(pref_name) == pref_callback_map_.end())
      ObservePref(pref_name);

    pref_callback_map_.insert(
        PreferenceCallbackMap::value_type(pref_name,
                                          UTF16ToWideHack(callback_func_name)));
  }
}

void CoreOptionsHandler::HandleSetBooleanPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_BOOLEAN);
}

void CoreOptionsHandler::HandleSetIntegerPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_INTEGER);
}

void CoreOptionsHandler::HandleSetDoublePref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_DOUBLE);
}

void CoreOptionsHandler::HandleSetStringPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_STRING);
}

void CoreOptionsHandler::HandleSetListPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_LIST);
}

void CoreOptionsHandler::HandleSetPref(const ListValue* args,
                                       Value::ValueType type) {
  DCHECK_GT(static_cast<int>(args->GetSize()), 1);

  std::string pref_name;
  if (!args->GetString(0, &pref_name))
    return;

  Value* value;
  if (!args->Get(1, &value))
    return;

  scoped_ptr<Value> temp_value;

  // In JS all numbers are doubles.
  if (type == Value::TYPE_INTEGER) {
    double double_value;
    CHECK(value->GetAsDouble(&double_value));
    temp_value.reset(Value::CreateIntegerValue(static_cast<int>(double_value)));
    value = temp_value.get();

  // In case we have a List pref we got a JSON string.
  } else if (type == Value::TYPE_LIST) {
    std::string json_string;
    CHECK(value->GetAsString(&json_string));
    temp_value.reset(
        base::JSONReader().JsonToValue(json_string,
                                       false,  // no check_root
                                       false));  // no trailing comma
    value = temp_value.get();
  }

  CHECK_EQ(type, value->GetType());

  std::string metric;
  if (args->GetSize() > 2 && !args->GetString(2, &metric))
    LOG(WARNING) << "Invalid metric parameter: " << pref_name;
  SetPref(pref_name, value, metric);
}

void CoreOptionsHandler::HandleClearPref(const ListValue* args) {
  DCHECK_GT(static_cast<int>(args->GetSize()), 0);

  std::string pref_name;
  if (!args->GetString(0, &pref_name))
    return;

  std::string metric;
  if (args->GetSize() > 1)
    args->GetString(1, &metric);

  ClearPref(pref_name, metric);
}

void CoreOptionsHandler::HandleUserMetricsAction(const ListValue* args) {
  std::string metric = UTF16ToUTF8(ExtractStringValue(args));
  if (!metric.empty())
    UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
}

void CoreOptionsHandler::UpdateClearPluginLSOData() {
  scoped_ptr<Value> enabled(
      Value::CreateBooleanValue(clear_plugin_lso_data_enabled_.GetValue()));
  web_ui_->CallJavascriptFunction(
      "OptionsPage.setClearPluginLSODataEnabled", *enabled);
}

void CoreOptionsHandler::NotifyPrefChanged(const std::string* pref_name) {
  if (*pref_name == prefs::kClearPluginLSODataEnabled) {
    // This preference is stored in Local State, not in the user preferences.
    UpdateClearPluginLSOData();
    return;
  }

  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
  const PrefService::Preference* pref =
      pref_service->FindPreference(pref_name->c_str());
  if (!pref)
    return;

  for (PreferenceCallbackMap::const_iterator iter =
      pref_callback_map_.find(*pref_name);
      iter != pref_callback_map_.end(); ++iter) {
    const std::wstring& callback_function = iter->second;
    ListValue result_value;
    result_value.Append(Value::CreateStringValue(pref_name->c_str()));

    result_value.Append(CreateValueForPref(pref));

    web_ui_->CallJavascriptFunction(WideToASCII(callback_function),
                                    result_value);
  }
}
<commit_msg>Fixed duplicate event notification for preference changes on a webui.<commit_after>// Copyright (c) 2011 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 "chrome/browser/ui/webui/options/core_options_handler.h"

#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/browser/user_metrics.h"
#include "content/common/content_notification_types.h"
#include "content/common/notification_details.h"
#include "googleurl/src/gurl.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace {

DictionaryValue* CreateValueForPref(const PrefService::Preference* pref) {
  DictionaryValue* dict = new DictionaryValue;
  dict->Set("value", pref->GetValue()->DeepCopy());
  if (pref->IsManaged()) {
    dict->SetString("controlledBy", "policy");
  } else if (pref->IsExtensionControlled()) {
    dict->SetString("controlledBy", "extension");
  }
  dict->SetBoolean("disabled", !pref->IsUserModifiable());
  return dict;
}

}  // namespace

CoreOptionsHandler::CoreOptionsHandler()
    : handlers_host_(NULL) {
}

CoreOptionsHandler::~CoreOptionsHandler() {}

void CoreOptionsHandler::Initialize() {
  clear_plugin_lso_data_enabled_.Init(prefs::kClearPluginLSODataEnabled,
                                      g_browser_process->local_state(),
                                      this);
  UpdateClearPluginLSOData();
}

void CoreOptionsHandler::GetLocalizedValues(
    DictionaryValue* localized_strings) {
  DCHECK(localized_strings);
  // Main
  localized_strings->SetString("title",
      l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));

  // Managed prefs
  localized_strings->SetString("policyManagedPrefsBannerText",
      l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_MANAGED_PREFS));
  localized_strings->SetString("extensionManagedPrefsBannerText",
      l10n_util::GetStringUTF16(IDS_OPTIONS_EXTENSION_MANAGED_PREFS));
  localized_strings->SetString("policyAndExtensionManagedPrefsBannerText",
      l10n_util::GetStringUTF16(IDS_OPTIONS_POLICY_EXTENSION_MANAGED_PREFS));

  // Search
  RegisterTitle(localized_strings, "searchPage", IDS_OPTIONS_SEARCH_PAGE_TITLE);
  localized_strings->SetString("searchPlaceholder",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PLACEHOLDER));
  localized_strings->SetString("searchPageNoMatches",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_NO_MATCHES));
  localized_strings->SetString("searchPageHelpLabel",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_LABEL));
  localized_strings->SetString("searchPageHelpTitle",
      l10n_util::GetStringFUTF16(IDS_OPTIONS_SEARCH_PAGE_HELP_TITLE,
          l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
  localized_strings->SetString("searchPageHelpURL",
      google_util::AppendGoogleLocaleParam(
          GURL(chrome::kChromeHelpURL)).spec());

  // Common
  localized_strings->SetString("ok",
      l10n_util::GetStringUTF16(IDS_OK));
  localized_strings->SetString("cancel",
      l10n_util::GetStringUTF16(IDS_CANCEL));
  localized_strings->SetString("learnMore",
      l10n_util::GetStringUTF16(IDS_LEARN_MORE));
  localized_strings->SetString("close",
      l10n_util::GetStringUTF16(IDS_CLOSE));
}

void CoreOptionsHandler::Uninitialize() {
  std::string last_pref;
  for (PreferenceCallbackMap::const_iterator iter = pref_callback_map_.begin();
       iter != pref_callback_map_.end();
       ++iter) {
    if (last_pref != iter->first) {
      StopObservingPref(iter->first);
      last_pref = iter->first;
    }
  }
}

WebUIMessageHandler* CoreOptionsHandler::Attach(WebUI* web_ui) {
  WebUIMessageHandler* result = WebUIMessageHandler::Attach(web_ui);
  DCHECK(web_ui_);
  registrar_.Init(web_ui_->GetProfile()->GetPrefs());
  return result;
}

void CoreOptionsHandler::Observe(int type,
                                 const NotificationSource& source,
                                 const NotificationDetails& details) {
  if (type == chrome::NOTIFICATION_PREF_CHANGED)
    NotifyPrefChanged(Details<std::string>(details).ptr());
}

void CoreOptionsHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("coreOptionsInitialize",
      NewCallback(this, &CoreOptionsHandler::HandleInitialize));
  web_ui_->RegisterMessageCallback("fetchPrefs",
      NewCallback(this, &CoreOptionsHandler::HandleFetchPrefs));
  web_ui_->RegisterMessageCallback("observePrefs",
      NewCallback(this, &CoreOptionsHandler::HandleObservePrefs));
  web_ui_->RegisterMessageCallback("setBooleanPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetBooleanPref));
  web_ui_->RegisterMessageCallback("setIntegerPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetIntegerPref));
  web_ui_->RegisterMessageCallback("setDoublePref",
      NewCallback(this, &CoreOptionsHandler::HandleSetDoublePref));
  web_ui_->RegisterMessageCallback("setStringPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetStringPref));
  web_ui_->RegisterMessageCallback("setListPref",
      NewCallback(this, &CoreOptionsHandler::HandleSetListPref));
  web_ui_->RegisterMessageCallback("clearPref",
      NewCallback(this, &CoreOptionsHandler::HandleClearPref));
  web_ui_->RegisterMessageCallback("coreOptionsUserMetricsAction",
      NewCallback(this, &CoreOptionsHandler::HandleUserMetricsAction));
}

void CoreOptionsHandler::HandleInitialize(const ListValue* args) {
  DCHECK(handlers_host_);
  handlers_host_->InitializeHandlers();
}

Value* CoreOptionsHandler::FetchPref(const std::string& pref_name) {
  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();

  const PrefService::Preference* pref =
      pref_service->FindPreference(pref_name.c_str());
  if (!pref)
    return Value::CreateNullValue();

  return CreateValueForPref(pref);
}

void CoreOptionsHandler::ObservePref(const std::string& pref_name) {
  registrar_.Add(pref_name.c_str(), this);
}

void CoreOptionsHandler::SetPref(const std::string& pref_name,
                                 const Value* value,
                                 const std::string& metric) {
  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();

  switch (value->GetType()) {
    case Value::TYPE_BOOLEAN:
    case Value::TYPE_INTEGER:
    case Value::TYPE_DOUBLE:
    case Value::TYPE_STRING:
      pref_service->Set(pref_name.c_str(), *value);
      break;

    default:
      NOTREACHED();
      return;
  }

  pref_service->ScheduleSavePersistentPrefs();
  ProcessUserMetric(value, metric);
}

void CoreOptionsHandler::ClearPref(const std::string& pref_name,
                                   const std::string& metric) {
  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
  pref_service->ClearPref(pref_name.c_str());
  pref_service->ScheduleSavePersistentPrefs();

  if (!metric.empty())
    UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
}

void CoreOptionsHandler::ProcessUserMetric(const Value* value,
                                           const std::string& metric) {
  if (metric.empty())
    return;

  std::string metric_string = metric;
  if (value->IsType(Value::TYPE_BOOLEAN)) {
    bool bool_value;
    CHECK(value->GetAsBoolean(&bool_value));
    metric_string += bool_value ? "_Enable" : "_Disable";
  }

  UserMetricsRecordAction(UserMetricsAction(metric_string.c_str()));
}

void CoreOptionsHandler::StopObservingPref(const std::string& path) {
  registrar_.Remove(path.c_str(), this);
}

void CoreOptionsHandler::HandleFetchPrefs(const ListValue* args) {
  // First param is name of callback function, so, there needs to be at least
  // one more element for the actual preference identifier.
  DCHECK_GE(static_cast<int>(args->GetSize()), 2);

  // Get callback JS function name.
  Value* callback;
  if (!args->Get(0, &callback) || !callback->IsType(Value::TYPE_STRING))
    return;

  string16 callback_function;
  if (!callback->GetAsString(&callback_function))
    return;

  // Get the list of name for prefs to build the response dictionary.
  DictionaryValue result_value;
  Value* list_member;

  for (size_t i = 1; i < args->GetSize(); i++) {
    if (!args->Get(i, &list_member))
      break;

    if (!list_member->IsType(Value::TYPE_STRING))
      continue;

    std::string pref_name;
    if (!list_member->GetAsString(&pref_name))
      continue;

    result_value.Set(pref_name.c_str(), FetchPref(pref_name));
  }
  web_ui_->CallJavascriptFunction(UTF16ToASCII(callback_function),
                                  result_value);
}

void CoreOptionsHandler::HandleObservePrefs(const ListValue* args) {
  // First param is name is JS callback function name, the rest are pref
  // identifiers that we are observing.
  DCHECK_GE(static_cast<int>(args->GetSize()), 2);

  // Get preference change callback function name.
  string16 callback_func_name;
  if (!args->GetString(0, &callback_func_name))
    return;

  // Get all other parameters - pref identifiers.
  for (size_t i = 1; i < args->GetSize(); i++) {
    Value* list_member;
    if (!args->Get(i, &list_member))
      break;

    // Just ignore bad pref identifiers for now.
    std::string pref_name;
    if (!list_member->IsType(Value::TYPE_STRING) ||
        !list_member->GetAsString(&pref_name))
      continue;

    if (pref_callback_map_.find(pref_name) == pref_callback_map_.end())
      ObservePref(pref_name);

    pref_callback_map_.insert(
        PreferenceCallbackMap::value_type(pref_name,
                                          UTF16ToWideHack(callback_func_name)));
  }
}

void CoreOptionsHandler::HandleSetBooleanPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_BOOLEAN);
}

void CoreOptionsHandler::HandleSetIntegerPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_INTEGER);
}

void CoreOptionsHandler::HandleSetDoublePref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_DOUBLE);
}

void CoreOptionsHandler::HandleSetStringPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_STRING);
}

void CoreOptionsHandler::HandleSetListPref(const ListValue* args) {
  HandleSetPref(args, Value::TYPE_LIST);
}

void CoreOptionsHandler::HandleSetPref(const ListValue* args,
                                       Value::ValueType type) {
  DCHECK_GT(static_cast<int>(args->GetSize()), 1);

  std::string pref_name;
  if (!args->GetString(0, &pref_name))
    return;

  Value* value;
  if (!args->Get(1, &value))
    return;

  scoped_ptr<Value> temp_value;

  // In JS all numbers are doubles.
  if (type == Value::TYPE_INTEGER) {
    double double_value;
    CHECK(value->GetAsDouble(&double_value));
    temp_value.reset(Value::CreateIntegerValue(static_cast<int>(double_value)));
    value = temp_value.get();

  // In case we have a List pref we got a JSON string.
  } else if (type == Value::TYPE_LIST) {
    std::string json_string;
    CHECK(value->GetAsString(&json_string));
    temp_value.reset(
        base::JSONReader().JsonToValue(json_string,
                                       false,  // no check_root
                                       false));  // no trailing comma
    value = temp_value.get();
  }

  CHECK_EQ(type, value->GetType());

  std::string metric;
  if (args->GetSize() > 2 && !args->GetString(2, &metric))
    LOG(WARNING) << "Invalid metric parameter: " << pref_name;
  SetPref(pref_name, value, metric);
}

void CoreOptionsHandler::HandleClearPref(const ListValue* args) {
  DCHECK_GT(static_cast<int>(args->GetSize()), 0);

  std::string pref_name;
  if (!args->GetString(0, &pref_name))
    return;

  std::string metric;
  if (args->GetSize() > 1)
    args->GetString(1, &metric);

  ClearPref(pref_name, metric);
}

void CoreOptionsHandler::HandleUserMetricsAction(const ListValue* args) {
  std::string metric = UTF16ToUTF8(ExtractStringValue(args));
  if (!metric.empty())
    UserMetricsRecordAction(UserMetricsAction(metric.c_str()));
}

void CoreOptionsHandler::UpdateClearPluginLSOData() {
  scoped_ptr<Value> enabled(
      Value::CreateBooleanValue(clear_plugin_lso_data_enabled_.GetValue()));
  web_ui_->CallJavascriptFunction(
      "OptionsPage.setClearPluginLSODataEnabled", *enabled);
}

void CoreOptionsHandler::NotifyPrefChanged(const std::string* pref_name) {
  if (*pref_name == prefs::kClearPluginLSODataEnabled) {
    // This preference is stored in Local State, not in the user preferences.
    UpdateClearPluginLSOData();
    return;
  }

  PrefService* pref_service = web_ui_->GetProfile()->GetPrefs();
  const PrefService::Preference* pref =
      pref_service->FindPreference(pref_name->c_str());
  if (!pref)
    return;

  std::pair<PreferenceCallbackMap::const_iterator,
            PreferenceCallbackMap::const_iterator> range;
  range = pref_callback_map_.equal_range(*pref_name);
  for (PreferenceCallbackMap::const_iterator iter = range.first;
       iter != range.second; ++iter) {
    const std::wstring& callback_function = iter->second;
    ListValue result_value;
    result_value.Append(Value::CreateStringValue(pref_name->c_str()));

    result_value.Append(CreateValueForPref(pref));

    web_ui_->CallJavascriptFunction(WideToASCII(callback_function),
                                    result_value);
  }
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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 OWNER 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 <modules/plotting/processors/volumetodataframe.h>
#include <inviwo/core/datastructures/volume/volumeram.h>
#include <inviwo/core/datastructures/volume/volumeramprecision.h>

namespace inviwo {

namespace plot {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo VolumeToDataFrame::processorInfo_{
    "org.inviwo.VolumeToDataFrame",  // Class identifier
    "Volume To DataFrame",           // Display name
    "Data Creation",                 // Category
    CodeState::Stable,               // Code state
    "CPU, DataFrame, Volume",        // Tags
};
const ProcessorInfo VolumeToDataFrame::getProcessorInfo() const { return processorInfo_; }

VolumeToDataFrame::VolumeToDataFrame()
    : Processor()
    , inport_{"volume"}
    , outport_{"dataframe"}

    , mode_{"mode",
            "Mode",
            {{"analytics", "Analytics", Mode::Analytics},
             {"xdir", "XDir", Mode::XDir},
             {"ydir", "YDir", Mode::YDir},
             {"zdir", "ZDir", Mode::ZDir}},
            0}
    , rangeX_{"xrange", "X Range", 0, 1, 0, 1, 1, 1}
    , rangeY_{"yrange", "Y Range", 0, 1, 0, 1, 1, 1}
    , rangeZ_{"zrange", "Z Range", 0, 1, 0, 1, 1, 1} {

    addPort(inport_);
    addPort(outport_);
    addProperty(mode_);
    addProperty(rangeX_);
    addProperty(rangeY_);
    addProperty(rangeZ_);

    inport_.onChange([this]() {
        if (inport_.hasData()) {
            const auto dim = inport_.getData()->getDimensions();
            rangeX_.setRangeMax(dim.x);
            rangeY_.setRangeMax(dim.y);
            rangeZ_.setRangeMax(dim.z);
        }
    });
}

void VolumeToDataFrame::process() {
    const auto volume = inport_.getData();
    const auto dim = volume->getDimensions();
    switch (mode_.get()) {
        case Mode::Analytics: {
            const auto size = (rangeX_.getEnd() - rangeX_.getStart()) *
                              (rangeY_.getEnd() - rangeY_.getStart()) *
                              (rangeZ_.getEnd() - rangeZ_.getStart());

            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));
            std::vector<std::vector<float>*> channelBuffer_;
            const auto numCh = volume->getDataFormat()->getComponents();
            for (size_t c = 0; c < numCh; c++) {
                auto col = dataFrame->addColumn<float>("Channel " + toString(c + 1), size);
                channelBuffer_.push_back(
                    &col->getTypedBuffer()->getEditableRAMRepresentation()->getDataContainer());
            }
            auto& magnitudes = dataFrame->addColumn<float>("Magnitude", size)
                                   ->getTypedBuffer()
                                   ->getEditableRAMRepresentation()
                                   ->getDataContainer();
            auto& indx = dataFrame->addColumn<int>("Index X", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& indy = dataFrame->addColumn<int>("Index Y", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& indz = dataFrame->addColumn<int>("Index Z", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& posx = dataFrame->addColumn<float>("Position X", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& posy = dataFrame->addColumn<float>("Position Y", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& posz = dataFrame->addColumn<float>("Position Z", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();

            const auto indexToModel = volume->getCoordinateTransformer().getIndexToModelMatrix();

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([&](auto vr) {
                const auto im = util::IndexMapper3D(dim);
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto data = vr->getDataTyped();
                auto i = 0;
                size3_t ind;
                for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                    for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                        for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                            const auto v = util::glm_convert<dvec4>(data[im(ind)]);
                            double m = 0.0;
                            for (size_t c = 0; c < DataFormat<ValueType>::comp; c++) {
                                (*channelBuffer_[c])[i] = static_cast<float>(v[c]);
                                m += v[c] * v[c];
                            }
                            magnitudes[i] = static_cast<float>(std::sqrt(m));

                            indx[i] = static_cast<int>(ind.x);
                            indy[i] = static_cast<int>(ind.y);
                            indz[i] = static_cast<int>(ind.z);

                            const dvec3 pos{indexToModel * dvec4{ind, 1}};

                            posx[i] = static_cast<float>(pos.x);
                            posy[i] = static_cast<float>(pos.y);
                            posz[i] = static_cast<float>(pos.z);
                            ++i;
                        }
                    }
                }
            });
            outport_.setData(dataFrame);
            break;
        }
        case Mode::XDir: {
            const auto size = rangeX_.getEnd() - rangeX_.getStart();
            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([&](const auto vr) {
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto im = util::IndexMapper3D(dim);
                const auto data = vr->getDataTyped();
                size3_t ind;
                for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                    for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                        auto col = dataFrame->addColumn<ValueType>(
                            "y:" + toString(ind.y) + " z:" + toString(ind.z), size);
                        auto& line = col->getTypedBuffer()
                                         ->getEditableRAMRepresentation()
                                         ->getDataContainer();
                        size_t i = 0;
                        for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                            line[i++] = data[im(ind)];
                        }
                    }
                }
            });

            outport_.setData(dataFrame);
            break;
        }
        case Mode::YDir: {
            const auto size = rangeY_.getEnd() - rangeY_.getStart();
            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([&](const auto vr) {
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto im = util::IndexMapper3D(dim);
                const auto data = vr->getDataTyped();
                size3_t ind;
                for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                    for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                        auto col = dataFrame->addColumn<ValueType>(
                            "x:" + toString(ind.x) + " z:" + toString(ind.z), size);
                        auto& line = col->getTypedBuffer()
                                         ->getEditableRAMRepresentation()
                                         ->getDataContainer();
                        size_t i = 0;
                        for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                            line[i++] = data[im(ind)];
                        }
                    }
                }
            });

            outport_.setData(dataFrame);
            break;
        }
        case Mode::ZDir: {
            const auto size = rangeZ_.getEnd() - rangeZ_.getStart();
            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([&](const auto vr) {
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto im = util::IndexMapper3D(dim);
                const auto data = vr->getDataTyped();
                size3_t ind;
                for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                    for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                        auto col = dataFrame->addColumn<ValueType>(
                            "x:" + toString(ind.x) + " y:" + toString(ind.y), size);
                        auto& line = col->getTypedBuffer()
                                         ->getEditableRAMRepresentation()
                                         ->getDataContainer();
                        size_t i = 0;
                        for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                            line[i++] = data[im(ind)];
                        }
                    }
                }
            });

            outport_.setData(dataFrame);
            break;
        }
    }
}

}  // namespace plot

}  // namespace inviwo
<commit_msg>Plotting: gcc-test<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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 OWNER 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 <modules/plotting/processors/volumetodataframe.h>
#include <inviwo/core/datastructures/volume/volumeram.h>
#include <inviwo/core/datastructures/volume/volumeramprecision.h>

namespace inviwo {

namespace plot {

// The Class Identifier has to be globally unique. Use a reverse DNS naming scheme
const ProcessorInfo VolumeToDataFrame::processorInfo_{
    "org.inviwo.VolumeToDataFrame",  // Class identifier
    "Volume To DataFrame",           // Display name
    "Data Creation",                 // Category
    CodeState::Stable,               // Code state
    "CPU, DataFrame, Volume",        // Tags
};
const ProcessorInfo VolumeToDataFrame::getProcessorInfo() const { return processorInfo_; }

VolumeToDataFrame::VolumeToDataFrame()
    : Processor()
    , inport_{"volume"}
    , outport_{"dataframe"}

    , mode_{"mode",
            "Mode",
            {{"analytics", "Analytics", Mode::Analytics},
             {"xdir", "XDir", Mode::XDir},
             {"ydir", "YDir", Mode::YDir},
             {"zdir", "ZDir", Mode::ZDir}},
            0}
    , rangeX_{"xrange", "X Range", 0, 1, 0, 1, 1, 1}
    , rangeY_{"yrange", "Y Range", 0, 1, 0, 1, 1, 1}
    , rangeZ_{"zrange", "Z Range", 0, 1, 0, 1, 1, 1} {

    addPort(inport_);
    addPort(outport_);
    addProperty(mode_);
    addProperty(rangeX_);
    addProperty(rangeY_);
    addProperty(rangeZ_);

    inport_.onChange([this]() {
        if (inport_.hasData()) {
            const auto dim = inport_.getData()->getDimensions();
            rangeX_.setRangeMax(dim.x);
            rangeY_.setRangeMax(dim.y);
            rangeZ_.setRangeMax(dim.z);
        }
    });
}

void VolumeToDataFrame::process() {
    const auto volume = inport_.getData();
    switch (mode_.get()) {
        case Mode::Analytics: {
            const auto size = (rangeX_.getEnd() - rangeX_.getStart()) *
                              (rangeY_.getEnd() - rangeY_.getStart()) *
                              (rangeZ_.getEnd() - rangeZ_.getStart());

            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));
            std::vector<std::vector<float>*> channelBuffer_;
            const auto numCh = volume->getDataFormat()->getComponents();
            for (size_t c = 0; c < numCh; c++) {
                auto col = dataFrame->addColumn<float>("Channel " + toString(c + 1), size);
                channelBuffer_.push_back(
                    &col->getTypedBuffer()->getEditableRAMRepresentation()->getDataContainer());
            }
            auto& magnitudes = dataFrame->addColumn<float>("Magnitude", size)
                                   ->getTypedBuffer()
                                   ->getEditableRAMRepresentation()
                                   ->getDataContainer();
            auto& indx = dataFrame->addColumn<int>("Index X", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& indy = dataFrame->addColumn<int>("Index Y", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& indz = dataFrame->addColumn<int>("Index Z", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& posx = dataFrame->addColumn<float>("Position X", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& posy = dataFrame->addColumn<float>("Position Y", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();
            auto& posz = dataFrame->addColumn<float>("Position Z", size)
                             ->getTypedBuffer()
                             ->getEditableRAMRepresentation()
                             ->getDataContainer();

            const auto indexToModel = volume->getCoordinateTransformer().getIndexToModelMatrix();

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([&](auto vr) {
                const auto im = util::IndexMapper3D(vr->getDimensions());
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto data = vr->getDataTyped();
                auto i = 0;
                size3_t ind;
                for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                    for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                        for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                            const auto v = util::glm_convert<dvec4>(data[im(ind)]);
                            double m = 0.0;
                            for (size_t c = 0; c < DataFormat<ValueType>::comp; c++) {
                                (*channelBuffer_[c])[i] = static_cast<float>(v[c]);
                                m += v[c] * v[c];
                            }
                            magnitudes[i] = static_cast<float>(std::sqrt(m));

                            indx[i] = static_cast<int>(ind.x);
                            indy[i] = static_cast<int>(ind.y);
                            indz[i] = static_cast<int>(ind.z);

                            const dvec3 pos{indexToModel * dvec4{ind, 1}};

                            posx[i] = static_cast<float>(pos.x);
                            posy[i] = static_cast<float>(pos.y);
                            posz[i] = static_cast<float>(pos.z);
                            ++i;
                        }
                    }
                }
            });
            outport_.setData(dataFrame);
            break;
        }
        case Mode::XDir: {
            auto dataFrame =
                volume->getRepresentation<VolumeRAM>()->dispatch<std::shared_ptr<plot::DataFrame>>(
                    [this](const auto vr) {
                        using ValueType = util::PrecsionValueType<decltype(vr)>;
                        const auto size = rangeX_.getEnd() - rangeY_.getStart();
                        auto df = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));
                        const auto im = util::IndexMapper3D(vr->getDimensions());
                        const auto data = vr->getDataTyped();
                        size3_t ind;
                        for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                            for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                                const std::string name =
                                    "y:" + toString(ind.y) + " z:" + toString(ind.z);
                                auto col = df->addColumn<ValueType>(name, size);
                                auto& line = col->getTypedBuffer()
                                                 ->getEditableRAMRepresentation()
                                                 ->getDataContainer();
                                size_t i = 0;
                                for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd();
                                     ind.x++) {
                                    line[i++] = data[im(ind)];
                                }
                            }
                        }
                        return df;
                    });

            outport_.setData(dataFrame);
            break;
        }
        case Mode::YDir: {
            const auto size = rangeY_.getEnd() - rangeY_.getStart();
            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([this, dataFrame, size](const auto vr) {
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto im = util::IndexMapper3D(vr->getDimensions());
                const auto data = vr->getDataTyped();
                size3_t ind;
                for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                    for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                        auto col = dataFrame->addColumn<ValueType>(
                            "x:" + toString(ind.x) + " z:" + toString(ind.z), size);
                        auto& line = col->getTypedBuffer()
                                         ->getEditableRAMRepresentation()
                                         ->getDataContainer();
                        size_t i = 0;
                        for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                            line[i++] = data[im(ind)];
                        }
                    }
                }
            });

            outport_.setData(dataFrame);
            break;
        }
        case Mode::ZDir: {
            const auto size = rangeZ_.getEnd() - rangeZ_.getStart();
            auto dataFrame = std::make_shared<plot::DataFrame>(static_cast<glm::u32>(size));

            volume->getRepresentation<VolumeRAM>()->dispatch<void>([&](const auto vr) {
                using ValueType = util::PrecsionValueType<decltype(vr)>;
                const auto im = util::IndexMapper3D(vr->getDimensions());
                const auto data = vr->getDataTyped();
                size3_t ind;
                for (ind.x = rangeX_.getStart(); ind.x < rangeX_.getEnd(); ind.x++) {
                    for (ind.y = rangeY_.getStart(); ind.y < rangeY_.getEnd(); ind.y++) {
                        auto col = dataFrame->addColumn<ValueType>(
                            "x:" + toString(ind.x) + " y:" + toString(ind.y), size);
                        auto& line = col->getTypedBuffer()
                                         ->getEditableRAMRepresentation()
                                         ->getDataContainer();
                        size_t i = 0;
                        for (ind.z = rangeZ_.getStart(); ind.z < rangeZ_.getEnd(); ind.z++) {
                            line[i++] = data[im(ind)];
                        }
                    }
                }
            });

            outport_.setData(dataFrame);
            break;
        }
    }
}

}  // namespace plot

}  // namespace inviwo
<|endoftext|>


<commit_before><commit_msg>FEM: cpp commands sort constraints, pressure<commit_after><|endoftext|>


<commit_before>#include "GeometricalComponent.h"
#include "Conversion.h"
#include "ConstantFunction.h"

template<>
InputParameters validParams<GeometricalComponent>()
{
  InputParameters params = validParams<Component>();

  params.addRequiredParam<Point>("position", "Origin (start) of the pipe");
  params.addParam<RealVectorValue>("offset", RealVectorValue(), "Offset of the origin for mesh generation");
  params.addRequiredParam<RealVectorValue>("orientation", "Orientation vector of the pipe");
  params.addParam<Real>("rotation", 0., "Rotation of the component (in degrees)");

  params.addRequiredParam<Real>("length", "The length of the geometric component along the main axis");

  params.addParam<unsigned int>("n_elems", 0, "The number of elements along the main axis");
  std::vector<Real> default_node_locations (1, 0.0);
  params.addParam<std::vector<Real> >("node_locations", default_node_locations, "The node locations along the main axis");

  return params;
}

GeometricalComponent::GeometricalComponent(const InputParameters & parameters) :
    Component(parameters),
    _position(getParam<Point>("position")),
    _offset(getParam<RealVectorValue>("offset")),
    _dir(getParam<RealVectorValue>("orientation")),
    _rotation(getParam<Real>("rotation")),
    _2nd_order_mesh(_sim.getParam<bool>("2nd_order_mesh")),
    _length(getParam<Real>("length")),
    _n_elems(getParam<unsigned int>("n_elems")),
    _node_locations(getParam<std::vector<Real> >("node_locations"))
{
  processNodeLocations();
}

GeometricalComponent::~GeometricalComponent()
{
}

void
GeometricalComponent::doBuildMesh()
{
  _first_node_id = _mesh.nNodes();
  Component::doBuildMesh();
  _last_node_id = _mesh.nNodes();

  // shift the component in z-direction so they do not overlap
  // NOTE: we are using 1D elements, so shifting each component by 1 is ok for now
  // When using 2D or even 3D meshes, this has to be way smarter
  for (unsigned int node_id = _first_node_id; node_id < _last_node_id; node_id++)
    _mesh.nodeRef(node_id)(2) += id();
}

void
GeometricalComponent::displaceMesh()
{
  Real rotation = M_PI * _rotation / 180.;
  RealVectorValue z_offset(0, 0, id());

  // rows of rotation matrix to rotate about x-axis
  RealVectorValue Rx_x(1, 0,              0);
  RealVectorValue Rx_y(0, cos(rotation), -sin(rotation));
  RealVectorValue Rx_z(0, sin(rotation),  cos(rotation));
  RealTensorValue Rx(Rx_x, Rx_y, Rx_z);

  // figure out the rotation
  Real r = _dir.norm();
  Real theta = acos(_dir(2) / r);
  Real aphi = atan2(_dir(1), _dir(0));
  // rows of transformation matrix
  RealVectorValue x( cos(-aphi)*cos(M_PI/2-theta), sin(-aphi), -cos(-aphi)*sin(M_PI/2-theta));
  RealVectorValue y(-sin(-aphi)*cos(M_PI/2-theta), cos(-aphi),  sin(-aphi)*sin(M_PI/2-theta));
  RealVectorValue z( sin(M_PI/2-theta),            0.0,         cos(M_PI/2-theta));
  RealTensorValue R(x, y, z);

  for (unsigned int node_id = _first_node_id; node_id < _last_node_id; ++node_id)
  {
    Node & current_node = _phys_mesh->nodeRef(node_id);
    RealVectorValue p(current_node(0), current_node(1), current_node(2));
    // move to the origin, rotate about x-axis, transform to follow the direction and move to its position
    current_node = R * (Rx * (p + _offset - z_offset)) + _position;
  }
}

const std::vector<RELAP7::Connection> &
GeometricalComponent::getConnections(RELAP7::EEndType id) const
{
  std::map<RELAP7::EEndType, std::vector<RELAP7::Connection> >::const_iterator it = _connections.find(id);
  if (it != _connections.end())
    return it->second;
  else
    mooseError(name() << ": No end of this type available (" << id << ").");
}

void
GeometricalComponent::processNodeLocations()
{
  bool specified_n_elems = _n_elems != 0;
  unsigned int n_nodes = _node_locations.size();
  bool specified_node_locations = ((n_nodes != 1) && (n_nodes != 0));
  unsigned int expected_n_elems = _2nd_order_mesh ? (n_nodes - 1) / 2 : n_nodes - 1;

  if (specified_n_elems)
  {
    if (specified_node_locations)
    {
      if (expected_n_elems != _n_elems) {
        mooseError(name() << ": \"n_elems\" and \"node_locations\" do not match.");
      }
    }
    else
    {
      _node_locations = std::vector<Real>(_n_elems + 1, 0.0);
      Real dx = _length / _n_elems;
      for (int i = 0; i < _n_elems; ++i)
      {
        _node_locations[i + 1] = _node_locations[i] + dx;
      }
      _node_locations[_n_elems] = _length;
    }
  }
  else
  {
    if (specified_node_locations)
    {
      _n_elems = _node_locations.size() - 1;
    }
    else
    {
      mooseError(name() << ": \"n_elems\" or \"node_locations\" must be specified.");
    }
  }

  if (_2nd_order_mesh)
  {
    unsigned int new_n_nodes = (2 * _n_elems) + 1;
    std::vector<Real> new_nodes(new_n_nodes, 0.0);
    unsigned int new_node_indx = 0;

    for (int i = 0; i < _n_elems; ++i)
    {
      new_nodes[new_node_indx] = _node_locations[i];
      ++new_node_indx;
      new_nodes[new_node_indx] = 0.5 * (_node_locations[i] + _node_locations[i+1]);
      ++new_node_indx;
    }
    new_nodes[new_node_indx] = _node_locations[_n_elems];
  }
}

const FunctionName &
GeometricalComponent::getVariableFn(const FunctionName & fn_param_name)
{
  const FunctionName & fn_name = getParam<FunctionName>(fn_param_name);
  const Function & fn = _sim.getFunction(fn_name);

  if (dynamic_cast<const ConstantFunction *>(&fn) != NULL)
  {
    connectObject(fn.parameters(), "", fn_name, fn_param_name, "value");
  }

  return fn_name;
}
<commit_msg>Added variable node locations to HeatStructure and Pipe. Added tests.<commit_after>#include "GeometricalComponent.h"
#include "Conversion.h"
#include "ConstantFunction.h"

template<>
InputParameters validParams<GeometricalComponent>()
{
  InputParameters params = validParams<Component>();

  params.addRequiredParam<Point>("position", "Origin (start) of the pipe");
  params.addParam<RealVectorValue>("offset", RealVectorValue(), "Offset of the origin for mesh generation");
  params.addRequiredParam<RealVectorValue>("orientation", "Orientation vector of the pipe");
  params.addParam<Real>("rotation", 0., "Rotation of the component (in degrees)");

  params.addRequiredParam<Real>("length", "The length of the geometric component along the main axis");

  params.addParam<unsigned int>("n_elems", 0, "The number of elements along the main axis");
  std::vector<Real> default_node_locations (1, 0.0);
  params.addParam<std::vector<Real> >("node_locations", default_node_locations, "Node locations along the main axis.");

  return params;
}

GeometricalComponent::GeometricalComponent(const InputParameters & parameters) :
    Component(parameters),
    _position(getParam<Point>("position")),
    _offset(getParam<RealVectorValue>("offset")),
    _dir(getParam<RealVectorValue>("orientation")),
    _rotation(getParam<Real>("rotation")),
    _2nd_order_mesh(_sim.getParam<bool>("2nd_order_mesh")),
    _length(getParam<Real>("length")),
    _n_elems(getParam<unsigned int>("n_elems")),
    _node_locations(getParam<std::vector<Real> >("node_locations"))
{
}

GeometricalComponent::~GeometricalComponent()
{
}

void
GeometricalComponent::doBuildMesh()
{
  processNodeLocations();
  _first_node_id = _mesh.nNodes();
  Component::doBuildMesh();
  _last_node_id = _mesh.nNodes();

  // shift the component in z-direction so they do not overlap
  // NOTE: we are using 1D elements, so shifting each component by 1 is ok for now
  // When using 2D or even 3D meshes, this has to be way smarter
  for (unsigned int node_id = _first_node_id; node_id < _last_node_id; node_id++)
    _mesh.nodeRef(node_id)(2) += id();
}

void
GeometricalComponent::displaceMesh()
{
  Real rotation = M_PI * _rotation / 180.;
  RealVectorValue z_offset(0, 0, id());

  // rows of rotation matrix to rotate about x-axis
  RealVectorValue Rx_x(1, 0,              0);
  RealVectorValue Rx_y(0, cos(rotation), -sin(rotation));
  RealVectorValue Rx_z(0, sin(rotation),  cos(rotation));
  RealTensorValue Rx(Rx_x, Rx_y, Rx_z);

  // figure out the rotation
  Real r = _dir.norm();
  Real theta = acos(_dir(2) / r);
  Real aphi = atan2(_dir(1), _dir(0));
  // rows of transformation matrix
  RealVectorValue x( cos(-aphi)*cos(M_PI/2-theta), sin(-aphi), -cos(-aphi)*sin(M_PI/2-theta));
  RealVectorValue y(-sin(-aphi)*cos(M_PI/2-theta), cos(-aphi),  sin(-aphi)*sin(M_PI/2-theta));
  RealVectorValue z( sin(M_PI/2-theta),            0.0,         cos(M_PI/2-theta));
  RealTensorValue R(x, y, z);

  for (unsigned int node_id = _first_node_id; node_id < _last_node_id; ++node_id)
  {
    Node & current_node = _phys_mesh->nodeRef(node_id);
    RealVectorValue p(current_node(0), current_node(1), current_node(2));
    // move to the origin, rotate about x-axis, transform to follow the direction and move to its position
    current_node = R * (Rx * (p + _offset - z_offset)) + _position;
  }
}

const std::vector<RELAP7::Connection> &
GeometricalComponent::getConnections(RELAP7::EEndType id) const
{
  std::map<RELAP7::EEndType, std::vector<RELAP7::Connection> >::const_iterator it = _connections.find(id);
  if (it != _connections.end())
    return it->second;
  else
    mooseError(name() << ": No end of this type available (" << id << ").");
}

void
GeometricalComponent::processNodeLocations()
{
  bool specified_n_elems = _n_elems != 0;
  unsigned int n_nodes = _node_locations.size();
  bool specified_node_locations = n_nodes > 1;

  if (specified_n_elems)
  {
    if (specified_node_locations)
    {
      unsigned int expected_n_elems = _2nd_order_mesh ? (n_nodes - 1) / 2 : n_nodes - 1;
      if (expected_n_elems != _n_elems) {
        mooseError(name() << ": \"n_elems\" and \"node_locations\" do not match.");
      }
    }
    else
    {
      _node_locations = std::vector<Real>(_n_elems + 1, 0.0);
      Real dx = _length / _n_elems;
      for (int i = 0; i < _n_elems - 1; ++i)
      {
        _node_locations[i + 1] = _node_locations[i] + dx;
      }
      _node_locations[_n_elems] = _length;
    }
  }
  else
  {
    if (specified_node_locations)
    {
      // remove duplicates and order in an increassing manner
      std::set<Real> unq_ord_node_lcns( _node_locations.begin(), _node_locations.end());
      _node_locations.assign(unq_ord_node_lcns.begin(), unq_ord_node_lcns.end());

      // removes locations not in the component
      std::vector<Real> new_nodes;
      new_nodes.reserve(_node_locations.size() + 2);
      for (auto node_location : _node_locations)
      {
        if ((node_location >= 0.0) && (node_location <= _length))
        {
          new_nodes.push_back(node_location);
        }
      }

      // add entry boundary node if not explicitly specified
      if (new_nodes[0] != 0.0)
      {
        new_nodes.insert(new_nodes.begin(), 0.0);
      }

      // add exit boundary node if not explicitly specified
      if (new_nodes[new_nodes.size() - 1] != _length)
      {
        new_nodes.push_back(_length);
      }

      _node_locations = new_nodes;

      // determine number of elements
      n_nodes = _node_locations.size();
      _n_elems = _2nd_order_mesh ? (n_nodes - 1) / 2 : n_nodes - 1;
    }
    else
    {
      mooseError(name() << ": \"n_elems\" or \"node_locations\" must be specified.");
    }
  }

  if (_2nd_order_mesh)
  {
    unsigned int new_n_nodes = (2 * _n_elems) + 1;
    std::vector<Real> new_nodes(new_n_nodes, 0.0);
    unsigned int new_node_indx = 0;

    for (int i = 0; i < _n_elems; ++i)
    {
      new_nodes[new_node_indx] = _node_locations[i];
      ++new_node_indx;
      new_nodes[new_node_indx] = 0.5 * (_node_locations[i] + _node_locations[i+1]);
      ++new_node_indx;
    }
    new_nodes[new_node_indx] = _node_locations[_n_elems];
    _node_locations = new_nodes;
  }
}

const FunctionName &
GeometricalComponent::getVariableFn(const FunctionName & fn_param_name)
{
  const FunctionName & fn_name = getParam<FunctionName>(fn_param_name);
  const Function & fn = _sim.getFunction(fn_name);

  if (dynamic_cast<const ConstantFunction *>(&fn) != NULL)
  {
    connectObject(fn.parameters(), "", fn_name, fn_param_name, "value");
  }

  return fn_name;
}
<|endoftext|>


<commit_before>// compilation on OSX
// $ g++ -std=c++11 main.cpp -o main

#include <fstream>
#include <vector>
#include <map>
#include <future>
#include <numeric>

typedef std::vector<int> GameTimes;
typedef std::map<std::string, GameTimes> GameMap;
typedef std::pair<int, int> StatPair;
typedef std::map<std::string, std::future<StatPair>> GameStat;

int sum(const GameTimes& vector)
{
  return std::accumulate(vector.begin(), vector.end(), 0);
}

int avg(const GameTimes& vector)
{
  return sum(vector) / vector.size();
}

StatPair calculateGameStats(const GameTimes& gameplays)
{
  return std::make_pair(sum(gameplays), avg(gameplays));
}

GameMap readFile(const std::string filename)
{
  std::ifstream input(filename);

  unsigned int lineCount, gameCount;

  GameMap games;
  std::string title;
  int seconds;

  input >> lineCount >> gameCount;

  for (int i = 0; i < lineCount; i++)
  {
    std::string temp;

    input >> temp >> title >> seconds;

    games[title].push_back(seconds);
  }

  input.close();

  return games;
}

void writeFile(const std::string filename, GameStat& results)
{
  std::ofstream output(filename);

  for (auto& result : results)
  {
    std::string title = result.first;
    StatPair stat = result.second.get();

    output << title << " " << stat.first << " " << stat.second << std::endl;
  }

  output.close();
}

int main()
{
  GameMap games = readFile("input.txt");

  // Calculating sum and avg for every game
  GameStat results;

  for (auto const & game : games)
  {
    results.insert(std::make_pair(game.first, std::async(std::launch::async, calculateGameStats, game.second)));
  }

  writeFile("output.txt", results);

  return 0;
}
<commit_msg>bead1: refactor<commit_after>// compilation on OSX
// $ g++ -std=c++11 main.cpp -o main

#include <fstream>
#include <vector>
#include <map>
#include <future>
#include <numeric>

typedef std::vector<int> GameTimes;
typedef std::map<std::string, GameTimes> GameMap;
typedef std::pair<int, int> StatPair;
typedef std::map<std::string, std::future<StatPair>> GameStat;

int sum(const GameTimes& vector)
{
  return std::accumulate(vector.begin(), vector.end(), 0);
}

int avg(const GameTimes& vector)
{
  return sum(vector) / vector.size();
}

StatPair calculateGameStats(const GameTimes& gameplays)
{
  return std::make_pair(sum(gameplays), avg(gameplays));
}

GameMap readFile(const std::string filename)
{
  std::ifstream input(filename);

  unsigned int lineCount, gameCount;

  input >> lineCount >> gameCount;

  GameMap games;

  for (int i = 0; i < lineCount; i++)
  {
    std::string temp, title;
    int seconds;

    input >> temp >> title >> seconds;

    games[title].push_back(seconds);
  }

  input.close();

  return games;
}

void writeFile(const std::string filename, GameStat& results)
{
  std::ofstream output(filename);

  for (auto& result : results)
  {
    std::string title = result.first;
    StatPair stat = result.second.get();

    output << title << " " << stat.first << " " << stat.second << std::endl;
  }

  output.close();
}

int main()
{
  GameMap games = readFile("input.txt");

  // Calculating sum and avg for every game
  GameStat results;

  for (auto const & game : games)
  {
    results.insert(std::make_pair(game.first, std::async(std::launch::async, calculateGameStats, game.second)));
  }

  writeFile("output.txt", results);

  return 0;
}
<|endoftext|>


<commit_before>// Copyright 2009 Minor Gordon.
// This source comes from the XtreemFS project. It is licensed under the GPLv2 (see COPYING for terms and conditions).

#include "xtreemfs/proxy_exception_response.h"
using namespace xtreemfs;

#ifdef _WIN32
#include <windows.h>
#endif

#include <errno.h>

uint32_t ProxyExceptionResponse::get_platform_error_code() const
{
  uint32_t error_code = get_error_code();

  switch ( error_code )
  {
#if defined(_WIN32)
    case EACCES: return ERROR_ACCESS_DENIED;
    case EEXIST: return ERROR_ALREADY_EXISTS;
    case EINVAL: return ERROR_INVALID_PARAMETER;
    case ENOENT: return ERROR_FILE_NOT_FOUND;
    case WSAETIMEDOUT: return ERROR_NETWORK_BUSY;
#elif defined(__FreeBSD__)
    case 11: return EAGAIN; // Not sure why they renumbered this one.
    case 39: return ENOTEMPTY; // 39 is EDESTADDRREQ on FreeBSD
    case 61: return ENOATTR; // 61 is ENODATA on Linux, returned when an xattr is not present
#endif
    case 0: DebugBreak(); return 0;
    default: return error_code;
  }
}
<commit_msg>client: __MACH__ errno translation<commit_after>// Copyright 2009 Minor Gordon.
// This source comes from the XtreemFS project. It is licensed under the GPLv2 (see COPYING for terms and conditions).

#include "xtreemfs/proxy_exception_response.h"
using namespace xtreemfs;

#ifdef _WIN32
#include <windows.h>
#endif

#include <errno.h>

uint32_t ProxyExceptionResponse::get_platform_error_code() const
{
  uint32_t error_code = get_error_code();

  switch ( error_code )
  {
#if defined(_WIN32)
    case EACCES: return ERROR_ACCESS_DENIED;
    case EEXIST: return ERROR_ALREADY_EXISTS;
    case EINVAL: return ERROR_INVALID_PARAMETER;
    case ENOENT: return ERROR_FILE_NOT_FOUND;
    case WSAETIMEDOUT: return ERROR_NETWORK_BUSY;
#elif defined(__FreeBSD__) || defined(__MACH__)
    case 11: return EAGAIN; // Not sure why they renumbered this one.
    case 39: return ENOTEMPTY; // 39 is EDESTADDRREQ on FreeBSD
    case 61: return ENOATTR; // 61 is ENODATA on Linux, returned when an xattr is not present
#endif
    case 0: DebugBreak(); return 0;
    default: return error_code;
  }
}
<|endoftext|>


<commit_before>/* Gearman server and library
 * Copyright (C) 2008-2009 Brian Aker, Eric Day
 * All rights reserved.
 *
 * Use and distribution licensed under the BSD license.  See
 * the COPYING file in the parent directory for full text.
 */

/**
 * @file
 * @brief Gearman State Definitions
 */

#include <config.h>
#include <libgearman-server/common.h>

#include <algorithm>
#include <cerrno>
#include <cstring>

static pthread_key_t logging_key;
static pthread_once_t intitialize_log_once= PTHREAD_ONCE_INIT;

static void delete_log(void *ptr)
{
  if (ptr)
  {
    free(ptr);
  }
}

static void create_log(void)
{
  (void) pthread_key_create(&logging_key, delete_log);
}

void gearmand_initialize_thread_logging(const char *identity)
{
  (void) pthread_once(&intitialize_log_once, create_log);

  void *ptr;
  if ((ptr= pthread_getspecific(logging_key)) == NULL)
  {
    const char *key_to_use= strdup(identity);
    (void) pthread_setspecific(logging_key, key_to_use);
  }
}

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

/**
 * Log a message.
 *
 * @param[in] gearman Structure previously initialized with gearman_create() or
 *  gearman_clone().
 * @param[in] verbose Logging level of the message.
 * @param[in] format Format and variable argument list of message.
 * @param[in] args Variable argument list that has been initialized.
 */

static void gearmand_log(const char *position, const char *func /* func */,
                         gearmand_verbose_t verbose,
                         const gearmand_error_t error_arg,
                         const char *format, va_list args)
{
  if (Gearmand() == NULL)
  {
    fprintf(stderr, "%s %7s: ", position,  gearmand_verbose_name(verbose));
    vprintf(format, args);
    fprintf(stderr, "\n");
    return;
  }

  (void) pthread_once(&intitialize_log_once, create_log);

  const char *identity= (const char *)pthread_getspecific(logging_key);

  if (identity == NULL)
  {
    identity= "[  main ]";
  }

  if (Gearmand() && Gearmand()->log_fn)
  {
    char log_buffer[GEARMAN_MAX_ERROR_SIZE*2];
    char *log_buffer_ptr= log_buffer;
    size_t remaining_size= sizeof(log_buffer);

    {
      int length= snprintf(log_buffer_ptr, sizeof(log_buffer), "%s ", identity);
      // We just return whatever we have if this occurs
      if (length < -1 || (size_t)length >= sizeof(log_buffer))
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size)
    {
      int length= vsnprintf(log_buffer_ptr, remaining_size, format, args);
      if (length < -1 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and error_arg != GEARMAN_SUCCESS)
    {
      int length= snprintf(log_buffer_ptr, remaining_size, " %s(%s)", func, gearmand_strerror(error_arg));
      if (length < -1 or size_t(length) >= remaining_size)
      { }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and position and verbose != GEARMAND_VERBOSE_INFO)
    {
      snprintf(log_buffer_ptr, remaining_size, " -> %s", position);
    }

    // Make sure this is null terminated
    log_buffer[sizeof(log_buffer)]= 0;

    Gearmand()->log_fn(log_buffer, verbose, (void *)Gearmand()->log_context);
  }
  else
  {
    fprintf(stderr, "%s %7s: ", identity,  gearmand_verbose_name(verbose));
    vprintf(format, args);
    fprintf(stderr, "\n");
  }
}

void gearmand_log_fatal(const char *position, const char *func, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    va_start(args, format);
    gearmand_log(position, func, GEARMAND_VERBOSE_FATAL, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_fatal_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif

    gearmand_log_fatal(position, function, "%s(%s)", message, errmsg_ptr);
  }
}

gearmand_error_t gearmand_log_error(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }

  return GEARMAN_UNKNOWN_OPTION;
}

void gearmand_log_warning(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_WARN, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

// LOG_NOTICE is only used for reporting job status.
void gearmand_log_notice(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_NOTICE)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_NOTICE, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_info(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_INFO)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_INFO, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_debug(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_DEBUG)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_DEBUG, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

gearmand_error_t gearmand_log_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() or (Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR))
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif
    gearmand_log_error(position, function, "%s(%s)", message, errmsg_ptr);
  }

  return GEARMAN_ERRNO;
}

gearmand_error_t gearmand_log_gerror(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gerror_warn(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_WARN, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gai_error(const char *position, const char *function, const int rc, const char *message)
{
  if (rc == EAI_SYSTEM)
  {
    return gearmand_log_perror(position, function, message);
  }

  gearmand_log_error(position, function, "%s getaddrinfo(%s)", message, gai_strerror(rc));

  return GEARMAN_GETADDRINFO;
}

gearmand_error_t gearmand_log_memory_error(const char *position, const char *function, const char *allocator, const char *object_type, size_t count, size_t size)
{
  if (count > 1)
  {
    gearmand_log_error(position, function, "%s(%s, count: %lu size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }
  else
  {
    gearmand_log_error(position, function, "%s(%s, size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }

  return GEARMAN_MEMORY_ALLOCATION_FAILURE;
}
<commit_msg>Add time to logging information.<commit_after>/* Gearman server and library
 * Copyright (C) 2008-2009 Brian Aker, Eric Day
 * All rights reserved.
 *
 * Use and distribution licensed under the BSD license.  See
 * the COPYING file in the parent directory for full text.
 */

/**
 * @file
 * @brief Gearman State Definitions
 */

#include <config.h>
#include <libgearman-server/common.h>
#include <libgearman-server/timer.h>

#include <algorithm>
#include <cerrno>
#include <cstring>
#include <ctime>

static pthread_key_t logging_key;
static pthread_once_t intitialize_log_once= PTHREAD_ONCE_INIT;

static void delete_log(void *ptr)
{
  if (ptr)
  {
    free(ptr);
  }
}

static void create_log(void)
{
  (void) pthread_key_create(&logging_key, delete_log);
}

void gearmand_initialize_thread_logging(const char *identity)
{
  (void) pthread_once(&intitialize_log_once, create_log);

  void *ptr;
  if ((ptr= pthread_getspecific(logging_key)) == NULL)
  {
    const char *key_to_use= strdup(identity);
    (void) pthread_setspecific(logging_key, key_to_use);
  }
}

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

/**
 * Log a message.
 *
 * @param[in] gearman Structure previously initialized with gearman_create() or
 *  gearman_clone().
 * @param[in] verbose Logging level of the message.
 * @param[in] format Format and variable argument list of message.
 * @param[in] args Variable argument list that has been initialized.
 */

static void gearmand_log(const char *position, const char *func /* func */,
                         gearmand_verbose_t verbose,
                         const gearmand_error_t error_arg,
                         const char *format, va_list args)
{
  struct timeval current_epoch;

  if (Gearmand() and Gearmand()->verbose < GEARMAND_VERBOSE_DEBUG)
  {
    current_epoch= libgearman::server::Epoch::current();
  }
  else
  {
    (void)gettimeofday(&current_epoch, NULL);
  }

  struct tm current_tm;
  const char *current_time_str_ptr;
  char current_time_str[27];

  if (current_epoch.tv_sec == 0)
  {
    (void)gettimeofday(&current_epoch, NULL);
  }

  if ((gmtime_r(&current_epoch.tv_sec, &current_tm) == NULL))
  {
    current_time_str_ptr = "NA";
  }
  else
  {
    snprintf(current_time_str, sizeof(current_time_str), "%04d-%02d-%02d %02d:%02d:%02d.%06d",
             (1900 + current_tm.tm_year), current_tm.tm_mon, current_tm.tm_mday, current_tm.tm_hour,
             current_tm.tm_min, current_tm.tm_sec, current_epoch.tv_usec);
    current_time_str_ptr = current_time_str;
  }

  if (Gearmand() == NULL)
  {
    fprintf(stderr, "%s %s %7s: ", current_time_str_ptr, position,  gearmand_verbose_name(verbose));
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");
    return;
  }

  (void) pthread_once(&intitialize_log_once, create_log);

  const char *identity= (const char *)pthread_getspecific(logging_key);

  if (identity == NULL)
  {
    identity= "[  main ]";
  }

  if (Gearmand() && Gearmand()->log_fn)
  {
    char log_buffer[GEARMAN_MAX_ERROR_SIZE*2];
    char *log_buffer_ptr= log_buffer;
    size_t remaining_size= sizeof(log_buffer);

    {
      int length= snprintf(log_buffer, sizeof(log_buffer), "%s %s ", current_time_str_ptr, identity);
      // We just return whatever we have if this occurs
      if (length < -1 || (size_t)length >= sizeof(log_buffer))
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size)
    {
      int length= vsnprintf(log_buffer_ptr, remaining_size, format, args);
      if (length < -1 or size_t(length) >= remaining_size)
      {
        remaining_size= 0;
      }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and error_arg != GEARMAN_SUCCESS)
    {
      int length= snprintf(log_buffer_ptr, remaining_size, " %s(%s)", func, gearmand_strerror(error_arg));
      if (length < -1 or size_t(length) >= remaining_size)
      { }
      else
      {
        remaining_size-= size_t(length);
        log_buffer_ptr+= length;
      }
    }

    if (remaining_size and position and verbose != GEARMAND_VERBOSE_INFO)
    {
      snprintf(log_buffer_ptr, remaining_size, " -> %s", position);
    }

    // Make sure this is null terminated
    log_buffer[sizeof(log_buffer)]= 0;

    Gearmand()->log_fn(log_buffer, verbose, (void *)Gearmand()->log_context);
  }
  else
  {
    fprintf(stderr, "%s %s %7s: ", current_time_str_ptr, identity,  gearmand_verbose_name(verbose));
    vfprintf(stderr, format, args);
    fprintf(stderr, "\n");
  }
}

void gearmand_log_fatal(const char *position, const char *func, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    va_start(args, format);
    gearmand_log(position, func, GEARMAND_VERBOSE_FATAL, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_fatal_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_FATAL)
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif

    gearmand_log_fatal(position, function, "%s(%s)", message, errmsg_ptr);
  }
}

gearmand_error_t gearmand_log_error(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }

  return GEARMAN_UNKNOWN_OPTION;
}

void gearmand_log_warning(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_WARN, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

// LOG_NOTICE is only used for reporting job status.
void gearmand_log_notice(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_NOTICE)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_NOTICE, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_info(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_INFO)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_INFO, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

void gearmand_log_debug(const char *position, const char *function, const char *format, ...)
{
  va_list args;

  if (not Gearmand() || Gearmand()->verbose >= GEARMAND_VERBOSE_DEBUG)
  {
    va_start(args, format);
    gearmand_log(position, function, GEARMAND_VERBOSE_DEBUG, GEARMAN_SUCCESS, format, args);
    va_end(args);
  }
}

gearmand_error_t gearmand_log_perror(const char *position, const char *function, const char *message)
{
  if (not Gearmand() or (Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR))
  {
    const char *errmsg_ptr;
    char errmsg[GEARMAN_MAX_ERROR_SIZE];
    errmsg[0]= 0;

#ifdef STRERROR_R_CHAR_P
    errmsg_ptr= strerror_r(errno, errmsg, sizeof(errmsg));
#else
    strerror_r(errno, errmsg, sizeof(errmsg));
    errmsg_ptr= errmsg;
#endif
    gearmand_log_error(position, function, "%s(%s)", message, errmsg_ptr);
  }

  return GEARMAN_ERRNO;
}

gearmand_error_t gearmand_log_gerror(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_ERROR)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_ERROR, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gerror_warn(const char *position, const char *function, const gearmand_error_t rc, const char *format, ...)
{
  if (gearmand_failed(rc) and rc != GEARMAN_IO_WAIT)
  {
    va_list args;

    if (Gearmand() == NULL or Gearmand()->verbose >= GEARMAND_VERBOSE_WARN)
    {
      va_start(args, format);
      gearmand_log(position, function, GEARMAND_VERBOSE_WARN, rc, format, args);
      va_end(args);
    }
  }
  else if (rc == GEARMAN_IO_WAIT)
  { }

  return rc;
}

gearmand_error_t gearmand_log_gai_error(const char *position, const char *function, const int rc, const char *message)
{
  if (rc == EAI_SYSTEM)
  {
    return gearmand_log_perror(position, function, message);
  }

  gearmand_log_error(position, function, "%s getaddrinfo(%s)", message, gai_strerror(rc));

  return GEARMAN_GETADDRINFO;
}

gearmand_error_t gearmand_log_memory_error(const char *position, const char *function, const char *allocator, const char *object_type, size_t count, size_t size)
{
  if (count > 1)
  {
    gearmand_log_error(position, function, "%s(%s, count: %lu size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }
  else
  {
    gearmand_log_error(position, function, "%s(%s, size: %lu)", allocator, object_type, static_cast<unsigned long>(count), static_cast<unsigned long>(size));
  }

  return GEARMAN_MEMORY_ALLOCATION_FAILURE;
}
<|endoftext|>


<commit_before>
#include <Hord/cc_unique_ptr.hpp>
#include <Hord/Rule/Defs.hpp>
#include <Hord/Error.hpp>
#include <Hord/System/Driver.hpp>

#include <ceformat/print.hpp>

#include <type_traits>
#include <algorithm>
#include <utility>
#include <chrono>

namespace Hord {
namespace System {

// class Driver implementation

#define HORD_SCOPE_CLASS_IDENT__ System::Driver

// NB: See note about stdlib defect in System/IDGenerator.cpp

Driver::Driver() /*noexcept*/ {
	static_assert(
		std::is_same<
			int64_t,
			std::chrono::steady_clock::rep
		>::value,
		"steady_clock representation is not 64 bits!"
	);

	// Initialize generator
	m_id_generator.seed(
		std::chrono::steady_clock::now().time_since_epoch().count()
	);
	// TODO: Register standard rule types.
}

Driver::Driver(Driver&&) = default;
Driver::~Driver() noexcept = default;

#define HORD_SCOPE_FUNC_IDENT__ register_rule_type
void
Driver::register_rule_type(
	Rule::type_info const& type_info
) {
	if (
		static_cast<Rule::Type>(Rule::StandardTypes::ReservedLast)
		>= type_info.type
	) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_rule_type_reserved,
			"type is within range reserved for standard rules"
		);
	} else if (0u == type_info.permitted_types) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_rule_type_zero_permitted_types,
			"permitted_types property must be a nonzero combination"
			" of FieldTypes"
		);
	} else if (m_rule_types.cend() != m_rule_types.find(type_info.type)) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_rule_type_shared,
			"type has already been registered"
		);
	}
	m_rule_types.insert(std::move(std::make_pair(
		type_info.type,
		type_info
	)));
}
#undef HORD_SCOPE_FUNC_IDENT__

#define HORD_SCOPE_FUNC_IDENT__ placehold_hive

HORD_FMT_SCOPED_FQN(
	s_err_root_shared,
	"cannot placehold hive with non-unique root path `%s`"
);

Hive::Unit const&
Driver::placehold_hive(
	IO::Datastore::type_info const& type_info,
	String root_path
) {
	if (root_path.empty()) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_hive_root_empty,
			"cannot placehold hive with empty root path"
		);
	} else if (
		// FIXME: This is rank.
		m_datastores.cend()
		!= std::find_if(m_datastores.cbegin(), m_datastores.cend(),
			[&root_path](datastore_map_type::value_type const& pair) -> bool {
				return 0 == root_path.compare(pair.second->get_root_path());
			}
		)
	) {
		HORD_THROW_ERROR_F(
			ErrorCode::driver_hive_root_shared,
			s_err_root_shared,
			root_path
		);
	}

	// Phew. Now let's try to construct and insert this guy
	Object::ID const
		id = m_id_generator.generate_unique(m_hives);
	IO::Datastore* const
		datastore_ptr = type_info.construct(std::move(root_path));
	if (nullptr == datastore_ptr) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_datastore_construct_failed,
			"failed to construct datastore"
		);
	}
	m_hive_order.emplace_back(id);
	auto const& result_pair = m_hives.emplace(
		id,
		std::move(Hive::Unit{id})
	);
	m_datastores.emplace(
		id,
		std::move(cc_unique_ptr<IO::Datastore>{datastore_ptr})
	);
	return result_pair.first->second;
}
#undef HORD_SCOPE_FUNC_IDENT__

#undef HORD_SCOPE_CLASS_IDENT__

} // namespace System
} // namespace Hord
<commit_msg>System::Driver: using sizeof() to compare steady_clock::rep instead of is_same.¹<commit_after>
#include <Hord/cc_unique_ptr.hpp>
#include <Hord/Rule/Defs.hpp>
#include <Hord/Error.hpp>
#include <Hord/System/Driver.hpp>

#include <ceformat/print.hpp>

#include <algorithm>
#include <utility>
#include <chrono>

namespace Hord {
namespace System {

// class Driver implementation

#define HORD_SCOPE_CLASS_IDENT__ System::Driver

// NB: See note about stdlib defect in System/IDGenerator.cpp

Driver::Driver() /*noexcept*/ {
	static_assert(
		8u == sizeof(std::chrono::steady_clock::rep),
		"steady_clock representation is not 64 bits!"
	);

	// Initialize generator
	m_id_generator.seed(
		std::chrono::steady_clock::now().time_since_epoch().count()
	);
	// TODO: Register standard rule types.
}

Driver::Driver(Driver&&) = default;
Driver::~Driver() noexcept = default;

#define HORD_SCOPE_FUNC_IDENT__ register_rule_type
void
Driver::register_rule_type(
	Rule::type_info const& type_info
) {
	if (
		static_cast<Rule::Type>(Rule::StandardTypes::ReservedLast)
		>= type_info.type
	) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_rule_type_reserved,
			"type is within range reserved for standard rules"
		);
	} else if (0u == type_info.permitted_types) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_rule_type_zero_permitted_types,
			"permitted_types property must be a nonzero combination"
			" of FieldTypes"
		);
	} else if (m_rule_types.cend() != m_rule_types.find(type_info.type)) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_rule_type_shared,
			"type has already been registered"
		);
	}
	m_rule_types.insert(std::move(std::make_pair(
		type_info.type,
		type_info
	)));
}
#undef HORD_SCOPE_FUNC_IDENT__

#define HORD_SCOPE_FUNC_IDENT__ placehold_hive

HORD_FMT_SCOPED_FQN(
	s_err_root_shared,
	"cannot placehold hive with non-unique root path `%s`"
);

Hive::Unit const&
Driver::placehold_hive(
	IO::Datastore::type_info const& type_info,
	String root_path
) {
	if (root_path.empty()) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_hive_root_empty,
			"cannot placehold hive with empty root path"
		);
	} else if (
		// FIXME: This is rank.
		m_datastores.cend()
		!= std::find_if(m_datastores.cbegin(), m_datastores.cend(),
			[&root_path](datastore_map_type::value_type const& pair) -> bool {
				return 0 == root_path.compare(pair.second->get_root_path());
			}
		)
	) {
		HORD_THROW_ERROR_F(
			ErrorCode::driver_hive_root_shared,
			s_err_root_shared,
			root_path
		);
	}

	// Phew. Now let's try to construct and insert this guy
	Object::ID const
		id = m_id_generator.generate_unique(m_hives);
	IO::Datastore* const
		datastore_ptr = type_info.construct(std::move(root_path));
	if (nullptr == datastore_ptr) {
		HORD_THROW_ERROR_SCOPED_FQN(
			ErrorCode::driver_datastore_construct_failed,
			"failed to construct datastore"
		);
	}
	m_hive_order.emplace_back(id);
	auto const& result_pair = m_hives.emplace(
		id,
		std::move(Hive::Unit{id})
	);
	m_datastores.emplace(
		id,
		std::move(cc_unique_ptr<IO::Datastore>{datastore_ptr})
	);
	return result_pair.first->second;
}
#undef HORD_SCOPE_FUNC_IDENT__

#undef HORD_SCOPE_CLASS_IDENT__

} // namespace System
} // namespace Hord
<|endoftext|>


<commit_before><commit_msg>Fix compiling on AppleClang.<commit_after><|endoftext|>