<commit_before>// Copyright (c) 2012 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 "base/format_macros.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/notification_service.h"

#if defined(TOOLKIT_GTK)
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#endif

namespace {

string16 AutocompleteResultAsString(const AutocompleteResult& result) {
  std::string output(base::StringPrintf("{%" PRIuS "} ", result.size()));
  for (size_t i = 0; i < result.size(); ++i) {
    AutocompleteMatch match = result.match_at(i);
    std::string provider_name = match.provider->name();
    output.append(base::StringPrintf("[\"%s\" by \"%s\"] ",
                                     UTF16ToUTF8(match.contents).c_str(),
                                     provider_name.c_str()));
  }
  return UTF8ToUTF16(output);
}

}  // namespace

class OmniboxApiTest : public ExtensionApiTest {
 protected:
  LocationBar* GetLocationBar(Browser* browser) const {
    return browser->window()->GetLocationBar();
  }

  AutocompleteController* GetAutocompleteController(Browser* browser) const {
    return GetLocationBar(browser)->location_entry()->model()->popup_model()->
        autocomplete_controller();
  }

  void WaitForTemplateURLServiceToLoad() {
    ui_test_utils::WindowedNotificationObserver loaded_observer(
        chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
        content::NotificationService::AllSources());
    TemplateURLService* model =
        TemplateURLServiceFactory::GetForProfile(browser()->profile());
    model->Load();
    if (!model->loaded())
      loaded_observer.Wait();
  }

  // TODO(phajdan.jr): Get rid of this wait-in-a-loop pattern.
  void WaitForAutocompleteDone(AutocompleteController* controller) {
    while (!controller->done()) {
      ui_test_utils::WindowedNotificationObserver ready_observer(
          chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
          content::Source<AutocompleteController>(controller));
      ready_observer.Wait();
    }
  }
};

#if defined(OS_CHROMEOS)
// The test fails on chromeos gtk bot, and linux chromeos aura although it
// passes locally. crbug.com/113455 and crbug.com/114721
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif

IN_PROC_BROWSER_TEST_F(OmniboxApiTest, MAYBE_Basic) {
#if defined(TOOLKIT_GTK)
  // Disable the timer because, on Lucid at least, it triggers resize/move
  // behavior in the browser window, which dismisses the autocomplete popup
  // before the results can be read.
  static_cast<BrowserWindowGtk*>(
      browser()->window())->DisableDebounceTimerForTests(true);
#endif

  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;

  // The results depend on the TemplateURLService being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  WaitForTemplateURLServiceToLoad();

  LocationBar* location_bar = GetLocationBar(browser());
  AutocompleteController* autocomplete_controller =
      GetAutocompleteController(browser());

  // Test that our extension's keyword is suggested to us when we partially type
  // it.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("keywor"), string16(), true, false, true,
        AutocompleteInput::ALL_MATCHES);
    WaitForAutocompleteDone(autocomplete_controller);
    EXPECT_TRUE(autocomplete_controller->done());

    // Now, peek into the controller to see if it has the results we expect.
    // First result should be to search for what was typed, second should be to
    // enter "extension keyword" mode.
    const AutocompleteResult& result = autocomplete_controller->result();
    ASSERT_EQ(2U, result.size()) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
    EXPECT_FALSE(match.deletable);

    match = result.match_at(1);
    ASSERT_TRUE(match.template_url);
    EXPECT_TRUE(match.template_url->IsExtensionKeyword());
    EXPECT_EQ(ASCIIToUTF16("keyword"), match.template_url->keyword());
  }

  // Test that our extension can send suggestions back to us.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("keyword suggestio"), string16(), true, false, true,
        AutocompleteInput::ALL_MATCHES);
    WaitForAutocompleteDone(autocomplete_controller);
    EXPECT_TRUE(autocomplete_controller->done());

    // Now, peek into the controller to see if it has the results we expect.
    // First result should be to invoke the keyword with what we typed, 2-4
    // should be to invoke with suggestions from the extension, and the last
    // should be to search for what we typed.
    const AutocompleteResult& result = autocomplete_controller->result();
    ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result);

    ASSERT_TRUE(result.match_at(0).template_url);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestio"),
              result.match_at(0).fill_into_edit);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion1"),
              result.match_at(1).fill_into_edit);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion2"),
              result.match_at(2).fill_into_edit);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion3"),
              result.match_at(3).fill_into_edit);

    string16 description =
        ASCIIToUTF16("Description with style: <match>, [dim], (url till end)");
    EXPECT_EQ(description, result.match_at(1).contents);
    ASSERT_EQ(6u, result.match_at(1).contents_class.size());

    EXPECT_EQ(0u,
              result.match_at(1).contents_class[0].offset);
    EXPECT_EQ(ACMatchClassification::NONE,
              result.match_at(1).contents_class[0].style);

    EXPECT_EQ(description.find('<'),
              result.match_at(1).contents_class[1].offset);
    EXPECT_EQ(ACMatchClassification::MATCH,
              result.match_at(1).contents_class[1].style);

    EXPECT_EQ(description.find('>') + 1u,
              result.match_at(1).contents_class[2].offset);
    EXPECT_EQ(ACMatchClassification::NONE,
              result.match_at(1).contents_class[2].style);

    EXPECT_EQ(description.find('['),
              result.match_at(1).contents_class[3].offset);
    EXPECT_EQ(ACMatchClassification::DIM,
              result.match_at(1).contents_class[3].style);

    EXPECT_EQ(description.find(']') + 1u,
              result.match_at(1).contents_class[4].offset);
    EXPECT_EQ(ACMatchClassification::NONE,
              result.match_at(1).contents_class[4].style);

    EXPECT_EQ(description.find('('),
              result.match_at(1).contents_class[5].offset);
    EXPECT_EQ(ACMatchClassification::URL,
              result.match_at(1).contents_class[5].style);

    AutocompleteMatch match = result.match_at(4);
    EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
    EXPECT_FALSE(match.deletable);
  }

  {
    ResultCatcher catcher;
    location_bar->location_entry()->OnBeforePossibleChange();
    location_bar->location_entry()->SetUserText(
        ASCIIToUTF16("keyword command"));
    location_bar->location_entry()->OnAfterPossibleChange();
    location_bar->AcceptInput();
    // This checks that the keyword provider (via javascript)
    // gets told to navigate to the string "command".
    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  }
}

#if defined(OS_CHROMEOS) && !defined(USE_AURA)
// The test fails on chromeos gtk bot, although it passes locally.
// crbug.com/113455.
#define MAYBE_PopupStaysClosed DISABLED_PopupStaysClosed
#else
#define MAYBE_PopupStaysClosed PopupStaysClosed
#endif

// Tests that the autocomplete popup doesn't reopen after accepting input for
// a given query.
// http://crbug.com/88552
IN_PROC_BROWSER_TEST_F(OmniboxApiTest, MAYBE_PopupStaysClosed) {
#if defined(TOOLKIT_GTK)
  // Disable the timer because, on Lucid at least, it triggers resize/move
  // behavior in the browser window, which dismisses the autocomplete popup
  // before the results can be read.
  static_cast<BrowserWindowGtk*>(
    browser()->window())->DisableDebounceTimerForTests(true);
#endif

  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;

  // The results depend on the TemplateURLService being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  WaitForTemplateURLServiceToLoad();

  LocationBar* location_bar = GetLocationBar(browser());
  AutocompleteController* autocomplete_controller =
      GetAutocompleteController(browser());
  AutocompletePopupModel* popup_model =
      GetLocationBar(browser())->location_entry()->model()->popup_model();

  // Input a keyword query and wait for suggestions from the extension.
  location_bar->location_entry()->OnBeforePossibleChange();
  location_bar->location_entry()->SetUserText(ASCIIToUTF16("keyword comman"));
  location_bar->location_entry()->OnAfterPossibleChange();
  WaitForAutocompleteDone(autocomplete_controller);
  EXPECT_TRUE(autocomplete_controller->done());
  EXPECT_TRUE(popup_model->IsOpen());

  // Quickly type another query and accept it before getting suggestions back
  // for the query. The popup will close after accepting input - ensure that it
  // does not reopen when the extension returns its suggestions.
  ResultCatcher catcher;

  // TODO: Rather than send this second request by talking to the controller
  // directly, figure out how to send it via the proper calls to
  // location_bar or location_bar->().
  autocomplete_controller->Start(
      ASCIIToUTF16("keyword command"), string16(), true, false, true,
      AutocompleteInput::ALL_MATCHES);
  location_bar->AcceptInput();
  WaitForAutocompleteDone(autocomplete_controller);
  EXPECT_TRUE(autocomplete_controller->done());
  // This checks that the keyword provider (via javascript)
  // gets told to navigate to the string "command".
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_FALSE(popup_model->IsOpen());
}

// Tests that we get suggestions from and send input to the incognito context
// of an incognito split mode extension.
// http://crbug.com/100927
// Test flaky on linux: http://crbug.com/101219
IN_PROC_BROWSER_TEST_F(OmniboxApiTest, DISABLED_IncognitoSplitMode) {
#if defined(TOOLKIT_GTK)
  // Disable the timer because, on Lucid at least, it triggers resize/move
  // behavior in the browser window, which dismisses the autocomplete popup
  // before the results can be read.
  static_cast<BrowserWindowGtk*>(
    browser()->window())->DisableDebounceTimerForTests(true);
#endif

  ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToProfile(
      browser()->profile()->GetOffTheRecordProfile());

  ASSERT_TRUE(RunExtensionTestIncognito("omnibox")) << message_;

  // Open an incognito window and wait for the incognito extension process to
  // respond.
  Browser* incognito_browser = CreateIncognitoBrowser();
  ASSERT_TRUE(catcher_incognito.GetNextResult()) << catcher_incognito.message();

  // The results depend on the TemplateURLService being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  WaitForTemplateURLServiceToLoad();

  LocationBar* location_bar = GetLocationBar(incognito_browser);
  AutocompleteController* autocomplete_controller =
      GetAutocompleteController(incognito_browser);

  // Test that we get the incognito-specific suggestions.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("keyword suggestio"), string16(), true, false, true,
        AutocompleteInput::ALL_MATCHES);
    WaitForAutocompleteDone(autocomplete_controller);
    EXPECT_TRUE(autocomplete_controller->done());

    // First result should be to invoke the keyword with what we typed, 2-4
    // should be to invoke with suggestions from the extension, and the last
    // should be to search for what we typed.
    const AutocompleteResult& result = autocomplete_controller->result();
    ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result);
    ASSERT_TRUE(result.match_at(0).template_url);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion3 incognito"),
              result.match_at(3).fill_into_edit);
  }

  // Test that our input is sent to the incognito context. The test will do a
  // text comparison and succeed only if "command incognito" is sent to the
  // incognito context.
  {
    ResultCatcher catcher;
    autocomplete_controller->Start(
        ASCIIToUTF16("keyword command incognito"), string16(),
        true, false, true, AutocompleteInput::ALL_MATCHES);
    location_bar->AcceptInput();
    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  }
}
<commit_msg>Revert 122457 - Disable OmniboxApiTest.Basic on ChromiumOS.  The offending patch was reverted.<commit_after>// Copyright (c) 2012 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 "base/format_macros.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autocomplete/autocomplete.h"
#include "chrome/browser/autocomplete/autocomplete_edit.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/notification_service.h"

#if defined(TOOLKIT_GTK)
#include "chrome/browser/ui/gtk/browser_window_gtk.h"
#endif

namespace {

string16 AutocompleteResultAsString(const AutocompleteResult& result) {
  std::string output(base::StringPrintf("{%" PRIuS "} ", result.size()));
  for (size_t i = 0; i < result.size(); ++i) {
    AutocompleteMatch match = result.match_at(i);
    std::string provider_name = match.provider->name();
    output.append(base::StringPrintf("[\"%s\" by \"%s\"] ",
                                     UTF16ToUTF8(match.contents).c_str(),
                                     provider_name.c_str()));
  }
  return UTF8ToUTF16(output);
}

}  // namespace

class OmniboxApiTest : public ExtensionApiTest {
 protected:
  LocationBar* GetLocationBar(Browser* browser) const {
    return browser->window()->GetLocationBar();
  }

  AutocompleteController* GetAutocompleteController(Browser* browser) const {
    return GetLocationBar(browser)->location_entry()->model()->popup_model()->
        autocomplete_controller();
  }

  void WaitForTemplateURLServiceToLoad() {
    ui_test_utils::WindowedNotificationObserver loaded_observer(
        chrome::NOTIFICATION_TEMPLATE_URL_SERVICE_LOADED,
        content::NotificationService::AllSources());
    TemplateURLService* model =
        TemplateURLServiceFactory::GetForProfile(browser()->profile());
    model->Load();
    if (!model->loaded())
      loaded_observer.Wait();
  }

  // TODO(phajdan.jr): Get rid of this wait-in-a-loop pattern.
  void WaitForAutocompleteDone(AutocompleteController* controller) {
    while (!controller->done()) {
      ui_test_utils::WindowedNotificationObserver ready_observer(
          chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
          content::Source<AutocompleteController>(controller));
      ready_observer.Wait();
    }
  }
};

#if defined(OS_CHROMEOS) && !defined(USE_AURA)
// The test fails on chromeos gtk bot, although it passes locally.
// crbug.com/113455.
#define MAYBE_Basic DISABLED_Basic
#else
#define MAYBE_Basic Basic
#endif

IN_PROC_BROWSER_TEST_F(OmniboxApiTest, MAYBE_Basic) {
#if defined(TOOLKIT_GTK)
  // Disable the timer because, on Lucid at least, it triggers resize/move
  // behavior in the browser window, which dismisses the autocomplete popup
  // before the results can be read.
  static_cast<BrowserWindowGtk*>(
      browser()->window())->DisableDebounceTimerForTests(true);
#endif

  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;

  // The results depend on the TemplateURLService being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  WaitForTemplateURLServiceToLoad();

  LocationBar* location_bar = GetLocationBar(browser());
  AutocompleteController* autocomplete_controller =
      GetAutocompleteController(browser());

  // Test that our extension's keyword is suggested to us when we partially type
  // it.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("keywor"), string16(), true, false, true,
        AutocompleteInput::ALL_MATCHES);
    WaitForAutocompleteDone(autocomplete_controller);
    EXPECT_TRUE(autocomplete_controller->done());

    // Now, peek into the controller to see if it has the results we expect.
    // First result should be to search for what was typed, second should be to
    // enter "extension keyword" mode.
    const AutocompleteResult& result = autocomplete_controller->result();
    ASSERT_EQ(2U, result.size()) << AutocompleteResultAsString(result);
    AutocompleteMatch match = result.match_at(0);
    EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
    EXPECT_FALSE(match.deletable);

    match = result.match_at(1);
    ASSERT_TRUE(match.template_url);
    EXPECT_TRUE(match.template_url->IsExtensionKeyword());
    EXPECT_EQ(ASCIIToUTF16("keyword"), match.template_url->keyword());
  }

  // Test that our extension can send suggestions back to us.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("keyword suggestio"), string16(), true, false, true,
        AutocompleteInput::ALL_MATCHES);
    WaitForAutocompleteDone(autocomplete_controller);
    EXPECT_TRUE(autocomplete_controller->done());

    // Now, peek into the controller to see if it has the results we expect.
    // First result should be to invoke the keyword with what we typed, 2-4
    // should be to invoke with suggestions from the extension, and the last
    // should be to search for what we typed.
    const AutocompleteResult& result = autocomplete_controller->result();
    ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result);

    ASSERT_TRUE(result.match_at(0).template_url);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestio"),
              result.match_at(0).fill_into_edit);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion1"),
              result.match_at(1).fill_into_edit);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion2"),
              result.match_at(2).fill_into_edit);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion3"),
              result.match_at(3).fill_into_edit);

    string16 description =
        ASCIIToUTF16("Description with style: <match>, [dim], (url till end)");
    EXPECT_EQ(description, result.match_at(1).contents);
    ASSERT_EQ(6u, result.match_at(1).contents_class.size());

    EXPECT_EQ(0u,
              result.match_at(1).contents_class[0].offset);
    EXPECT_EQ(ACMatchClassification::NONE,
              result.match_at(1).contents_class[0].style);

    EXPECT_EQ(description.find('<'),
              result.match_at(1).contents_class[1].offset);
    EXPECT_EQ(ACMatchClassification::MATCH,
              result.match_at(1).contents_class[1].style);

    EXPECT_EQ(description.find('>') + 1u,
              result.match_at(1).contents_class[2].offset);
    EXPECT_EQ(ACMatchClassification::NONE,
              result.match_at(1).contents_class[2].style);

    EXPECT_EQ(description.find('['),
              result.match_at(1).contents_class[3].offset);
    EXPECT_EQ(ACMatchClassification::DIM,
              result.match_at(1).contents_class[3].style);

    EXPECT_EQ(description.find(']') + 1u,
              result.match_at(1).contents_class[4].offset);
    EXPECT_EQ(ACMatchClassification::NONE,
              result.match_at(1).contents_class[4].style);

    EXPECT_EQ(description.find('('),
              result.match_at(1).contents_class[5].offset);
    EXPECT_EQ(ACMatchClassification::URL,
              result.match_at(1).contents_class[5].style);

    AutocompleteMatch match = result.match_at(4);
    EXPECT_EQ(AutocompleteMatch::SEARCH_WHAT_YOU_TYPED, match.type);
    EXPECT_FALSE(match.deletable);
  }

  {
    ResultCatcher catcher;
    location_bar->location_entry()->OnBeforePossibleChange();
    location_bar->location_entry()->SetUserText(
        ASCIIToUTF16("keyword command"));
    location_bar->location_entry()->OnAfterPossibleChange();
    location_bar->AcceptInput();
    // This checks that the keyword provider (via javascript)
    // gets told to navigate to the string "command".
    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  }
}

#if defined(OS_CHROMEOS) && !defined(USE_AURA)
// The test fails on chromeos gtk bot, although it passes locally.
// crbug.com/113455.
#define MAYBE_PopupStaysClosed DISABLED_PopupStaysClosed
#else
#define MAYBE_PopupStaysClosed PopupStaysClosed
#endif

// Tests that the autocomplete popup doesn't reopen after accepting input for
// a given query.
// http://crbug.com/88552
IN_PROC_BROWSER_TEST_F(OmniboxApiTest, MAYBE_PopupStaysClosed) {
#if defined(TOOLKIT_GTK)
  // Disable the timer because, on Lucid at least, it triggers resize/move
  // behavior in the browser window, which dismisses the autocomplete popup
  // before the results can be read.
  static_cast<BrowserWindowGtk*>(
    browser()->window())->DisableDebounceTimerForTests(true);
#endif

  ASSERT_TRUE(RunExtensionTest("omnibox")) << message_;

  // The results depend on the TemplateURLService being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  WaitForTemplateURLServiceToLoad();

  LocationBar* location_bar = GetLocationBar(browser());
  AutocompleteController* autocomplete_controller =
      GetAutocompleteController(browser());
  AutocompletePopupModel* popup_model =
      GetLocationBar(browser())->location_entry()->model()->popup_model();

  // Input a keyword query and wait for suggestions from the extension.
  location_bar->location_entry()->OnBeforePossibleChange();
  location_bar->location_entry()->SetUserText(ASCIIToUTF16("keyword comman"));
  location_bar->location_entry()->OnAfterPossibleChange();
  WaitForAutocompleteDone(autocomplete_controller);
  EXPECT_TRUE(autocomplete_controller->done());
  EXPECT_TRUE(popup_model->IsOpen());

  // Quickly type another query and accept it before getting suggestions back
  // for the query. The popup will close after accepting input - ensure that it
  // does not reopen when the extension returns its suggestions.
  ResultCatcher catcher;

  // TODO: Rather than send this second request by talking to the controller
  // directly, figure out how to send it via the proper calls to
  // location_bar or location_bar->().
  autocomplete_controller->Start(
      ASCIIToUTF16("keyword command"), string16(), true, false, true,
      AutocompleteInput::ALL_MATCHES);
  location_bar->AcceptInput();
  WaitForAutocompleteDone(autocomplete_controller);
  EXPECT_TRUE(autocomplete_controller->done());
  // This checks that the keyword provider (via javascript)
  // gets told to navigate to the string "command".
  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  EXPECT_FALSE(popup_model->IsOpen());
}

// Tests that we get suggestions from and send input to the incognito context
// of an incognito split mode extension.
// http://crbug.com/100927
// Test flaky on linux: http://crbug.com/101219
IN_PROC_BROWSER_TEST_F(OmniboxApiTest, DISABLED_IncognitoSplitMode) {
#if defined(TOOLKIT_GTK)
  // Disable the timer because, on Lucid at least, it triggers resize/move
  // behavior in the browser window, which dismisses the autocomplete popup
  // before the results can be read.
  static_cast<BrowserWindowGtk*>(
    browser()->window())->DisableDebounceTimerForTests(true);
#endif

  ResultCatcher catcher_incognito;
  catcher_incognito.RestrictToProfile(
      browser()->profile()->GetOffTheRecordProfile());

  ASSERT_TRUE(RunExtensionTestIncognito("omnibox")) << message_;

  // Open an incognito window and wait for the incognito extension process to
  // respond.
  Browser* incognito_browser = CreateIncognitoBrowser();
  ASSERT_TRUE(catcher_incognito.GetNextResult()) << catcher_incognito.message();

  // The results depend on the TemplateURLService being loaded. Make sure it is
  // loaded so that the autocomplete results are consistent.
  WaitForTemplateURLServiceToLoad();

  LocationBar* location_bar = GetLocationBar(incognito_browser);
  AutocompleteController* autocomplete_controller =
      GetAutocompleteController(incognito_browser);

  // Test that we get the incognito-specific suggestions.
  {
    autocomplete_controller->Start(
        ASCIIToUTF16("keyword suggestio"), string16(), true, false, true,
        AutocompleteInput::ALL_MATCHES);
    WaitForAutocompleteDone(autocomplete_controller);
    EXPECT_TRUE(autocomplete_controller->done());

    // First result should be to invoke the keyword with what we typed, 2-4
    // should be to invoke with suggestions from the extension, and the last
    // should be to search for what we typed.
    const AutocompleteResult& result = autocomplete_controller->result();
    ASSERT_EQ(5U, result.size()) << AutocompleteResultAsString(result);
    ASSERT_TRUE(result.match_at(0).template_url);
    EXPECT_EQ(ASCIIToUTF16("keyword suggestion3 incognito"),
              result.match_at(3).fill_into_edit);
  }

  // Test that our input is sent to the incognito context. The test will do a
  // text comparison and succeed only if "command incognito" is sent to the
  // incognito context.
  {
    ResultCatcher catcher;
    autocomplete_controller->Start(
        ASCIIToUTF16("keyword command incognito"), string16(),
        true, false, true, AutocompleteInput::ALL_MATCHES);
    location_bar->AcceptInput();
    EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
  }
}
<|endoftext|>


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

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE calculator_test
#include "../../include/votca/tools/calculator.h"
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <fstream>

using namespace ::votca;

BOOST_AUTO_TEST_SUITE(calculator_test)

BOOST_AUTO_TEST_CASE(load_defaults_test) {

  class TestCalc : public tools::Calculator {

   public:
    std::string Identify() override { return "testcalc"; }

    void Initialize(const tools::Property &user_options) override {

      // Create folder for test
      const char dir_path[] = "calculators";
      boost::filesystem::path dir(dir_path);
      boost::filesystem::create_directory(dir);
      dir.append("xml");
      boost::filesystem::create_directory(dir);

      std::ofstream defaults("calculators/xml/testcalc.xml");
      defaults << "<options>\n"
               << "<testcalc>\n"
               << "<option1>0</option1>\n"
               << "<option2>3.141592</option2>\n"
               << "</testcalc>\n"
               << "</options>";
      defaults.close();

      // Load and check the options
      tools::Property final_opt =
          LoadDefaultsAndUpdateWithUserOptions("calculators", user_options);

      Index prop1 = final_opt.get("option1").as<votca::Index>();
      std::string prop2 = final_opt.get("option2").as<std::string>();
      BOOST_CHECK_EQUAL(prop1, 42);
      BOOST_CHECK_EQUAL(prop2, "3.141592");
    }
  };

  setenv("VOTCASHARE", ".", 1);
  char buff[FILENAME_MAX];
  std::cout << "WARNING: the VOTCASHARE env. variable has been updated to "
            << getcwd(buff, FILENAME_MAX) << "\n";

  // Generate user options
  tools::Property user_options;

  tools::Property &opt = user_options.add("options", "");
  tools::Property &opt_test = opt.add("testcalc", "");
  opt_test.add("option1", "42");

  TestCalc test_calc;
  test_calc.Initialize(user_options);
}

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

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE calculator_test
#include "../../include/votca/tools/calculator.h"
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <fstream>

using namespace ::votca;

BOOST_AUTO_TEST_SUITE(calculator_test)

BOOST_AUTO_TEST_CASE(load_defaults_test) {

  class TestCalc : public tools::Calculator {

   public:
    std::string Identify() override { return "testcalc"; }

    void Initialize(const tools::Property &user_options) override {

      // Create folder for test
      const char dir_path[] = "calculators";
      boost::filesystem::path dir(dir_path);
      boost::filesystem::create_directory(dir);
      dir.append("xml");
      boost::filesystem::create_directory(dir);

      std::ofstream defaults("calculators/xml/testcalc.xml");
      defaults << "<options>\n"
               << "<testcalc>\n"
               << "<option1>0</option1>\n"
               << "<option2>3.141592</option2>\n"
               << "</testcalc>\n"
               << "</options>";
      defaults.close();

      // Load and check the options
      tools::Property final_opt =
          LoadDefaultsAndUpdateWithUserOptions("calculators", user_options);

      Index prop1 = final_opt.get("option1").as<votca::Index>();
      std::string prop2 = final_opt.get("option2").as<std::string>();
      std::string prop3 = final_opt.get("option3").as<std::string>();
      BOOST_CHECK_EQUAL(prop1, 42);
      BOOST_CHECK_EQUAL(prop2, "3.141592");
      BOOST_CHECK_EQUAL(prop3, "some_value");
    }
  };

  setenv("VOTCASHARE", ".", 1);
  char buff[FILENAME_MAX];
  std::cout << "WARNING: the VOTCASHARE env. variable has been updated to "
            << getcwd(buff, FILENAME_MAX) << "\n";

  // Generate user options
  tools::Property user_options;

  tools::Property &opt = user_options.add("options", "");
  tools::Property &opt_test = opt.add("testcalc", "");
  opt_test.add("option1", "42");
  opt_test.add("option3", "some_value");

  TestCalc test_calc;
  test_calc.Initialize(user_options);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>
/* ========================================

   * File Name : 16.cpp

   * Creation Date : 09-08-2020

   * Last Modified : St 12. srpna 2020, 22:27:49

   * Created By : Karel Ha <mathemage@gmail.com>

   * URL : https://www.facebook.com/codingcompetitions/hacker-cup/2019/round-1/problems/B

   * Points Gained (in case of online contest) :

   ==========================================*/

#include <bits/stdc++.h>

using namespace std;

#define REP(I,N)   FOR(I,0,N)
#define FOR(i, begin, end) for (__typeof(end) i = (begin) - ((begin) > (end)); i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin) > (end)))
#define ALL(A)     (A).begin(), (A).end()
#define MSG(a) cout << #a << " == " << (a) << endl;

const int CLEAN = -1;

template <typename T>
string NumberToString ( T Number ) {
  ostringstream ss;
  ss << Number;
  return ss.str();
}

#define ERR(args...) { vector<string> _v = split(#args, ','); err(_v.begin(), args); }
vector<string> split(const string& s, char c) {
  vector<string> v;
  stringstream ss(s);
  string x;
  while (getline(ss, x, c))
    v.emplace_back(x);
  return move(v);
}
void err(vector<string>::iterator it) {}
template<typename T, typename... Args>
void err(vector<string>::iterator it, T a, Args... args) {
  cout << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << endl;
  err(++it, args...);
}

#define MOD 1000000007
#define UNDEF MOD
#define N_MAX 1000000

vector<int> powers(N_MAX + 1, UNDEF);

int mod_power(int base, int exp) {
  if (powers[exp] == UNDEF) {
    powers[0] = 1;
    FOR(i, 1, exp + 1) {
      powers[i] = (powers[i-1] * base) % MOD;
//       cout << endl; MSG(i) MSG(powers[i])
    }
  }
  return powers[exp];
}

int get_result(const string & V, int K) {
  int N = V.size();

  int init_balance = 0;    // n_B - n_A
  int balance = 0;
  FOR(i, N-K, N) {
    init_balance += (V[i] == 'A') ? (-1) : 1;
    balance = max(balance, init_balance);
//     MSG(init_balance)
  }
//   cout << endl << "inital balance: "; MSG(balance)

  int result = 0;
  FOR(j, N-K, 0) {
//     MSG(j) MSG(V[j])
//     cout << "0: "; MSG(balance)
    balance = max(balance, 0);
    balance += (V[j] == 'A') ? (-1) : 1;
//     cout << "1: "; MSG(balance) MSG(result)

    if (balance > K) {                  // over threshold
      balance -= 2;                     // swap 'B' for 'A'
      result += mod_power(2, j + 1);    // pay the charge
//       MSG(mod_power(2, j + 1))
      result %= MOD;                    // TODO: use memo table of pows
    }
//     cout << "2: "; MSG(balance) MSG(result)
  }

  return result;
}

int main() {
  int T;
  cin >> T;
//   MSG(T)

  REP(t,T) {
    int N, K;
    cin >> N >> K;
//     MSG(N) MSG(K)

    string V;
    V.reserve(N);
    cin >> V;
//     MSG(V) cout << endl;

    cout << "Case #" << t+1 << ": " << get_result(V, K) << endl;
  }

  return 0;
}
<commit_msg>Pre-compute entire powers() at once<commit_after>
/* ========================================

   * File Name : 16.cpp

   * Creation Date : 09-08-2020

   * Last Modified : St 12. srpna 2020, 22:34:28

   * Created By : Karel Ha <mathemage@gmail.com>

   * URL : https://www.facebook.com/codingcompetitions/hacker-cup/2019/round-1/problems/B

   * Points Gained (in case of online contest) :

   ==========================================*/

#include <bits/stdc++.h>

using namespace std;

#define REP(I,N)   FOR(I,0,N)
#define FOR(i, begin, end) for (__typeof(end) i = (begin) - ((begin) > (end)); i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin) > (end)))
#define ALL(A)     (A).begin(), (A).end()
#define MSG(a) cout << #a << " == " << (a) << endl;

const int CLEAN = -1;

template <typename T>
string NumberToString ( T Number ) {
  ostringstream ss;
  ss << Number;
  return ss.str();
}

#define ERR(args...) { vector<string> _v = split(#args, ','); err(_v.begin(), args); }
vector<string> split(const string& s, char c) {
  vector<string> v;
  stringstream ss(s);
  string x;
  while (getline(ss, x, c))
    v.emplace_back(x);
  return move(v);
}
void err(vector<string>::iterator it) {}
template<typename T, typename... Args>
void err(vector<string>::iterator it, T a, Args... args) {
  cout << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << endl;
  err(++it, args...);
}

#define MOD 1000000007
#define UNDEF -1
#define N_MAX 1000000

vector<int> powers(N_MAX + 1, UNDEF);

int mod_power(int base, int exp) {
  if (powers[exp] == UNDEF) {   // not pre-computed yet -> pre-compute powers[]
    powers[0] = 1;
    FOR(i, 1, powers.size()) {
      powers[i] = (powers[i-1] * base) % MOD;
//       cout << endl; MSG(i) MSG(powers[i])
    }
  }
  return powers[exp];
}

int get_result(const string & V, int K) {
  int N = V.size();

  int init_balance = 0;    // n_B - n_A
  int balance = 0;
  FOR(i, N-K, N) {
    init_balance += (V[i] == 'A') ? (-1) : 1;
    balance = max(balance, init_balance);
//     MSG(init_balance)
  }
//   cout << endl << "inital balance: "; MSG(balance)

  int result = 0;
  FOR(j, N-K, 0) {
//     MSG(j) MSG(V[j])
//     cout << "0: "; MSG(balance)
    balance = max(balance, 0);
    balance += (V[j] == 'A') ? (-1) : 1;
//     cout << "1: "; MSG(balance) MSG(result)

    if (balance > K) {                  // over threshold
      balance -= 2;                     // swap 'B' for 'A'
      result += mod_power(2, j + 1);    // pay the charge
//       MSG(mod_power(2, j + 1))
      result %= MOD;                    // TODO: use memo table of pows
    }
//     cout << "2: "; MSG(balance) MSG(result)
  }

  return result;
}

int main() {
  int T;
  cin >> T;
//   MSG(T)

  REP(t,T) {
    int N, K;
    cin >> N >> K;
//     MSG(N) MSG(K)

    string V;
    V.reserve(N);
    cin >> V;
//     MSG(V) cout << endl;

    cout << "Case #" << t+1 << ": " << get_result(V, K) << endl;
  }

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "browser/inspectable_web_contents_impl.h"

#include "browser/browser_client.h"
#include "browser/browser_context.h"
#include "browser/browser_main_parts.h"
#include "browser/inspectable_web_contents_delegate.h"
#include "browser/inspectable_web_contents_view.h"

#include "base/json/json_reader.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"

namespace brightray {

namespace {

const char kChromeUIDevToolsURL[] = "chrome-devtools://devtools/devtools.html?"
                                    "can_dock=true&&"
                                    "experiments=true";
const char kDevToolsBoundsPref[] = "brightray.devtools.bounds";

const char kFrontendHostId[] = "id";
const char kFrontendHostMethod[] = "method";
const char kFrontendHostParams[] = "params";

void RectToDictionary(const gfx::Rect& bounds, base::DictionaryValue* dict) {
  dict->SetInteger("x", bounds.x());
  dict->SetInteger("y", bounds.y());
  dict->SetInteger("width", bounds.width());
  dict->SetInteger("height", bounds.height());
}

void DictionaryToRect(const base::DictionaryValue& dict, gfx::Rect* bounds) {
  int x = 0, y = 0, width = 800, height = 600;
  dict.GetInteger("x", &x);
  dict.GetInteger("y", &y);
  dict.GetInteger("width", &width);
  dict.GetInteger("height", &height);
  *bounds = gfx::Rect(x, y, width, height);
}

bool ParseMessage(const std::string& message,
                  std::string* method,
                  base::ListValue* params,
                  int* id) {
  scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
  if (!parsed_message)
    return false;

  base::DictionaryValue* dict = NULL;
  if (!parsed_message->GetAsDictionary(&dict))
    return false;
  if (!dict->GetString(kFrontendHostMethod, method))
    return false;

  // "params" is optional.
  if (dict->HasKey(kFrontendHostParams)) {
    base::ListValue* internal_params;
    if (dict->GetList(kFrontendHostParams, &internal_params))
      params->Swap(internal_params);
    else
      return false;
  }

  *id = 0;
  dict->GetInteger(kFrontendHostId, id);
  return true;
}

}  // namespace

// Implemented separately on each platform.
InspectableWebContentsView* CreateInspectableContentsView(
    InspectableWebContentsImpl* inspectable_web_contents_impl);

void InspectableWebContentsImpl::RegisterPrefs(PrefRegistrySimple* registry) {
  auto bounds_dict = make_scoped_ptr(new base::DictionaryValue);
  RectToDictionary(gfx::Rect(0, 0, 800, 600), bounds_dict.get());
  registry->RegisterDictionaryPref(kDevToolsBoundsPref, bounds_dict.release());
}

InspectableWebContentsImpl::InspectableWebContentsImpl(
    content::WebContents* web_contents)
    : web_contents_(web_contents),
      delegate_(nullptr) {
  auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
  auto bounds_dict = context->prefs()->GetDictionary(kDevToolsBoundsPref);
  if (bounds_dict)
    DictionaryToRect(*bounds_dict, &devtools_bounds_);

  view_.reset(CreateInspectableContentsView(this));
}

InspectableWebContentsImpl::~InspectableWebContentsImpl() {
}

InspectableWebContentsView* InspectableWebContentsImpl::GetView() const {
  return view_.get();
}

content::WebContents* InspectableWebContentsImpl::GetWebContents() const {
  return web_contents_.get();
}

void InspectableWebContentsImpl::ShowDevTools() {
  // Show devtools only after it has done loading, this is to make sure the
  // SetIsDocked is called *BEFORE* ShowDevTools.
  if (!devtools_web_contents_) {
    embedder_message_dispatcher_.reset(
        new DevToolsEmbedderMessageDispatcher(this));

    auto create_params = content::WebContents::CreateParams(
        web_contents_->GetBrowserContext());
    devtools_web_contents_.reset(content::WebContents::Create(create_params));

    Observe(devtools_web_contents_.get());
    devtools_web_contents_->SetDelegate(this);

    agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(
        web_contents_->GetRenderViewHost());
    frontend_host_.reset(
        content::DevToolsClientHost::CreateDevToolsFrontendHost(
            devtools_web_contents_.get(), this));
    content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
        agent_host_, frontend_host_.get());

    GURL devtools_url(kChromeUIDevToolsURL);
    devtools_web_contents_->GetController().LoadURL(
        devtools_url,
        content::Referrer(),
        content::PAGE_TRANSITION_AUTO_TOPLEVEL,
        std::string());
  } else {
    view_->ShowDevTools();
  }
}

void InspectableWebContentsImpl::CloseDevTools() {
  if (devtools_web_contents_) {
    view_->CloseDevTools();
    devtools_web_contents_.reset();
    web_contents_->Focus();
  }
}

bool InspectableWebContentsImpl::IsDevToolsViewShowing() {
  return devtools_web_contents_ && view_->IsDevToolsViewShowing();
}

gfx::Rect InspectableWebContentsImpl::GetDevToolsBounds() const {
  return devtools_bounds_;
}

void InspectableWebContentsImpl::SaveDevToolsBounds(const gfx::Rect& bounds) {
  auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
  base::DictionaryValue bounds_dict;
  RectToDictionary(bounds, &bounds_dict);
  context->prefs()->Set(kDevToolsBoundsPref, bounds_dict);
  devtools_bounds_ = bounds;
}

void InspectableWebContentsImpl::ActivateWindow() {
}

void InspectableWebContentsImpl::CloseWindow() {
  devtools_web_contents()->DispatchBeforeUnload(false);
}

void InspectableWebContentsImpl::SetContentsResizingStrategy(
    const gfx::Insets& insets, const gfx::Size& min_size) {
  DevToolsContentsResizingStrategy strategy(insets, min_size);
  if (contents_resizing_strategy_.Equals(strategy))
    return;

  contents_resizing_strategy_.CopyFrom(strategy);
  view_->SetContentsResizingStrategy(contents_resizing_strategy_);
}

void InspectableWebContentsImpl::InspectElementCompleted() {
}

void InspectableWebContentsImpl::MoveWindow(int x, int y) {
}

void InspectableWebContentsImpl::SetIsDocked(bool docked) {
  view_->SetIsDocked(docked);
}

void InspectableWebContentsImpl::OpenInNewTab(const std::string& url) {
}

void InspectableWebContentsImpl::SaveToFile(
    const std::string& url, const std::string& content, bool save_as) {
  if (delegate_)
    delegate_->DevToolsSaveToFile(url, content, save_as);
}

void InspectableWebContentsImpl::AppendToFile(
    const std::string& url, const std::string& content) {
  if (delegate_)
    delegate_->DevToolsAppendToFile(url, content);
}

void InspectableWebContentsImpl::RequestFileSystems() {
    devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(
        base::ASCIIToUTF16("InspectorFrontendAPI.fileSystemsLoaded([])"));
}

void InspectableWebContentsImpl::AddFileSystem() {
}

void InspectableWebContentsImpl::RemoveFileSystem(
    const std::string& file_system_path) {
}

void InspectableWebContentsImpl::UpgradeDraggedFileSystemPermissions(
    const std::string& file_system_url) {
}

void InspectableWebContentsImpl::IndexPath(
    int request_id, const std::string& file_system_path) {
}

void InspectableWebContentsImpl::StopIndexing(int request_id) {
}

void InspectableWebContentsImpl::SearchInPath(
    int request_id,
    const std::string& file_system_path,
    const std::string& query) {
}

void InspectableWebContentsImpl::ZoomIn() {
}

void InspectableWebContentsImpl::ZoomOut() {
}

void InspectableWebContentsImpl::ResetZoom() {
}

void InspectableWebContentsImpl::DispatchOnEmbedder(
    const std::string& message) {
  std::string method;
  base::ListValue params;
  int id;
  if (!ParseMessage(message, &method, &params, &id)) {
    LOG(ERROR) << "Invalid message was sent to embedder: " << message;
    return;
  }

  std::string error = embedder_message_dispatcher_->Dispatch(method, &params);
  if (id) {
    std::string ack = base::StringPrintf(
        "InspectorFrontendAPI.embedderMessageAck(%d, \"%s\");", id, error.c_str());
    devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(ack));
  }
}

void InspectableWebContentsImpl::InspectedContentsClosing() {
}

void InspectableWebContentsImpl::AboutToNavigateRenderView(
    content::RenderViewHost* render_view_host) {
  content::DevToolsClientHost::SetupDevToolsFrontendClient(
      web_contents()->GetRenderViewHost());
}

void InspectableWebContentsImpl::DidFinishLoad(int64 frame_id,
                                               const GURL& validated_url,
                                               bool is_main_frame,
                                               content::RenderViewHost*) {
  if (!is_main_frame)
    return;

  view_->ShowDevTools();
}

void InspectableWebContentsImpl::WebContentsDestroyed() {
  content::DevToolsManager::GetInstance()->ClientHostClosing(
      frontend_host_.get());
  Observe(nullptr);
  agent_host_ = nullptr;
  frontend_host_.reset();
}

void InspectableWebContentsImpl::HandleKeyboardEvent(
    content::WebContents* source,
    const content::NativeWebKeyboardEvent& event) {
  auto delegate = web_contents_->GetDelegate();
  if (delegate)
    delegate->HandleKeyboardEvent(source, event);
}

void InspectableWebContentsImpl::CloseContents(content::WebContents* source) {
  CloseDevTools();
}

}  // namespace brightray
<commit_msg>Implement zoom messages for devtools.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "browser/inspectable_web_contents_impl.h"

#include "browser/browser_client.h"
#include "browser/browser_context.h"
#include "browser/browser_main_parts.h"
#include "browser/inspectable_web_contents_delegate.h"
#include "browser/inspectable_web_contents_view.h"

#include "base/json/json_reader.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"

namespace brightray {

namespace {

const double kPresetZoomFactors[] = { 0.25, 0.333, 0.5, 0.666, 0.75, 0.9, 1.0,
                                      1.1, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 4.0,
                                      5.0 };

const char kDevToolsScheme[] = "chrome-devtools";
const char kDevToolsHost[] = "devtools";
const char kChromeUIDevToolsURL[] = "chrome-devtools://devtools/devtools.html?"
                                    "can_dock=true&&"
                                    "experiments=true";
const char kDevToolsBoundsPref[] = "brightray.devtools.bounds";

const char kFrontendHostId[] = "id";
const char kFrontendHostMethod[] = "method";
const char kFrontendHostParams[] = "params";

void RectToDictionary(const gfx::Rect& bounds, base::DictionaryValue* dict) {
  dict->SetInteger("x", bounds.x());
  dict->SetInteger("y", bounds.y());
  dict->SetInteger("width", bounds.width());
  dict->SetInteger("height", bounds.height());
}

void DictionaryToRect(const base::DictionaryValue& dict, gfx::Rect* bounds) {
  int x = 0, y = 0, width = 800, height = 600;
  dict.GetInteger("x", &x);
  dict.GetInteger("y", &y);
  dict.GetInteger("width", &width);
  dict.GetInteger("height", &height);
  *bounds = gfx::Rect(x, y, width, height);
}

bool ParseMessage(const std::string& message,
                  std::string* method,
                  base::ListValue* params,
                  int* id) {
  scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
  if (!parsed_message)
    return false;

  base::DictionaryValue* dict = NULL;
  if (!parsed_message->GetAsDictionary(&dict))
    return false;
  if (!dict->GetString(kFrontendHostMethod, method))
    return false;

  // "params" is optional.
  if (dict->HasKey(kFrontendHostParams)) {
    base::ListValue* internal_params;
    if (dict->GetList(kFrontendHostParams, &internal_params))
      params->Swap(internal_params);
    else
      return false;
  }

  *id = 0;
  dict->GetInteger(kFrontendHostId, id);
  return true;
}

double GetZoomLevelForWebContents(content::WebContents* web_contents) {
  content::HostZoomMap* host_zoom_map = content::HostZoomMap::GetForBrowserContext(
      web_contents->GetBrowserContext());
  return host_zoom_map->GetZoomLevelForHostAndScheme(kDevToolsScheme, kDevToolsHost);
}

void SetZoomLevelForWebContents(content::WebContents* web_contents, double level) {
  content::HostZoomMap* host_zoom_map = content::HostZoomMap::GetForBrowserContext(
      web_contents->GetBrowserContext());
  return host_zoom_map->SetZoomLevelForHostAndScheme(kDevToolsScheme, kDevToolsHost, level);
}

double GetNextZoomLevel(double level, bool out) {
  double factor = content::ZoomLevelToZoomFactor(level);
  size_t size = arraysize(kPresetZoomFactors);
  for (size_t i = 0; i < size; ++i) {
    if (!content::ZoomValuesEqual(kPresetZoomFactors[i], factor))
      continue;
    if (out && i > 0)
      return content::ZoomFactorToZoomLevel(kPresetZoomFactors[i - 1]);
    if (!out && i != size - 1)
      return content::ZoomFactorToZoomLevel(kPresetZoomFactors[i + 1]);
  }
  return level;
}

}  // namespace

// Implemented separately on each platform.
InspectableWebContentsView* CreateInspectableContentsView(
    InspectableWebContentsImpl* inspectable_web_contents_impl);

void InspectableWebContentsImpl::RegisterPrefs(PrefRegistrySimple* registry) {
  auto bounds_dict = make_scoped_ptr(new base::DictionaryValue);
  RectToDictionary(gfx::Rect(0, 0, 800, 600), bounds_dict.get());
  registry->RegisterDictionaryPref(kDevToolsBoundsPref, bounds_dict.release());
}

InspectableWebContentsImpl::InspectableWebContentsImpl(
    content::WebContents* web_contents)
    : web_contents_(web_contents),
      delegate_(nullptr) {
  auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
  auto bounds_dict = context->prefs()->GetDictionary(kDevToolsBoundsPref);
  if (bounds_dict)
    DictionaryToRect(*bounds_dict, &devtools_bounds_);

  view_.reset(CreateInspectableContentsView(this));
}

InspectableWebContentsImpl::~InspectableWebContentsImpl() {
}

InspectableWebContentsView* InspectableWebContentsImpl::GetView() const {
  return view_.get();
}

content::WebContents* InspectableWebContentsImpl::GetWebContents() const {
  return web_contents_.get();
}

void InspectableWebContentsImpl::ShowDevTools() {
  // Show devtools only after it has done loading, this is to make sure the
  // SetIsDocked is called *BEFORE* ShowDevTools.
  if (!devtools_web_contents_) {
    embedder_message_dispatcher_.reset(
        new DevToolsEmbedderMessageDispatcher(this));

    auto create_params = content::WebContents::CreateParams(
        web_contents_->GetBrowserContext());
    devtools_web_contents_.reset(content::WebContents::Create(create_params));

    Observe(devtools_web_contents_.get());
    devtools_web_contents_->SetDelegate(this);

    agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(
        web_contents_->GetRenderViewHost());
    frontend_host_.reset(
        content::DevToolsClientHost::CreateDevToolsFrontendHost(
            devtools_web_contents_.get(), this));
    content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
        agent_host_, frontend_host_.get());

    GURL devtools_url(kChromeUIDevToolsURL);
    devtools_web_contents_->GetController().LoadURL(
        devtools_url,
        content::Referrer(),
        content::PAGE_TRANSITION_AUTO_TOPLEVEL,
        std::string());
  } else {
    view_->ShowDevTools();
  }
}

void InspectableWebContentsImpl::CloseDevTools() {
  if (devtools_web_contents_) {
    view_->CloseDevTools();
    devtools_web_contents_.reset();
    web_contents_->Focus();
  }
}

bool InspectableWebContentsImpl::IsDevToolsViewShowing() {
  return devtools_web_contents_ && view_->IsDevToolsViewShowing();
}

gfx::Rect InspectableWebContentsImpl::GetDevToolsBounds() const {
  return devtools_bounds_;
}

void InspectableWebContentsImpl::SaveDevToolsBounds(const gfx::Rect& bounds) {
  auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
  base::DictionaryValue bounds_dict;
  RectToDictionary(bounds, &bounds_dict);
  context->prefs()->Set(kDevToolsBoundsPref, bounds_dict);
  devtools_bounds_ = bounds;
}

void InspectableWebContentsImpl::ActivateWindow() {
}

void InspectableWebContentsImpl::CloseWindow() {
  devtools_web_contents()->DispatchBeforeUnload(false);
}

void InspectableWebContentsImpl::SetContentsResizingStrategy(
    const gfx::Insets& insets, const gfx::Size& min_size) {
  DevToolsContentsResizingStrategy strategy(insets, min_size);
  if (contents_resizing_strategy_.Equals(strategy))
    return;

  contents_resizing_strategy_.CopyFrom(strategy);
  view_->SetContentsResizingStrategy(contents_resizing_strategy_);
}

void InspectableWebContentsImpl::InspectElementCompleted() {
}

void InspectableWebContentsImpl::MoveWindow(int x, int y) {
}

void InspectableWebContentsImpl::SetIsDocked(bool docked) {
  view_->SetIsDocked(docked);
}

void InspectableWebContentsImpl::OpenInNewTab(const std::string& url) {
}

void InspectableWebContentsImpl::SaveToFile(
    const std::string& url, const std::string& content, bool save_as) {
  if (delegate_)
    delegate_->DevToolsSaveToFile(url, content, save_as);
}

void InspectableWebContentsImpl::AppendToFile(
    const std::string& url, const std::string& content) {
  if (delegate_)
    delegate_->DevToolsAppendToFile(url, content);
}

void InspectableWebContentsImpl::RequestFileSystems() {
    devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(
        base::ASCIIToUTF16("InspectorFrontendAPI.fileSystemsLoaded([])"));
}

void InspectableWebContentsImpl::AddFileSystem() {
}

void InspectableWebContentsImpl::RemoveFileSystem(
    const std::string& file_system_path) {
}

void InspectableWebContentsImpl::UpgradeDraggedFileSystemPermissions(
    const std::string& file_system_url) {
}

void InspectableWebContentsImpl::IndexPath(
    int request_id, const std::string& file_system_path) {
}

void InspectableWebContentsImpl::StopIndexing(int request_id) {
}

void InspectableWebContentsImpl::SearchInPath(
    int request_id,
    const std::string& file_system_path,
    const std::string& query) {
}

void InspectableWebContentsImpl::ZoomIn() {
  double level = GetZoomLevelForWebContents(devtools_web_contents());
  SetZoomLevelForWebContents(devtools_web_contents(), GetNextZoomLevel(level, false));
}

void InspectableWebContentsImpl::ZoomOut() {
  double level = GetZoomLevelForWebContents(devtools_web_contents());
  SetZoomLevelForWebContents(devtools_web_contents(), GetNextZoomLevel(level, true));
}

void InspectableWebContentsImpl::ResetZoom() {
  SetZoomLevelForWebContents(devtools_web_contents(), 0.);
}

void InspectableWebContentsImpl::DispatchOnEmbedder(
    const std::string& message) {
  std::string method;
  base::ListValue params;
  int id;
  if (!ParseMessage(message, &method, &params, &id)) {
    LOG(ERROR) << "Invalid message was sent to embedder: " << message;
    return;
  }

  std::string error = embedder_message_dispatcher_->Dispatch(method, &params);
  if (id) {
    std::string ack = base::StringPrintf(
        "InspectorFrontendAPI.embedderMessageAck(%d, \"%s\");", id, error.c_str());
    devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(ack));
  }
}

void InspectableWebContentsImpl::InspectedContentsClosing() {
}

void InspectableWebContentsImpl::AboutToNavigateRenderView(
    content::RenderViewHost* render_view_host) {
  content::DevToolsClientHost::SetupDevToolsFrontendClient(
      web_contents()->GetRenderViewHost());
}

void InspectableWebContentsImpl::DidFinishLoad(int64 frame_id,
                                               const GURL& validated_url,
                                               bool is_main_frame,
                                               content::RenderViewHost*) {
  if (!is_main_frame)
    return;

  view_->ShowDevTools();
}

void InspectableWebContentsImpl::WebContentsDestroyed() {
  content::DevToolsManager::GetInstance()->ClientHostClosing(
      frontend_host_.get());
  Observe(nullptr);
  agent_host_ = nullptr;
  frontend_host_.reset();
}

void InspectableWebContentsImpl::HandleKeyboardEvent(
    content::WebContents* source,
    const content::NativeWebKeyboardEvent& event) {
  auto delegate = web_contents_->GetDelegate();
  if (delegate)
    delegate->HandleKeyboardEvent(source, event);
}

void InspectableWebContentsImpl::CloseContents(content::WebContents* source) {
  CloseDevTools();
}

}  // namespace brightray
<|endoftext|>


<commit_before>#include <cstdio>
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <string>

using namespace std;

#define USAGE "Usage: \n" \
    "  occupancy_im_saver -h\n"\
    "  occupancy_im_saver [-c <to store color map>] [-f file path]"
#define DEFAULT_FILE "/tmp/occupancy_image.png"

void imCb(const sensor_msgs::ImageConstPtr im_msg);

string file_path;
string topic_name = "occupancy_image";
bool awaiting_image = false;

int main(int argc, char** argv)
{
    file_path = DEFAULT_FILE;
    for(int i=1; i<argc; i++)
    {
        if(!strcmp(argv[i], "-h"))
        {
            puts(USAGE);
            return 0;
        }
        else if(!strcmp(argv[i], "-c"))
        {
            topic_name += "_color";
        }
        else if(!strcmp(argv[i], "-f"))
        {
            if(++i < argc)
                file_path = argv[i];
            else
            {
                puts(USAGE);
                return 1;
            }
        }
        else
        {
            puts(USAGE);
            return 1;
        }
    }

    ros::init(argc, argv, "occupancy_image_publisher");
    ros::NodeHandle n;
    image_transport::ImageTransport it(n);
    image_transport::Subscriber im_sub = it.subscribe(topic_name,1,imCb);

    awaiting_image = true;
    ROS_INFO("Wainting for image with topic name: %s", topic_name.c_str());
    ros::Rate r(5);
    while (n.ok() && awaiting_image) {
        ros::spinOnce();
        r.sleep();
    }
    return 0;
}

void imCb(const sensor_msgs::ImageConstPtr im_msg)
{
    cv_bridge::CvImageConstPtr cv_ptr;
    // Convert image to opencv
    try
    {
        cv_ptr = cv_bridge::toCvShare(im_msg, sensor_msgs::image_encodings::BGR8);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }
    ROS_INFO("Storing image to path: %s", file_path.c_str());
    cv::imwrite(file_path, cv_ptr->image);
    awaiting_image = false;
}
<commit_msg>store occupancy without name conflict with occupancy publisher<commit_after>#include <cstdio>
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <string>

using namespace std;

#define USAGE "Usage: \n" \
    "  occupancy_im_saver -h\n"\
    "  occupancy_im_saver [-c <to store color map>] [-f file path]"
#define DEFAULT_FILE "/tmp/occupancy_image.png"

void imCb(const sensor_msgs::ImageConstPtr im_msg);

string file_path;
string topic_name = "/occupancy_image";
bool awaiting_image = false;

int main(int argc, char** argv)
{
    file_path = DEFAULT_FILE;
    for(int i=1; i<argc; i++)
    {
        if(!strcmp(argv[i], "-h"))
        {
            puts(USAGE);
            return 0;
        }
        else if(!strcmp(argv[i], "-c"))
        {
            topic_name += "_color";
        }
        else if(!strcmp(argv[i], "-f"))
        {
            if(++i < argc)
                file_path = argv[i];
            else
            {
                puts(USAGE);
                return 1;
            }
        }
        else
        {
            puts(USAGE);
            return 1;
        }
    }

    ros::init(argc, argv, "occupancy_image_saver");
    ros::NodeHandle n;
    image_transport::ImageTransport it(n);
    image_transport::Subscriber im_sub = it.subscribe(topic_name,1,imCb);

    awaiting_image = true;
    ROS_INFO("Wainting for image with topic name: %s", topic_name.c_str());
    ros::Rate r(5);
    while (n.ok() && awaiting_image) {
        ros::spinOnce();
        r.sleep();
    }
    return 0;
}

void imCb(const sensor_msgs::ImageConstPtr im_msg)
{
    cv_bridge::CvImageConstPtr cv_ptr;
    // Convert image to opencv
    try
    {
        cv_ptr = cv_bridge::toCvShare(im_msg, sensor_msgs::image_encodings::BGR8);
    }
    catch (cv_bridge::Exception& e)
    {
        ROS_ERROR("cv_bridge exception: %s", e.what());
        return;
    }
    ROS_INFO("Storing image to path: %s", file_path.c_str());
    cv::imwrite(file_path, cv_ptr->image);
    awaiting_image = false;
}
<|endoftext|>


<commit_before>#include "collision.h"

Collision::Collision(){
}
    bool Collision::SphereVersusSphere(int x1 ,int y1 ,int z1 ,int size1 ,int x2 ,int y2 ,int z2 ,int size2){

        return     ((x1 - x2) * (x1 - x2) +
                    (y1 - y2) * (y1 - y2) +
                    (z1 - z2) * (z1 - z2)) >= ((size1+size2) * (size1+size2));
    }

    bool Collision::SphereVersusPoint(int sphereX ,int sphereY ,int sphereZ ,int sphereSize ,int PointX ,int PointY ,int PointZ){

        return ((sphereX - PointX) * (sphereX - PointX) +
            (sphereY - PointY) * (sphereY - PointY) +
            (sphereZ - PointZ) * (sphereZ - PointZ) >= (sphereSize * sphereSize));
    }

    bool Collision::BoxVersusPoint(int PointX ,int PointY ,int PointZ ,int boxMinX ,int boxMinY ,int boxMinZ ,int boxMaxX ,int boxMaxY ,int boxMaxZ){

        return (PointX >= boxMinX && PointX <= boxMaxX) &&
               (PointY >= boxMinY && PointY <= boxMaxY) &&
               (PointZ >= boxMinZ && PointZ <= boxMaxZ);
    }

    bool Collision::BoxVersusBox(int boxMinX1 ,int boxMinY1 ,int boxMinZ1 ,int boxMaxX1 ,int boxMaxY1 ,int boxMaxZ1 ,int boxMinX2 ,int boxMinY2 ,int boxMinZ2 ,int boxMaxX2 ,int boxMaxY2 ,int boxMaxZ2){

        return (boxMinX1 <= boxMaxX2 && boxMaxX1 >= boxMinX2) &&
               (boxMinY1 <= boxMaxY2 && boxMaxY1 >= boxMinY2) &&
               (boxMinZ1 <= boxMaxZ2 && boxMaxZ1 >= boxMinZ2);

    }

    bool Collision::SphereVersusBox(int sphereX ,int sphereY ,int sphereZ ,int sphereSize ,int boxMinX ,int boxMinY ,int boxMinZ ,int boxMaxX ,int boxMaxY ,int boxMaxZ){
        //Math.max(box.minX, Math.min(sphere.x, box.maxX);
        int x = Max(boxMinX, Min(sphereX ,boxMaxX));
        int y = Max(boxMinY, Min(sphereY ,boxMaxY));
        int z = Max(boxMinZ, Min(sphereZ ,boxMaxZ));

        return (x - sphereX) * (x - sphereX) +
            (y - sphereY) * (y - sphereY) +
            (z - sphereZ) * (z - sphereZ) < (sphereSize * sphereSize);
    }

    int Collision::Min(int i1 ,int i2){
        if(i1 < i2){
            return i1;
        }else{
            return i2;
        }
    }

    int Collision::Max(int i1 ,int i2){
        if(i1 > i2){
            return i1;
        }else{
            return i2;
        }
    }

<commit_msg>nothing<commit_after>#include "collision.h"

Collision::Collision(){
}
    bool Collision::SphereVersusSphere(int x1 ,int y1 ,int z1 ,int size1 ,int x2 ,int y2 ,int z2 ,int size2){

        return     ((x1 - x2) * (x1 - x2) +
                    (y1 - y2) * (y1 - y2) +
                    (z1 - z2) * (z1 - z2)) >= ((size1+size2) * (size1+size2));
    }

    bool Collision::SphereVersusPoint(int sphereX ,int sphereY ,int sphereZ ,int sphereSize ,int PointX ,int PointY ,int PointZ){

        return ((sphereX - PointX) * (sphereX - PointX) +
            (sphereY - PointY) * (sphereY - PointY) +
            (sphereZ - PointZ) * (sphereZ - PointZ) >= (sphereSize * sphereSize));
    }

    bool Collision::BoxVersusPoint(int PointX ,int PointY ,int PointZ ,int boxMinX ,int boxMinY ,int boxMinZ ,int boxMaxX ,int boxMaxY ,int boxMaxZ){

        return (PointX >= boxMinX && PointX <= boxMaxX) &&
               (PointY >= boxMinY && PointY <= boxMaxY) &&
               (PointZ >= boxMinZ && PointZ <= boxMaxZ);
    }

    bool Collision::BoxVersusBox(int boxMinX1 ,int boxMinY1 ,int boxMinZ1 ,int boxMaxX1 ,int boxMaxY1 ,int boxMaxZ1 ,int boxMinX2 ,int boxMinY2 ,int boxMinZ2 ,int boxMaxX2 ,int boxMaxY2 ,int boxMaxZ2){

        return (boxMinX1 <= boxMaxX2 && boxMaxX1 >= boxMinX2) &&
               (boxMinY1 <= boxMaxY2 && boxMaxY1 >= boxMinY2) &&
               (boxMinZ1 <= boxMaxZ2 && boxMaxZ1 >= boxMinZ2);

    }

    bool Collision::SphereVersusBox(int sphereX ,int sphereY ,int sphereZ ,int sphereSize ,int boxMinX ,int boxMinY ,int boxMinZ ,int boxMaxX ,int boxMaxY ,int boxMaxZ){
        //Math.max(box.minX, Math.min(sphere.x, box.maxX);
        int x = Max(boxMinX, Min(sphereX ,boxMaxX));
        int y = Max(boxMinY, Min(sphereY ,boxMaxY));
        int z = Max(boxMinZ, Min(sphereZ ,boxMaxZ));

        return (x - sphereX) * (x - sphereX) +
            (y - sphereY) * (y - sphereY) +
            (z - sphereZ) * (z - sphereZ) < (sphereSize * sphereSize);
    }

    int Collision::Min(int i1 ,int i2){
        if(i1 < i2){
            return i1;
        }else{
            return i2;
        }
    }

    int Collision::Max(int i1 ,int i2){
        if(i1 > i2){
            return i1;
        }else{
            return i2;
        }
    }

<|endoftext|>


<commit_before>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ****************************************************************************/

/**
 * @file
 * @brief Predicate --- Standard String Implementation
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#include <predicate/standard_string.hpp>

#include <predicate/call_factory.hpp>
#include <predicate/call_helpers.hpp>
#include <predicate/validate.hpp>

#include <boost/regex.hpp>

using namespace std;

namespace IronBee {
namespace Predicate {
namespace Standard {

struct StringReplaceRx::data_t
{
    boost::regex expression;
    string       replacement;
};

StringReplaceRx::StringReplaceRx() :
    m_data(new data_t())
{
    // nop
}

string StringReplaceRx::name() const
{
    return "stringReplaceRx";
}

bool StringReplaceRx::validate(NodeReporter reporter) const
{
    bool result = true;
    result = Validate::n_children(reporter, 3) && result;
    result = Validate::nth_child_is_string(reporter, 0) && result;
    result = Validate::nth_child_is_string(reporter, 1) && result;

    return result;
}

void StringReplaceRx::pre_eval(Environment environment, NodeReporter reporter)
{
    // Validation guarantees that the first two children are string
    // literals and thus can be evaluated with default EvalContext.

    node_list_t::const_iterator child_i = children().begin();
    Value expression_value = literal_value(*child_i);
    ++child_i;
    Value replacement_value = literal_value(*child_i);

    ConstByteString expression = expression_value.value_as_byte_string();
    ConstByteString replacement  = replacement_value.value_as_byte_string();

    if (! expression) {
        reporter.error("Missing expression.");
        return;
    }
    if (! replacement) {
        reporter.error("Missing replacement.");
        return;
    }

    try {
        m_data->expression.assign(
            expression.const_data(), expression.length(),
            boost::regex_constants::normal
        );
    }
    catch (const boost::bad_expression& e) {
        reporter.error("Could not compile regexp: " + expression.to_s() + " (" + e.what() + ")");
        return;
    }

    m_data->replacement = replacement.to_s();
}

Value StringReplaceRx::value_calculate(
    Value           v,
    GraphEvalState& graph_eval_state,
    EvalContext     context
) const
{
    if (! m_data) {
        BOOST_THROW_EXCEPTION(
            einval() << errinfo_what(
                "Evaluation without pre evaluation!"
            )
        );
    }

    if (v.type() != Value::BYTE_STRING) {
        return Value();
    }

    ConstByteString text = v.value_as_byte_string();
    boost::shared_ptr<vector<char> > result(new vector<char>());
    // value_to_data() ensures that a copy is associated with the memory
    // pool and will be deleted when the memory pool goes away.
    assert(context.memory_pool());
    value_to_data(result, context.memory_pool().ib());

    boost::regex_replace(
        back_inserter(*result),
        text.const_data(), text.const_data() + text.length(),
        m_data->expression,
        m_data->replacement
    );

    return Field::create_byte_string(
        context.memory_pool(),
        v.name(), v.name_length(),
        ByteString::create_alias(
            context.memory_pool(),
            result->data(), result->size()
        )
    );
}

void StringReplaceRx::eval_calculate(
    GraphEvalState& graph_eval_state,
    EvalContext     context
) const
{
    const node_p& input_node = children().back();

    map_calculate(input_node, graph_eval_state, context);
}

void load_string(CallFactory& to)
{
    to
        .add<StringReplaceRx>()
        ;
}

} // Standard
} // Predicate
} // IronBee
<commit_msg>predicate/standard_string: Fix bug in StringReplaceRx that occurred when the result was the empty string.<commit_after>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ****************************************************************************/

/**
 * @file
 * @brief Predicate --- Standard String Implementation
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#include <predicate/standard_string.hpp>

#include <predicate/call_factory.hpp>
#include <predicate/call_helpers.hpp>
#include <predicate/validate.hpp>

#include <boost/regex.hpp>

using namespace std;

namespace IronBee {
namespace Predicate {
namespace Standard {

struct StringReplaceRx::data_t
{
    boost::regex expression;
    string       replacement;
};

StringReplaceRx::StringReplaceRx() :
    m_data(new data_t())
{
    // nop
}

string StringReplaceRx::name() const
{
    return "stringReplaceRx";
}

bool StringReplaceRx::validate(NodeReporter reporter) const
{
    bool result = true;
    result = Validate::n_children(reporter, 3) && result;
    result = Validate::nth_child_is_string(reporter, 0) && result;
    result = Validate::nth_child_is_string(reporter, 1) && result;

    return result;
}

void StringReplaceRx::pre_eval(Environment environment, NodeReporter reporter)
{
    // Validation guarantees that the first two children are string
    // literals and thus can be evaluated with default EvalContext.

    node_list_t::const_iterator child_i = children().begin();
    Value expression_value = literal_value(*child_i);
    ++child_i;
    Value replacement_value = literal_value(*child_i);

    ConstByteString expression = expression_value.value_as_byte_string();
    ConstByteString replacement  = replacement_value.value_as_byte_string();

    if (! expression) {
        reporter.error("Missing expression.");
        return;
    }
    if (! replacement) {
        reporter.error("Missing replacement.");
        return;
    }

    try {
        m_data->expression.assign(
            expression.const_data(), expression.length(),
            boost::regex_constants::normal
        );
    }
    catch (const boost::bad_expression& e) {
        reporter.error("Could not compile regexp: " + expression.to_s() + " (" + e.what() + ")");
        return;
    }

    m_data->replacement = replacement.to_s();
}

Value StringReplaceRx::value_calculate(
    Value           v,
    GraphEvalState& graph_eval_state,
    EvalContext     context
) const
{
    if (! m_data) {
        BOOST_THROW_EXCEPTION(
            einval() << errinfo_what(
                "Evaluation without pre evaluation!"
            )
        );
    }

    if (v.type() != Value::BYTE_STRING) {
        return Value();
    }

    ConstByteString text = v.value_as_byte_string();
    boost::shared_ptr<vector<char> > result(new vector<char>());
    // Ensure that result.data() is non-null, even if we never insert
    // anything.
    result->reserve(1);

    // value_to_data() ensures that a copy is associated with the memory
    // pool and will be deleted when the memory pool goes away.
    assert(context.memory_pool());
    value_to_data(result, context.memory_pool().ib());

    boost::regex_replace(
        back_inserter(*result),
        text.const_data(), text.const_data() + text.length(),
        m_data->expression,
        m_data->replacement
    );

    return Field::create_byte_string(
        context.memory_pool(),
        v.name(), v.name_length(),
        ByteString::create_alias(
            context.memory_pool(),
            result->data(), result->size()
        )
    );
}

void StringReplaceRx::eval_calculate(
    GraphEvalState& graph_eval_state,
    EvalContext     context
) const
{
    const node_p& input_node = children().back();

    map_calculate(input_node, graph_eval_state, context);
}

void load_string(CallFactory& to)
{
    to
        .add<StringReplaceRx>()
        ;
}

} // Standard
} // Predicate
} // IronBee
<|endoftext|>


<commit_before>#include <tightdb/column_mixed.hpp>

namespace tightdb {

ColumnMixed::~ColumnMixed()
{
    delete m_types;
    delete m_refs;
    delete m_data;
    delete m_array;
}

void ColumnMixed::Destroy()
{
    if (m_array != NULL)
        m_array->Destroy();
}

void ColumnMixed::SetParent(ArrayParent *parent, size_t pndx)
{
    m_array->SetParent(parent, pndx);
}

void ColumnMixed::UpdateFromParent()
{
    if (!m_array->UpdateFromParent())
        return;

    m_types->UpdateFromParent();
    m_refs->UpdateFromParent();
    if (m_data)
        m_data->UpdateFromParent();
}

void ColumnMixed::Create(Allocator& alloc, const Table* table, size_t column_ndx)
{
    m_array = new Array(COLUMN_HASREFS, NULL, 0, alloc);

    m_types = new Column(COLUMN_NORMAL, alloc);
    m_refs  = new RefsColumn(alloc, table, column_ndx);

    m_array->add(m_types->GetRef());
    m_array->add(m_refs->GetRef());

    m_types->SetParent(m_array, 0);
    m_refs->SetParent(m_array, 1);
}

void ColumnMixed::Create(Allocator& alloc, const Table* table, size_t column_ndx,
                         ArrayParent* parent, size_t ndx_in_parent, size_t ref)
{
    m_array = new Array(ref, parent, ndx_in_parent, alloc);
    TIGHTDB_ASSERT(m_array->Size() == 2 || m_array->Size() == 3);

    const size_t types_ref = m_array->GetAsRef(0);
    const size_t refs_ref  = m_array->GetAsRef(1);

    m_types = new Column(types_ref, m_array, 0, alloc);
    m_refs  = new RefsColumn(alloc, table, column_ndx, m_array, 1, refs_ref);
    TIGHTDB_ASSERT(m_types->Size() == m_refs->Size());

    // Binary column with values that does not fit in refs
    // is only there if needed
    if (m_array->Size() == 3) {
        const size_t data_ref = m_array->GetAsRef(2);
        m_data = new ColumnBinary(data_ref, m_array, 2, alloc);
    }
}

void ColumnMixed::InitDataColumn()
{
    if (m_data)
        return;

    TIGHTDB_ASSERT(m_array->Size() == 2);

    // Create new data column for items that do not fit in refs
    m_data = new ColumnBinary(m_array->GetAllocator());
    const size_t ref = m_data->GetRef();

    m_array->add(ref);
    m_data->SetParent(m_array, 2);
}

void ColumnMixed::clear_value(size_t ndx, MixedColType newtype)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());

    const MixedColType type = (MixedColType)m_types->Get(ndx);
    if (type != MIXED_COL_INT) {
        switch (type) {
            case MIXED_COL_INT_NEG:
            case MIXED_COL_BOOL:
            case MIXED_COL_DATE:
            case MIXED_COL_FLOAT:
            case MIXED_COL_DOUBLE:
            case MIXED_COL_DOUBLE_NEG:
                break;
            case MIXED_COL_STRING:
            case MIXED_COL_BINARY:
            {
                // If item is in middle of the column, we just clear
                // it to avoid having to adjust refs to following items
                const size_t ref = m_refs->GetAsRef(ndx) >> 1;
                if (ref == m_data->Size()-1)
                    m_data->Delete(ref);
                else
                    m_data->Set(ref, "", 0);
                break;
            }
            case MIXED_COL_TABLE:
            {
                // Delete entire table
                const size_t ref = m_refs->GetAsRef(ndx);
                Array top(ref, (Array*)NULL, 0, m_array->GetAllocator());
                top.Destroy();
                break;
            }
            default:
                TIGHTDB_ASSERT(false);
        }
    }
    if (type != newtype)
        m_types->Set(ndx, newtype);
}

void ColumnMixed::Delete(size_t ndx)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());

    // Remove refs or binary data
    clear_value(ndx, MIXED_COL_INT);

    m_types->Delete(ndx);
    m_refs->Delete(ndx);

    invalidate_subtables();
}

void ColumnMixed::Clear()
{
    m_types->Clear();
    m_refs->Clear();
    if (m_data)
        m_data->Clear();
}

DataType ColumnMixed::get_type(size_t ndx) const TIGHTDB_NOEXCEPT
{
    TIGHTDB_ASSERT(ndx < m_types->Size());
    MixedColType coltype = static_cast<MixedColType>(m_types->Get(ndx));
    switch (coltype) {
        case MIXED_COL_INT_NEG:     return type_Int;
        case MIXED_COL_DOUBLE_NEG:  return type_Double;
        default: return static_cast<ColumnType>(coltype);   // all others must be in sync with ColumnType
    }
}

void ColumnMixed::fill(size_t count)
{
    TIGHTDB_ASSERT(is_empty());

    // Fill column with default values
    // TODO: this is a very naive approach
    // we could speedup by creating full nodes directly
    for (size_t i = 0; i < count; ++i) {
        m_types->Insert(i, MIXED_COL_INT);
    }
    for (size_t i = 0; i < count; ++i) {
        m_refs->Insert(i, 1); // 1 is zero shifted one and low bit set;
    }

#ifdef TIGHTDB_DEBUG
    Verify();
#endif
}

void ColumnMixed::set_string(size_t ndx, const char* value)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());
    InitDataColumn();

    const MixedColType type = (MixedColType)m_types->Get(ndx);
    const size_t len = strlen(value)+1;

    // See if we can reuse data position
    if (type == MIXED_COL_STRING) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
    }
    else if (type == MIXED_COL_BINARY) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
        m_types->Set(ndx, MIXED_COL_STRING);
    }
    else {
        // Remove refs or binary data
        clear_value(ndx, MIXED_COL_STRING);

        // Add value to data column
        const size_t ref = m_data->Size();
        m_data->add(value, len);

        // Shift value one bit and set lowest bit to indicate that this is not a ref
        const int64_t v = (ref << 1) + 1;

        m_types->Set(ndx, MIXED_COL_STRING);
        m_refs->Set(ndx, v);
    }
}

void ColumnMixed::set_binary(size_t ndx, const char* value, size_t len)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());
    InitDataColumn();

    const MixedColType type = (MixedColType)m_types->Get(ndx);

    // See if we can reuse data position
    if (type == MIXED_COL_STRING) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
        m_types->Set(ndx, MIXED_COL_BINARY);
    }
    else if (type == MIXED_COL_BINARY) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
    }
    else {
        // Remove refs or binary data
        clear_value(ndx, MIXED_COL_BINARY);

        // Add value to data column
        const size_t ref = m_data->Size();
        m_data->add(value, len);

        // Shift value one bit and set lowest bit to indicate that this is not a ref
        const int64_t v = (ref << 1) + 1;

        m_types->Set(ndx, MIXED_COL_BINARY);
        m_refs->Set(ndx, v);
    }
}

bool ColumnMixed::Compare(const ColumnMixed& c) const
{
    const size_t n = Size();
    if (c.Size() != n)
        return false;

    for (size_t i=0; i<n; ++i) {
        const DataType type = get_type(i);
        if (c.get_type(i) != type)
            return false;
        switch (type) {
        case type_Int:
            if (get_int(i) != c.get_int(i)) return false;
            break;
        case type_Bool:
            if (get_bool(i) != c.get_bool(i)) return false;
            break;
        case type_Date:
            if (get_date(i) != c.get_date(i)) return false;
            break;
        case type_Float:
            if (get_float(i) != c.get_float(i)) return false;
            break;
        case type_Double:
            if (get_double(i) != c.get_double(i)) return false;
            break;
        case type_String:
            if (strcmp(get_string(i), c.get_string(i)) != 0) return false;
            break;
        case type_Binary:
            {
                const BinaryData d1 = get_binary(i);
                const BinaryData d2 = c.get_binary(i);
                if (d1.len != d2.len || !std::equal(d1.pointer, d1.pointer+d1.len, d2.pointer))
                    return false;
            }
            break;
        case type_Table:
            {
                ConstTableRef t1 = get_subtable_ptr(i)->get_table_ref();
                ConstTableRef t2 = c.get_subtable_ptr(i)->get_table_ref();
                if (*t1 != *t2)
                    return false;
            }
            break;
        case type_Mixed:
            TIGHTDB_ASSERT(false);
            break;
        }
    }
    return true;
}

#ifdef TIGHTDB_DEBUG

void ColumnMixed::Verify() const
{
    m_array->Verify();
    m_types->Verify();
    m_refs->Verify();
    if (m_data) m_data->Verify();

    // types and refs should be in sync
    const size_t types_len = m_types->Size();
    const size_t refs_len  = m_refs->Size();
    TIGHTDB_ASSERT(types_len == refs_len);

    // Verify each sub-table
    const size_t count = Size();
    for (size_t i = 0; i < count; ++i) {
        const size_t tref = m_refs->GetAsRef(i);
        if (tref == 0 || tref & 0x1) continue;
        ConstTableRef subtable = m_refs->get_subtable(i);
        subtable->Verify();
    }
}

void ColumnMixed::ToDot(std::ostream& out, const char* title) const
{
    const size_t ref = GetRef();

    out << "subgraph cluster_columnmixed" << ref << " {" << std::endl;
    out << " label = \"ColumnMixed";
    if (title) out << "\\n'" << title << "'";
    out << "\";" << std::endl;

    m_array->ToDot(out, "mixed_top");

    // Write sub-tables
    const size_t count = Size();
    for (size_t i = 0; i < count; ++i) {
        const MixedColType type = (MixedColType)m_types->Get(i);
        if (type != MIXED_COL_TABLE) continue;
        ConstTableRef subtable = m_refs->get_subtable(i);
        subtable->to_dot(out);
    }

    m_types->ToDot(out, "types");
    m_refs->ToDot(out, "refs");

    if (m_array->Size() > 2) {
        m_data->ToDot(out, "data");
    }

    out << "}" << std::endl;
}

#endif // TIGHTDB_DEBUG

} // namespace tightdb
<commit_msg>Fix for: Merge branch 'error_handling_plus_float' into column_type_rename<commit_after>#include <tightdb/column_mixed.hpp>

namespace tightdb {

ColumnMixed::~ColumnMixed()
{
    delete m_types;
    delete m_refs;
    delete m_data;
    delete m_array;
}

void ColumnMixed::Destroy()
{
    if (m_array != NULL)
        m_array->Destroy();
}

void ColumnMixed::SetParent(ArrayParent *parent, size_t pndx)
{
    m_array->SetParent(parent, pndx);
}

void ColumnMixed::UpdateFromParent()
{
    if (!m_array->UpdateFromParent())
        return;

    m_types->UpdateFromParent();
    m_refs->UpdateFromParent();
    if (m_data)
        m_data->UpdateFromParent();
}

void ColumnMixed::Create(Allocator& alloc, const Table* table, size_t column_ndx)
{
    m_array = new Array(COLUMN_HASREFS, NULL, 0, alloc);

    m_types = new Column(COLUMN_NORMAL, alloc);
    m_refs  = new RefsColumn(alloc, table, column_ndx);

    m_array->add(m_types->GetRef());
    m_array->add(m_refs->GetRef());

    m_types->SetParent(m_array, 0);
    m_refs->SetParent(m_array, 1);
}

void ColumnMixed::Create(Allocator& alloc, const Table* table, size_t column_ndx,
                         ArrayParent* parent, size_t ndx_in_parent, size_t ref)
{
    m_array = new Array(ref, parent, ndx_in_parent, alloc);
    TIGHTDB_ASSERT(m_array->Size() == 2 || m_array->Size() == 3);

    const size_t types_ref = m_array->GetAsRef(0);
    const size_t refs_ref  = m_array->GetAsRef(1);

    m_types = new Column(types_ref, m_array, 0, alloc);
    m_refs  = new RefsColumn(alloc, table, column_ndx, m_array, 1, refs_ref);
    TIGHTDB_ASSERT(m_types->Size() == m_refs->Size());

    // Binary column with values that does not fit in refs
    // is only there if needed
    if (m_array->Size() == 3) {
        const size_t data_ref = m_array->GetAsRef(2);
        m_data = new ColumnBinary(data_ref, m_array, 2, alloc);
    }
}

void ColumnMixed::InitDataColumn()
{
    if (m_data)
        return;

    TIGHTDB_ASSERT(m_array->Size() == 2);

    // Create new data column for items that do not fit in refs
    m_data = new ColumnBinary(m_array->GetAllocator());
    const size_t ref = m_data->GetRef();

    m_array->add(ref);
    m_data->SetParent(m_array, 2);
}

void ColumnMixed::clear_value(size_t ndx, MixedColType newtype)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());

    const MixedColType type = (MixedColType)m_types->Get(ndx);
    if (type != MIXED_COL_INT) {
        switch (type) {
            case MIXED_COL_INT_NEG:
            case MIXED_COL_BOOL:
            case MIXED_COL_DATE:
            case MIXED_COL_FLOAT:
            case MIXED_COL_DOUBLE:
            case MIXED_COL_DOUBLE_NEG:
                break;
            case MIXED_COL_STRING:
            case MIXED_COL_BINARY:
            {
                // If item is in middle of the column, we just clear
                // it to avoid having to adjust refs to following items
                const size_t ref = m_refs->GetAsRef(ndx) >> 1;
                if (ref == m_data->Size()-1)
                    m_data->Delete(ref);
                else
                    m_data->Set(ref, "", 0);
                break;
            }
            case MIXED_COL_TABLE:
            {
                // Delete entire table
                const size_t ref = m_refs->GetAsRef(ndx);
                Array top(ref, (Array*)NULL, 0, m_array->GetAllocator());
                top.Destroy();
                break;
            }
            default:
                TIGHTDB_ASSERT(false);
        }
    }
    if (type != newtype)
        m_types->Set(ndx, newtype);
}

void ColumnMixed::Delete(size_t ndx)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());

    // Remove refs or binary data
    clear_value(ndx, MIXED_COL_INT);

    m_types->Delete(ndx);
    m_refs->Delete(ndx);

    invalidate_subtables();
}

void ColumnMixed::Clear()
{
    m_types->Clear();
    m_refs->Clear();
    if (m_data)
        m_data->Clear();
}

DataType ColumnMixed::get_type(size_t ndx) const TIGHTDB_NOEXCEPT
{
    TIGHTDB_ASSERT(ndx < m_types->Size());
    MixedColType coltype = static_cast<MixedColType>(m_types->Get(ndx));
    switch (coltype) {
        case MIXED_COL_INT_NEG:     return type_Int;
        case MIXED_COL_DOUBLE_NEG:  return type_Double;
        default: return static_cast<DataType>(coltype);   // all others must be in sync with ColumnType
    }
}

void ColumnMixed::fill(size_t count)
{
    TIGHTDB_ASSERT(is_empty());

    // Fill column with default values
    // TODO: this is a very naive approach
    // we could speedup by creating full nodes directly
    for (size_t i = 0; i < count; ++i) {
        m_types->Insert(i, MIXED_COL_INT);
    }
    for (size_t i = 0; i < count; ++i) {
        m_refs->Insert(i, 1); // 1 is zero shifted one and low bit set;
    }

#ifdef TIGHTDB_DEBUG
    Verify();
#endif
}

void ColumnMixed::set_string(size_t ndx, const char* value)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());
    InitDataColumn();

    const MixedColType type = (MixedColType)m_types->Get(ndx);
    const size_t len = strlen(value)+1;

    // See if we can reuse data position
    if (type == MIXED_COL_STRING) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
    }
    else if (type == MIXED_COL_BINARY) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
        m_types->Set(ndx, MIXED_COL_STRING);
    }
    else {
        // Remove refs or binary data
        clear_value(ndx, MIXED_COL_STRING);

        // Add value to data column
        const size_t ref = m_data->Size();
        m_data->add(value, len);

        // Shift value one bit and set lowest bit to indicate that this is not a ref
        const int64_t v = (ref << 1) + 1;

        m_types->Set(ndx, MIXED_COL_STRING);
        m_refs->Set(ndx, v);
    }
}

void ColumnMixed::set_binary(size_t ndx, const char* value, size_t len)
{
    TIGHTDB_ASSERT(ndx < m_types->Size());
    InitDataColumn();

    const MixedColType type = (MixedColType)m_types->Get(ndx);

    // See if we can reuse data position
    if (type == MIXED_COL_STRING) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
        m_types->Set(ndx, MIXED_COL_BINARY);
    }
    else if (type == MIXED_COL_BINARY) {
        const size_t ref = m_refs->GetAsRef(ndx) >> 1;
        m_data->Set(ref, value, len);
    }
    else {
        // Remove refs or binary data
        clear_value(ndx, MIXED_COL_BINARY);

        // Add value to data column
        const size_t ref = m_data->Size();
        m_data->add(value, len);

        // Shift value one bit and set lowest bit to indicate that this is not a ref
        const int64_t v = (ref << 1) + 1;

        m_types->Set(ndx, MIXED_COL_BINARY);
        m_refs->Set(ndx, v);
    }
}

bool ColumnMixed::Compare(const ColumnMixed& c) const
{
    const size_t n = Size();
    if (c.Size() != n)
        return false;

    for (size_t i=0; i<n; ++i) {
        const DataType type = get_type(i);
        if (c.get_type(i) != type)
            return false;
        switch (type) {
        case type_Int:
            if (get_int(i) != c.get_int(i)) return false;
            break;
        case type_Bool:
            if (get_bool(i) != c.get_bool(i)) return false;
            break;
        case type_Date:
            if (get_date(i) != c.get_date(i)) return false;
            break;
        case type_Float:
            if (get_float(i) != c.get_float(i)) return false;
            break;
        case type_Double:
            if (get_double(i) != c.get_double(i)) return false;
            break;
        case type_String:
            if (strcmp(get_string(i), c.get_string(i)) != 0) return false;
            break;
        case type_Binary:
            {
                const BinaryData d1 = get_binary(i);
                const BinaryData d2 = c.get_binary(i);
                if (d1.len != d2.len || !std::equal(d1.pointer, d1.pointer+d1.len, d2.pointer))
                    return false;
            }
            break;
        case type_Table:
            {
                ConstTableRef t1 = get_subtable_ptr(i)->get_table_ref();
                ConstTableRef t2 = c.get_subtable_ptr(i)->get_table_ref();
                if (*t1 != *t2)
                    return false;
            }
            break;
        case type_Mixed:
            TIGHTDB_ASSERT(false);
            break;
        }
    }
    return true;
}

#ifdef TIGHTDB_DEBUG

void ColumnMixed::Verify() const
{
    m_array->Verify();
    m_types->Verify();
    m_refs->Verify();
    if (m_data) m_data->Verify();

    // types and refs should be in sync
    const size_t types_len = m_types->Size();
    const size_t refs_len  = m_refs->Size();
    TIGHTDB_ASSERT(types_len == refs_len);

    // Verify each sub-table
    const size_t count = Size();
    for (size_t i = 0; i < count; ++i) {
        const size_t tref = m_refs->GetAsRef(i);
        if (tref == 0 || tref & 0x1) continue;
        ConstTableRef subtable = m_refs->get_subtable(i);
        subtable->Verify();
    }
}

void ColumnMixed::ToDot(std::ostream& out, const char* title) const
{
    const size_t ref = GetRef();

    out << "subgraph cluster_columnmixed" << ref << " {" << std::endl;
    out << " label = \"ColumnMixed";
    if (title) out << "\\n'" << title << "'";
    out << "\";" << std::endl;

    m_array->ToDot(out, "mixed_top");

    // Write sub-tables
    const size_t count = Size();
    for (size_t i = 0; i < count; ++i) {
        const MixedColType type = (MixedColType)m_types->Get(i);
        if (type != MIXED_COL_TABLE) continue;
        ConstTableRef subtable = m_refs->get_subtable(i);
        subtable->to_dot(out);
    }

    m_types->ToDot(out, "types");
    m_refs->ToDot(out, "refs");

    if (m_array->Size() > 2) {
        m_data->ToDot(out, "data");
    }

    out << "}" << std::endl;
}

#endif // TIGHTDB_DEBUG

} // namespace tightdb
<|endoftext|>