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

#include "chrome/browser/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"

namespace prerender {

namespace {

int omnibox_exact_group_id = 0;
int omnibox_exact_full_group_id = 0;

const char* kOmniboxHeuristicNames[] = {
  "Exact",
  "Exact_Full"
};
COMPILE_ASSERT(arraysize(kOmniboxHeuristicNames) == OMNIBOX_HEURISTIC_MAX,
               OmniboxHeuristic_name_count_mismatch);

const char kPrerenderFromOmniboxTrialName[] = "PrerenderFromOmnibox";
const char kPrerenderFromOmniboxHeuristicTrialName[] =
    "PrerenderFromOmniboxHeuristic";

const char* NameFromOmniboxHeuristic(OmniboxHeuristic heuristic) {
  DCHECK_LT(static_cast<unsigned int>(heuristic),
            arraysize(kOmniboxHeuristicNames));
  return kOmniboxHeuristicNames[heuristic];
}

}  // end namespace

void ConfigurePrerenderFromOmnibox();

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerenderMode)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerenderMode);

    if (switch_value == switches::kPrerenderModeSwitchValueAuto) {
      prerender_option = PRERENDER_OPTION_AUTO;
    } else if (switch_value == switches::kPrerenderModeSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderModeSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value ==
               switches::kPrerenderModeSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      base::FieldTrial::Probability divisor = 1000;
      base::FieldTrial::Probability exp1_probability = 200;
      base::FieldTrial::Probability control1_probability = 200;
      base::FieldTrial::Probability no_use1_probability = 100;
      base::FieldTrial::Probability exp2_probability = 200;
      base::FieldTrial::Probability control2_probability = 200;
      base::FieldTrial::Probability no_use2_probability = 100;
      chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
      if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
          channel == chrome::VersionInfo::CHANNEL_BETA) {
        exp1_probability = 495;
        control1_probability = 5;
        no_use1_probability = 0;
        exp2_probability = 495;
        control2_probability = 5;
        no_use2_probability = 0;
      }
      CHECK_EQ(divisor, exp1_probability + control1_probability +
               no_use1_probability + exp2_probability +
               control2_probability + no_use2_probability);
      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", divisor,
                               "ContentPrefetchPrerender1", 2012, 6, 30));

      const int kPrerenderExperiment1Group = trial->kDefaultGroupNumber;
      const int kPrerenderControl1Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl1",
                             control1_probability);
      const int kPrerenderNoUse1Group =
          trial->AppendGroup("ContentPrefetchPrerenderNoUse1",
                             no_use1_probability);
      const int kPrerenderExperiment2Group =
          trial->AppendGroup("ContentPrefetchPrerender2",
                             exp2_probability);
      const int kPrerenderControl2Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl2",
                             control2_probability);
      const int kPrerenderNoUse2Group =
          trial->AppendGroup("ContentPrefetchPrerenderNoUse2",
                             no_use2_probability);
      const int trial_group = trial->group();
      if (trial_group == kPrerenderExperiment1Group ||
                 trial_group == kPrerenderExperiment2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else if (trial_group == kPrerenderControl1Group ||
                 trial_group == kPrerenderControl2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else if (trial_group == kPrerenderNoUse1Group ||
                 trial_group == kPrerenderNoUse2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);

  ConfigurePrerenderFromOmnibox();
}

void ConfigurePrerenderFromOmnibox() {
  // Field trial to see if we're enabled.
  const base::FieldTrial::Probability kDivisor = 100;

  const base::FieldTrial::Probability kEnabledProbability = 40;
  scoped_refptr<base::FieldTrial> enabled_trial(
      new base::FieldTrial(kPrerenderFromOmniboxTrialName, kDivisor,
                           "OmniboxPrerenderDisabled", 2012, 8, 30));
  enabled_trial->AppendGroup("OmniboxPrerenderEnabled", kEnabledProbability);

  // Field trial to see which heuristic to use.
  const base::FieldTrial::Probability kExactFullProbability = 50;
  scoped_refptr<base::FieldTrial> heuristic_trial(
      new base::FieldTrial(kPrerenderFromOmniboxHeuristicTrialName, kDivisor,
                           "OriginalAlgorithm", 2012, 8, 30));
  omnibox_exact_group_id = base::FieldTrial::kDefaultGroupNumber;
  omnibox_exact_full_group_id =
      heuristic_trial->AppendGroup("ExactFullAlgorithm", kExactFullProbability);
}

bool IsOmniboxEnabled(Profile* profile) {
  if (!profile || profile->IsOffTheRecord())
    return false;

  if (!PrerenderManager::IsPrerenderingPossible())
    return false;

  // Override any field trial groups if the user has set a command line flag.
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kPrerenderFromOmnibox)) {
    const std::string switch_value =
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
            switches::kPrerenderFromOmnibox);

    if (switch_value == switches::kPrerenderFromOmniboxSwitchValueEnabled)
      return true;

    if (switch_value == switches::kPrerenderFromOmniboxSwitchValueDisabled)
      return false;

    DCHECK(switch_value == switches::kPrerenderFromOmniboxSwitchValueAuto);
  }

  if (!MetricsServiceHelper::IsMetricsReportingEnabled())
    return false;

  const int group =
      base::FieldTrialList::FindValue(kPrerenderFromOmniboxTrialName);
  return group != base::FieldTrial::kNotFinalized &&
         group != base::FieldTrial::kDefaultGroupNumber;
}

OmniboxHeuristic GetOmniboxHeuristicToUse() {
  const int group =
      base::FieldTrialList::FindValue(kPrerenderFromOmniboxHeuristicTrialName);
  if (group == omnibox_exact_group_id)
    return OMNIBOX_HEURISTIC_EXACT;
  if (group == omnibox_exact_full_group_id)
    return OMNIBOX_HEURISTIC_EXACT_FULL;

  // If we don't have a group just return the exact heuristic.
  return OMNIBOX_HEURISTIC_EXACT;
}

std::string GetOmniboxHistogramSuffix() {
  return NameFromOmniboxHeuristic(prerender::GetOmniboxHeuristicToUse());
}

}  // namespace prerender
<commit_msg>Increase omnibox prerender field trial opt-in from 40% to 90%.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"

namespace prerender {

namespace {

int omnibox_exact_group_id = 0;
int omnibox_exact_full_group_id = 0;

const char* kOmniboxHeuristicNames[] = {
  "Exact",
  "Exact_Full"
};
COMPILE_ASSERT(arraysize(kOmniboxHeuristicNames) == OMNIBOX_HEURISTIC_MAX,
               OmniboxHeuristic_name_count_mismatch);

const char kPrerenderFromOmniboxTrialName[] = "PrerenderFromOmnibox";
const char kPrerenderFromOmniboxHeuristicTrialName[] =
    "PrerenderFromOmniboxHeuristic";

const char* NameFromOmniboxHeuristic(OmniboxHeuristic heuristic) {
  DCHECK_LT(static_cast<unsigned int>(heuristic),
            arraysize(kOmniboxHeuristicNames));
  return kOmniboxHeuristicNames[heuristic];
}

}  // end namespace

void ConfigurePrerenderFromOmnibox();

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerenderMode)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerenderMode);

    if (switch_value == switches::kPrerenderModeSwitchValueAuto) {
      prerender_option = PRERENDER_OPTION_AUTO;
    } else if (switch_value == switches::kPrerenderModeSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderModeSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value ==
               switches::kPrerenderModeSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      base::FieldTrial::Probability divisor = 1000;
      base::FieldTrial::Probability exp1_probability = 200;
      base::FieldTrial::Probability control1_probability = 200;
      base::FieldTrial::Probability no_use1_probability = 100;
      base::FieldTrial::Probability exp2_probability = 200;
      base::FieldTrial::Probability control2_probability = 200;
      base::FieldTrial::Probability no_use2_probability = 100;
      chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
      if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
          channel == chrome::VersionInfo::CHANNEL_BETA) {
        exp1_probability = 495;
        control1_probability = 5;
        no_use1_probability = 0;
        exp2_probability = 495;
        control2_probability = 5;
        no_use2_probability = 0;
      }
      CHECK_EQ(divisor, exp1_probability + control1_probability +
               no_use1_probability + exp2_probability +
               control2_probability + no_use2_probability);
      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", divisor,
                               "ContentPrefetchPrerender1", 2012, 6, 30));

      const int kPrerenderExperiment1Group = trial->kDefaultGroupNumber;
      const int kPrerenderControl1Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl1",
                             control1_probability);
      const int kPrerenderNoUse1Group =
          trial->AppendGroup("ContentPrefetchPrerenderNoUse1",
                             no_use1_probability);
      const int kPrerenderExperiment2Group =
          trial->AppendGroup("ContentPrefetchPrerender2",
                             exp2_probability);
      const int kPrerenderControl2Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl2",
                             control2_probability);
      const int kPrerenderNoUse2Group =
          trial->AppendGroup("ContentPrefetchPrerenderNoUse2",
                             no_use2_probability);
      const int trial_group = trial->group();
      if (trial_group == kPrerenderExperiment1Group ||
                 trial_group == kPrerenderExperiment2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else if (trial_group == kPrerenderControl1Group ||
                 trial_group == kPrerenderControl2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else if (trial_group == kPrerenderNoUse1Group ||
                 trial_group == kPrerenderNoUse2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);

  ConfigurePrerenderFromOmnibox();
}

void ConfigurePrerenderFromOmnibox() {
  // Field trial to see if we're enabled.
  const base::FieldTrial::Probability kDivisor = 100;

  const base::FieldTrial::Probability kEnabledProbability = 90;
  scoped_refptr<base::FieldTrial> enabled_trial(
      new base::FieldTrial(kPrerenderFromOmniboxTrialName, kDivisor,
                           "OmniboxPrerenderDisabled", 2012, 8, 30));
  enabled_trial->AppendGroup("OmniboxPrerenderEnabled", kEnabledProbability);

  // Field trial to see which heuristic to use.
  const base::FieldTrial::Probability kExactFullProbability = 50;
  scoped_refptr<base::FieldTrial> heuristic_trial(
      new base::FieldTrial(kPrerenderFromOmniboxHeuristicTrialName, kDivisor,
                           "OriginalAlgorithm", 2012, 8, 30));
  omnibox_exact_group_id = base::FieldTrial::kDefaultGroupNumber;
  omnibox_exact_full_group_id =
      heuristic_trial->AppendGroup("ExactFullAlgorithm", kExactFullProbability);
}

bool IsOmniboxEnabled(Profile* profile) {
  if (!profile || profile->IsOffTheRecord())
    return false;

  if (!PrerenderManager::IsPrerenderingPossible())
    return false;

  // Override any field trial groups if the user has set a command line flag.
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kPrerenderFromOmnibox)) {
    const std::string switch_value =
        CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
            switches::kPrerenderFromOmnibox);

    if (switch_value == switches::kPrerenderFromOmniboxSwitchValueEnabled)
      return true;

    if (switch_value == switches::kPrerenderFromOmniboxSwitchValueDisabled)
      return false;

    DCHECK(switch_value == switches::kPrerenderFromOmniboxSwitchValueAuto);
  }

  if (!MetricsServiceHelper::IsMetricsReportingEnabled())
    return false;

  const int group =
      base::FieldTrialList::FindValue(kPrerenderFromOmniboxTrialName);
  return group != base::FieldTrial::kNotFinalized &&
         group != base::FieldTrial::kDefaultGroupNumber;
}

OmniboxHeuristic GetOmniboxHeuristicToUse() {
  const int group =
      base::FieldTrialList::FindValue(kPrerenderFromOmniboxHeuristicTrialName);
  if (group == omnibox_exact_group_id)
    return OMNIBOX_HEURISTIC_EXACT;
  if (group == omnibox_exact_full_group_id)
    return OMNIBOX_HEURISTIC_EXACT_FULL;

  // If we don't have a group just return the exact heuristic.
  return OMNIBOX_HEURISTIC_EXACT;
}

std::string GetOmniboxHistogramSuffix() {
  return NameFromOmniboxHeuristic(prerender::GetOmniboxHeuristicToUse());
}

}  // namespace prerender
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2014 The Communi Project
 *
 * This example is free, and not covered by the LGPL license. There is no
 * restriction applied to their modification, redistribution, using and so on.
 * You can study them, modify them, use them in your own program - either
 * completely or partially.
 */

#include "settingspage.h"
#include "textdocument.h"
#include "textbrowser.h"
#include "themeloader.h"
#include "treewidget.h"
#include "bufferview.h"
#include "themeinfo.h"
#include "splitview.h"
#include "chatpage.h"
#include <IrcBufferModel>
#include <IrcConnection>
#include <QPushButton>
#include <IrcChannel>
#include <IrcMessage>
#include <QShortcut>
#include <IrcBuffer>
#include <QPainter>
#include <QPixmap>
#include <QBuffer>

class Channel : public IrcChannel
{
public:
    Channel(QObject* parent = 0) : IrcChannel(parent) { }
    bool isActive() const { return true; }
};

class Server : public IrcBuffer
{
public:
    Server(QObject* parent = 0) : IrcBuffer(parent) { }
    bool isActive() const { return true; }
};

static void receiveMessages(TextDocument* doc)
{
    QString title = doc->buffer()->title();
    IrcConnection* connection = doc->buffer()->connection();
    doc->receiveMessage(IrcMessage::fromParameters("Lorem", "JOIN", QStringList() << title, connection));
    doc->receiveMessage(IrcMessage::fromParameters("Morbi", "PRIVMSG", QStringList() << title << "nullam eget commodo diam. sit amet ornare leo.", connection));
    doc->receiveMessage(IrcMessage::fromParameters("nulla", "PRIVMSG", QStringList() << title << "...", connection));
    doc->receiveMessage(IrcMessage::fromParameters("Ipsum", "JOIN", QStringList() << title, connection));
    doc->receiveMessage(IrcMessage::fromParameters("rhoncus", "PRIVMSG", QStringList() << title << "vivamus!", connection));
    doc->receiveMessage(IrcMessage::fromParameters("Etiam", "PRIVMSG", QStringList() << title << "Ut volutpat nibh nec enim elementum, sed placerat erat gravida.", connection));
    doc->receiveMessage(IrcMessage::fromParameters("Ipsum", "QUIT", QStringList() << "Nulla facilisi.", connection));
    doc->receiveMessage(IrcMessage::fromParameters("Ipsum", "JOIN", QStringList() << title, connection));
    doc->receiveMessage(IrcMessage::fromParameters("nunc", "PRIVMSG", QStringList() << title << ":)", connection));
    doc->receiveMessage(IrcMessage::fromParameters("gravida", "PRIVMSG", QStringList() << title << "etiam augue purus, pharetra vel neque a, fringilla hendrerit orci", connection));
    doc->receiveMessage(IrcMessage::fromParameters("Proin", "PRIVMSG", QStringList() << title << "enim ante?", connection));
    doc->receiveMessage(IrcMessage::fromParameters("Cras", "PRIVMSG", QStringList() << title << "quisque vel lacus eu odio pretium adipiscing...", connection));
}

static IrcBuffer* createChannel(const QString& name, QObject* parent)
{
    IrcChannel* channel = new Channel(parent);
    channel->setPrefix("#");
    channel->setName(name);
    return channel;
}

static IrcBufferModel* createBufferModel(QObject* parent)
{
    IrcConnection* connection = new IrcConnection(parent);
    connection->setNickName("communi");
    IrcBufferModel* model = new IrcBufferModel(connection);
    IrcBuffer* server = new Server(model);
    server->setName("Lorem Ipsum");
    server->setSticky(true);
    model->add(server);
    model->add(createChannel("donec", model));
    model->add(createChannel("convallis", model));
    model->add(createChannel("sagittis", model));
    model->add(createChannel("magna", model));
    model->add(createChannel("tincidunt", model));
    model->add(createChannel("phasellus ", model));
    model->add(createChannel("tellus", model));
    model->add(createChannel("fermentum", model));
    model->add(createChannel("pharetra", model));
    model->add(createChannel("vehicula", model));
    model->add(createChannel("aliquam", model));
    model->add(createChannel("bibendum", model));
    model->add(createChannel("semper", model));
    model->add(createChannel("dictum", model));
    model->add(createChannel("rhoncus", model));
    return model;
}

static ChatPage* createChatPage(QWidget* parent = 0)
{
    ChatPage* page = new ChatPage(parent);
    IrcBufferModel* model = createBufferModel(page);
    foreach (IrcBuffer* buffer, model->buffers())
        page->treeWidget()->addBuffer(buffer);
    IrcBuffer* buffer = model->find("#magna");
    page->addBuffer(buffer);
    page->splitView()->setCurrentBuffer(buffer);
    page->treeWidget()->setCurrentBuffer(buffer);
    page->treeWidget()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    page->currentView()->textBrowser()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    receiveMessages(page->currentView()->textDocument());
    return page;
}

SettingsPage::SettingsPage(QWidget* parent) : QWidget(parent)
{
    ui.setupUi(this);

    connect(ui.buttonBox, SIGNAL(accepted()), this, SIGNAL(accepted()));
    connect(ui.buttonBox, SIGNAL(rejected()), this, SIGNAL(rejected()));

    QShortcut* shortcut = new QShortcut(Qt::Key_Return, this);
    connect(shortcut, SIGNAL(activated()), ui.buttonBox->button(QDialogButtonBox::Ok), SLOT(click()));

    shortcut = new QShortcut(Qt::Key_Escape, this);
    connect(shortcut, SIGNAL(activated()), ui.buttonBox->button(QDialogButtonBox::Cancel), SLOT(click()));

    ChatPage* page = createChatPage();
    page->resize(640, 400);

    foreach (const QString& name, ThemeLoader::instance()->themes()) {
        ThemeInfo theme = ThemeLoader::instance()->theme(name);

        QPixmap pixmap(640, 400);
        QPainter painter(&pixmap);

        page->setTheme(theme.name());
        page->render(&painter);

        QByteArray ba;
        QBuffer buffer(&ba);
        buffer.open(QIODevice::WriteOnly);
        pixmap.scaled(320, 200).save(&buffer, "PNG");

        QLabel* label = new QLabel(ui.content);
        label->setTextFormat(Qt::RichText);
        label->setText(tr("

"
                          ""
                          ""
                          "	"
                          ""
                          "
%1
"
                          "
Version: %2
"
                          "
Author: %3
"
                          "
%4
"
                          "	"
                          "

").arg(theme.name(), theme.version(), theme.author(), theme.description(), ba.toBase64()));
        ui.content->layout()->addWidget(label);
    }

    delete page;
}

SettingsPage::~SettingsPage()
{
}

QString SettingsPage::theme() const
{
    //return ui.comboBox->currentText();
    return "Cute";
}
/*
void SettingsPage::setThemes(const QStringList& themes)
{
    //ui.comboBox->clear();
    //ui.comboBox->addItems(themes);
}
*/

<commit_msg>Improve theme preview<commit_after>/*
 * Copyright (C) 2008-2014 The Communi Project
 *
 * This example is free, and not covered by the LGPL license. There is no
 * restriction applied to their modification, redistribution, using and so on.
 * You can study them, modify them, use them in your own program - either
 * completely or partially.
 */

#include "settingspage.h"
#include "textdocument.h"
#include "textbrowser.h"
#include "themeloader.h"
#include "treewidget.h"
#include "bufferview.h"
#include "themeinfo.h"
#include "splitview.h"
#include "chatpage.h"
#include <IrcBufferModel>
#include <IrcConnection>
#include <QPushButton>
#include <IrcChannel>
#include <IrcMessage>
#include <QShortcut>
#include <IrcBuffer>
#include <QPainter>
#include <QPixmap>
#include <QBuffer>

class Channel : public IrcChannel
{
public:
    Channel(QObject* parent = 0) : IrcChannel(parent) { }
    bool isActive() const { return true; }
};

class Server : public IrcBuffer
{
public:
    Server(QObject* parent = 0) : IrcBuffer(parent) { }
    bool isActive() const { return true; }
};

static void receiveMessages(IrcBufferModel* model, IrcBuffer* buffer)
{
    QString title = buffer->title();
    IrcConnection* connection = buffer->connection();
    model->receiveMessage(IrcMessage::fromParameters("Lorem", "JOIN", QStringList() << title, connection));
    IrcNamesMessage* names = new IrcNamesMessage(connection);
    names->setParameters(QStringList() << title << "Lorem" << "Morbi" << "nulla" << "rhoncus" << "Etiam" << "nunc" << "gravida" << "Proin" << "Cras");
    model->receiveMessage(names);
    model->receiveMessage(IrcMessage::fromParameters("Morbi", "PRIVMSG", QStringList() << title << "nullam eget commodo diam. sit amet ornare leo.", connection));
    model->receiveMessage(IrcMessage::fromParameters("nulla", "PRIVMSG", QStringList() << title << "...", connection));
    model->receiveMessage(IrcMessage::fromParameters("Ipsum", "JOIN", QStringList() << title, connection));
    model->receiveMessage(IrcMessage::fromParameters("rhoncus", "PRIVMSG", QStringList() << title << "vivamus!", connection));
    model->receiveMessage(IrcMessage::fromParameters("Etiam", "PRIVMSG", QStringList() << title << "Ut volutpat nibh nec enim elementum, sed placerat erat gravida.", connection));
    model->receiveMessage(IrcMessage::fromParameters("Ipsum", "QUIT", QStringList() << "Nulla facilisi.", connection));
    model->receiveMessage(IrcMessage::fromParameters("Ipsum", "JOIN", QStringList() << title, connection));
    model->receiveMessage(IrcMessage::fromParameters("nunc", "PRIVMSG", QStringList() << title << ":)", connection));
    model->receiveMessage(IrcMessage::fromParameters("gravida", "PRIVMSG", QStringList() << title << "etiam augue purus, pharetra vel neque a, fringilla hendrerit orci", connection));
    model->receiveMessage(IrcMessage::fromParameters("Proin", "PRIVMSG", QStringList() << title << "enim ante?", connection));
    model->receiveMessage(IrcMessage::fromParameters("Cras", "PRIVMSG", QStringList() << title << "quisque vel lacus eu odio pretium adipiscing...", connection));
}

static IrcBuffer* createChannel(const QString& name, QObject* parent)
{
    IrcChannel* channel = new Channel(parent);
    channel->setPrefix("#");
    channel->setName(name);
    return channel;
}

static IrcBufferModel* createBufferModel(QObject* parent)
{
    IrcConnection* connection = new IrcConnection(parent);
    connection->setNickName("communi");
    IrcBufferModel* model = new IrcBufferModel(connection);
    IrcBuffer* server = new Server(model);
    server->setName("Lorem Ipsum");
    server->setSticky(true);
    model->add(server);
    model->add(createChannel("donec", model));
    model->add(createChannel("convallis", model));
    model->add(createChannel("sagittis", model));
    model->add(createChannel("magna", model));
    model->add(createChannel("tincidunt", model));
    model->add(createChannel("phasellus ", model));
    model->add(createChannel("tellus", model));
    model->add(createChannel("fermentum", model));
    model->add(createChannel("pharetra", model));
    model->add(createChannel("vehicula", model));
    model->add(createChannel("aliquam", model));
    model->add(createChannel("bibendum", model));
    model->add(createChannel("semper", model));
    model->add(createChannel("dictum", model));
    model->add(createChannel("rhoncus", model));
    return model;
}

static ChatPage* createChatPage(QWidget* parent = 0)
{
    ChatPage* page = new ChatPage(parent);
    IrcBufferModel* model = createBufferModel(page);
    foreach (IrcBuffer* buffer, model->buffers())
        page->treeWidget()->addBuffer(buffer);
    IrcBuffer* buffer = model->find("#magna");
    page->addBuffer(buffer);
    page->splitView()->setCurrentBuffer(buffer);
    page->treeWidget()->setCurrentBuffer(buffer);
    page->treeWidget()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    page->currentView()->textBrowser()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    receiveMessages(model, buffer);
    return page;
}

SettingsPage::SettingsPage(QWidget* parent) : QWidget(parent)
{
    ui.setupUi(this);

    connect(ui.buttonBox, SIGNAL(accepted()), this, SIGNAL(accepted()));
    connect(ui.buttonBox, SIGNAL(rejected()), this, SIGNAL(rejected()));

    QShortcut* shortcut = new QShortcut(Qt::Key_Return, this);
    connect(shortcut, SIGNAL(activated()), ui.buttonBox->button(QDialogButtonBox::Ok), SLOT(click()));

    shortcut = new QShortcut(Qt::Key_Escape, this);
    connect(shortcut, SIGNAL(activated()), ui.buttonBox->button(QDialogButtonBox::Cancel), SLOT(click()));

    ChatPage* page = createChatPage();
    page->resize(640, 400);

    foreach (const QString& name, ThemeLoader::instance()->themes()) {
        ThemeInfo theme = ThemeLoader::instance()->theme(name);

        QPixmap pixmap(640, 400);
        QPainter painter(&pixmap);

        page->setTheme(theme.name());
        page->render(&painter);

        QByteArray ba;
        QBuffer buffer(&ba);
        buffer.open(QIODevice::WriteOnly);
        pixmap.scaled(320, 200).save(&buffer, "PNG");

        QLabel* label = new QLabel(ui.content);
        label->setTextFormat(Qt::RichText);
        label->setText(tr("

"
                          ""
                          ""
                          "	"
                          ""
                          "
%1
"
                          "
Version: %2
"
                          "
Author: %3
"
                          "
%4
"
                          "	"
                          "

").arg(theme.name(), theme.version(), theme.author(), theme.description(), ba.toBase64()));
        ui.content->layout()->addWidget(label);
    }

    delete page;
}

SettingsPage::~SettingsPage()
{
}

QString SettingsPage::theme() const
{
    //return ui.comboBox->currentText();
    return "Cute";
}
/*
void SettingsPage::setThemes(const QStringList& themes)
{
    //ui.comboBox->clear();
    //ui.comboBox->addItems(themes);
}
*/

<|endoftext|>


<commit_before>//
// complex2record
//
// This pass changes the primitive complex type to a record.  As an
// optimization, unimplemented, it can be turned off to take advantage
// of C99 support of complex types.
//

#include "astutil.h"
#include "build.h"
#include "expr.h"
#include "passes.h"
#include "stmt.h"
#include "stringutil.h"
#include "symbol.h"
#include "symscope.h"

static ClassType*
buildComplexRecord(const char* name, Type* real) {
  ClassType* ct = new ClassType(CLASS_RECORD);
  TypeSymbol* ts = new TypeSymbol(name, ct);
  ct->fields.insertAtTail(new DefExpr(new VarSymbol("re", real)));
  ct->fields.insertAtTail(new DefExpr(new VarSymbol("im", real)));
  rootModule->block->insertAtTail(new DefExpr(ts));
  return ct;
}

#define complex2rec(t)                                          \
  ((t == dtComplex[COMPLEX_SIZE_64]) ? complex64 :              \
   ((t == dtComplex[COMPLEX_SIZE_128]) ? complex128 : 0))

#define complex2real(t)                                                 \
  ((t == dtComplex[COMPLEX_SIZE_64]) ? dtReal[FLOAT_SIZE_32] :         \
   ((t == dtComplex[COMPLEX_SIZE_128]) ? dtReal[FLOAT_SIZE_64] : 0))

void
complex2record() {
  ClassType* complex64 = buildComplexRecord("_complex64", dtReal[FLOAT_SIZE_32]);
  ClassType* complex128 = buildComplexRecord("_complex128", dtReal[FLOAT_SIZE_64]);

  complex64->refType = dtComplex[COMPLEX_SIZE_64]->refType;
  complex128->refType = dtComplex[COMPLEX_SIZE_128]->refType;

  dtComplex[COMPLEX_SIZE_64]->refType = NULL;
  dtComplex[COMPLEX_SIZE_128]->refType = NULL;

  dtComplex[COMPLEX_SIZE_64]->symbol->defPoint->remove();
  dtComplex[COMPLEX_SIZE_128]->symbol->defPoint->remove();

  forv_Vec(BaseAST, ast, gAsts) {
    if (DefExpr* def = toDefExpr(ast)) {
      if (def->parentExpr != rootModule->block)
        if (!isTypeSymbol(def->sym))
          if (is_complex_type(def->sym->type))
            def->sym->type = complex2rec(def->sym->type);
      if (FnSymbol* fn = toFnSymbol(def->sym))
        if (is_complex_type(fn->retType))
          fn->retType = complex2rec(fn->retType);
    } else if (SymExpr* se = toSymExpr(ast)) {
      if (VarSymbol* var = toVarSymbol(se->var)) {
        if (is_complex_type(var->type)) {
          if (var->immediate) {
            ClassType* ct = complex2rec(se->var->type);
            VarSymbol* tmp = new VarSymbol("_tmp", ct);
            se->getStmtExpr()->insertBefore(new DefExpr(tmp));
            se->getStmtExpr()->insertBefore(new CallExpr(PRIMITIVE_SET_MEMBER, tmp, ct->getField(1), complex2real(se->var->type)->defaultValue));
            se->getStmtExpr()->insertBefore(new CallExpr(PRIMITIVE_SET_MEMBER, tmp, ct->getField(2), complex2real(se->var->type)->defaultValue));
            se->replace(new SymExpr(tmp));
          }
        }
      } else if (TypeSymbol* ts = toTypeSymbol(se->var)) {
        if (is_complex_type(ts->type)) {
          se->var = complex2rec(ts->type)->symbol;
        }
      }
    }
  }

  forv_Vec(BaseAST, ast, gAsts) {
    if (CallExpr* call = toCallExpr(ast)) {
      if (call->isPrimitive(PRIMITIVE_GET_REAL)) {
        call->primitive = primitives[PRIMITIVE_GET_MEMBER];
        ClassType* ct = toClassType(call->get(1)->typeInfo());
        if (isReference(ct))
          ct = toClassType(getValueType(ct));
        call->insertAtTail(ct->getField(1));
      } else if (call->isPrimitive(PRIMITIVE_GET_IMAG)) {
        call->primitive = primitives[PRIMITIVE_GET_MEMBER];
        ClassType* ct = toClassType(call->get(1)->typeInfo());
        if (isReference(ct))
          ct = toClassType(getValueType(ct));
        call->insertAtTail(ct->getField(2));
      }
    }
  }

  //
  // change arrays of complexes into arrays of new complex records
  //
  forv_Vec(TypeSymbol, ts, gTypes) {
    if (ts->hasPragma("data class")) {
      if (Type* nt = toType(ts->type->substitutions.v[0].value)) {
        if (is_complex_type(nt)) {
          ts->type->substitutions.v[0].value = complex2rec(nt);
        }
      }
    }
  }

}
<commit_msg>fixed valgrind regression due to complex type bug<commit_after>//
// complex2record
//
// This pass changes the primitive complex type to a record.  As an
// optimization, unimplemented, it can be turned off to take advantage
// of C99 support of complex types.
//

#include "astutil.h"
#include "build.h"
#include "expr.h"
#include "passes.h"
#include "stmt.h"
#include "stringutil.h"
#include "symbol.h"
#include "symscope.h"

static ClassType*
buildComplexRecord(const char* name, Type* real) {
  ClassType* ct = new ClassType(CLASS_RECORD);
  TypeSymbol* ts = new TypeSymbol(name, ct);
  ct->fields.insertAtTail(new DefExpr(new VarSymbol("re", real)));
  ct->fields.insertAtTail(new DefExpr(new VarSymbol("im", real)));
  rootModule->block->insertAtTail(new DefExpr(ts));
  return ct;
}

#define complex2rec(t)                                          \
  ((t == dtComplex[COMPLEX_SIZE_64]) ? complex64 :              \
   ((t == dtComplex[COMPLEX_SIZE_128]) ? complex128 : 0))

#define complex2real(t)                                                 \
  ((t == dtComplex[COMPLEX_SIZE_64]) ? dtReal[FLOAT_SIZE_32] :         \
   ((t == dtComplex[COMPLEX_SIZE_128]) ? dtReal[FLOAT_SIZE_64] : 0))

void
complex2record() {
  ClassType* complex64 = buildComplexRecord("_complex64", dtReal[FLOAT_SIZE_32]);
  ClassType* complex128 = buildComplexRecord("_complex128", dtReal[FLOAT_SIZE_64]);

  complex64->refType = dtComplex[COMPLEX_SIZE_64]->refType;
  complex128->refType = dtComplex[COMPLEX_SIZE_128]->refType;

  dtComplex[COMPLEX_SIZE_64]->refType = NULL;
  dtComplex[COMPLEX_SIZE_128]->refType = NULL;

  dtComplex[COMPLEX_SIZE_64]->symbol->defPoint->remove();
  dtComplex[COMPLEX_SIZE_128]->symbol->defPoint->remove();

  forv_Vec(BaseAST, ast, gAsts) {
    if (SymExpr* se = toSymExpr(ast)) {
      if (VarSymbol* var = toVarSymbol(se->var)) {
        if (is_complex_type(var->type)) {
          if (var->immediate) {
            ClassType* ct = complex2rec(se->var->type);
            VarSymbol* tmp = new VarSymbol("_tmp", ct);
            se->getStmtExpr()->insertBefore(new DefExpr(tmp));
            se->getStmtExpr()->insertBefore(new CallExpr(PRIMITIVE_SET_MEMBER, tmp, ct->getField(1), complex2real(se->var->type)->defaultValue));
            se->getStmtExpr()->insertBefore(new CallExpr(PRIMITIVE_SET_MEMBER, tmp, ct->getField(2), complex2real(se->var->type)->defaultValue));
            se->replace(new SymExpr(tmp));
          }
        }
      } else if (TypeSymbol* ts = toTypeSymbol(se->var)) {
        if (is_complex_type(ts->type)) {
          se->var = complex2rec(ts->type)->symbol;
        }
      }
    }
  }

  forv_Vec(BaseAST, ast, gAsts) {
    if (DefExpr* def = toDefExpr(ast)) {
      if (!isTypeSymbol(def->sym))
        if (is_complex_type(def->sym->type))
          def->sym->type = complex2rec(def->sym->type);
      if (FnSymbol* fn = toFnSymbol(def->sym))
        if (is_complex_type(fn->retType))
          fn->retType = complex2rec(fn->retType);
    }
  }

  forv_Vec(BaseAST, ast, gAsts) {
    if (CallExpr* call = toCallExpr(ast)) {
      if (call->isPrimitive(PRIMITIVE_GET_REAL)) {
        call->primitive = primitives[PRIMITIVE_GET_MEMBER];
        ClassType* ct = toClassType(call->get(1)->typeInfo());
        if (isReference(ct))
          ct = toClassType(getValueType(ct));
        call->insertAtTail(ct->getField(1));
      } else if (call->isPrimitive(PRIMITIVE_GET_IMAG)) {
        call->primitive = primitives[PRIMITIVE_GET_MEMBER];
        ClassType* ct = toClassType(call->get(1)->typeInfo());
        if (isReference(ct))
          ct = toClassType(getValueType(ct));
        call->insertAtTail(ct->getField(2));
      }
    }
  }

  //
  // change arrays of complexes into arrays of new complex records
  //
  forv_Vec(TypeSymbol, ts, gTypes) {
    if (ts->hasPragma("data class")) {
      if (Type* nt = toType(ts->type->substitutions.v[0].value)) {
        if (is_complex_type(nt)) {
          ts->type->substitutions.v[0].value = complex2rec(nt);
        }
      }
    }
  }

}
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "proto_converter.h"
#include <vespa/searchlib/common/mapnames.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/data/slime/binary_format.h>
#include <vespa/vespalib/data/smart_buffer.h>
#include <vespa/vespalib/util/size_literals.h>
#include <vespa/log/log.h>

LOG_SETUP(".searchlib.engine.proto_converter");

namespace search::engine {

namespace {

template <typename T>
vespalib::string make_sort_spec(const T &sorting) {
    vespalib::string spec;
    for (const auto &field_spec: sorting) {
        if (!spec.empty()) {
            spec.push_back(' ');
        }
        if (field_spec.ascending()) {
            spec.push_back('+');
        } else {
            spec.push_back('-');
        }
        spec.append(field_spec.field());
    }
    return spec;
}

template <typename T>
void add_single_props(fef::Properties &dst, const T &src) {
    for (const auto &entry: src) {
        dst.add(entry.name(), entry.value());
    }
}

template <typename T>
void add_multi_props(fef::Properties &dst, const T &src) {
    for (const auto &entry: src) {
        for (int i = 0; i < entry.values_size(); ++i) {
            dst.add(entry.name(), entry.values(i));
        }
    }
}

}

//-----------------------------------------------------------------------------

void
ProtoConverter::search_request_from_proto(const ProtoSearchRequest &proto, SearchRequest &request)
{
    request.offset = proto.offset();
    request.maxhits = proto.hits();
    request.setTimeout(1ms * proto.timeout());
    request.setTraceLevel(proto.trace_level());
    request.sortSpec = make_sort_spec(proto.sorting());
    request.sessionId.assign(proto.session_key().begin(), proto.session_key().end());
    request.propertiesMap.lookupCreate(MapNames::MATCH).add("documentdb.searchdoctype", proto.document_type());
    if (proto.cache_grouping()) {
        request.propertiesMap.lookupCreate(MapNames::CACHES).add("grouping", "true");
    }
    if (proto.cache_query()) {
        request.propertiesMap.lookupCreate(MapNames::CACHES).add("query", "true");
    }
    request.ranking = proto.rank_profile();
    if ((proto.feature_overrides_size() + proto.tensor_feature_overrides_size()) > 0) {
        auto &feature_overrides = request.propertiesMap.lookupCreate(MapNames::FEATURE);
        add_multi_props(feature_overrides, proto.feature_overrides());
        add_single_props(feature_overrides, proto.tensor_feature_overrides());
    }
    if ((proto.rank_properties_size() + proto.tensor_rank_properties_size()) > 0) {
        auto &rank_props = request.propertiesMap.lookupCreate(MapNames::RANK);
        add_multi_props(rank_props, proto.rank_properties());
        add_single_props(rank_props, proto.tensor_rank_properties());
    }
    request.groupSpec.assign(proto.grouping_blob().begin(), proto.grouping_blob().end());
    request.location = proto.geo_location();
    request.stackDump.assign(proto.query_tree_blob().begin(), proto.query_tree_blob().end());
}

void
ProtoConverter::search_reply_to_proto(const SearchReply &reply, ProtoSearchReply &proto)
{
    proto.set_total_hit_count(reply.totalHitCount);
    proto.set_coverage_docs(reply.coverage.getCovered());
    proto.set_active_docs(reply.coverage.getActive());
    proto.set_soon_active_docs(reply.coverage.getSoonActive());
    proto.set_degraded_by_match_phase(reply.coverage.wasDegradedByMatchPhase());
    proto.set_degraded_by_soft_timeout(reply.coverage.wasDegradedByTimeout());
    bool has_sort_data = (reply.sortIndex.size() > 0);
    assert(!has_sort_data || (reply.sortIndex.size() == (reply.hits.size() + 1)));
    if (reply.request) {
        uint32_t asked_offset = reply.request->offset;
        uint32_t asked_hits = reply.request->maxhits;
        size_t got_hits = reply.hits.size();
        if (got_hits < asked_hits && asked_offset + got_hits < reply.totalHitCount) {
            LOG(warning, "asked for %u hits [at offset %u] but only returning %zu hits from %" PRIu64 " available",
                asked_hits, asked_offset, got_hits, reply.totalHitCount);
        }
    }
    for (size_t i = 0; i < reply.hits.size(); ++i) {
        auto *hit = proto.add_hits();
        hit->set_global_id(reply.hits[i].gid.get(), document::GlobalId::LENGTH);
        hit->set_relevance(reply.hits[i].metric);
        if (has_sort_data) {
            size_t sort_data_offset = reply.sortIndex[i];
            size_t sort_data_size = (reply.sortIndex[i + 1] - reply.sortIndex[i]);
            assert((sort_data_offset + sort_data_size) <= reply.sortData.size());
            hit->set_sort_data(&reply.sortData[sort_data_offset], sort_data_size);
        }
    }
    proto.set_grouping_blob(&reply.groupResult[0], reply.groupResult.size());
    const auto &slime_trace = reply.propertiesMap.trace().lookup("slime");
    proto.set_slime_trace(slime_trace.get().data(), slime_trace.get().size());
    if (reply.my_issues) {
        reply.my_issues->for_each_message([&](const vespalib::string &err_msg)
                                          {
                                              auto *err_obj = proto.add_errors();
                                              err_obj->set_message(err_msg);
                                          });
    }
}

//-----------------------------------------------------------------------------

void
ProtoConverter::docsum_request_from_proto(const ProtoDocsumRequest &proto, DocsumRequest &request)
{
    request.setTimeout(1ms * proto.timeout());
    request.sessionId.assign(proto.session_key().begin(), proto.session_key().end());
    request.propertiesMap.lookupCreate(MapNames::MATCH).add("documentdb.searchdoctype", proto.document_type());
    request.resultClassName = proto.summary_class();
    if (proto.cache_query()) {
        request.propertiesMap.lookupCreate(MapNames::CACHES).add("query", "true");
    }
    request.dumpFeatures = proto.dump_features();
    request.ranking = proto.rank_profile();
    if ((proto.feature_overrides_size() + proto.tensor_feature_overrides_size()) > 0) {
        auto &feature_overrides = request.propertiesMap.lookupCreate(MapNames::FEATURE);
        add_multi_props(feature_overrides, proto.feature_overrides());
        add_single_props(feature_overrides, proto.tensor_feature_overrides());
    }
    if ((proto.rank_properties_size() + proto.tensor_rank_properties_size()) > 0) {
        auto &rank_props = request.propertiesMap.lookupCreate(MapNames::RANK);
        add_multi_props(rank_props, proto.rank_properties());
        add_single_props(rank_props, proto.tensor_rank_properties());
    }
    if(proto.highlight_terms_size() > 0) {
        auto &highlight_terms = request.propertiesMap.lookupCreate(MapNames::HIGHLIGHTTERMS);
        add_multi_props(highlight_terms, proto.highlight_terms());
    }
    request.location = proto.geo_location();
    request.stackDump.assign(proto.query_tree_blob().begin(), proto.query_tree_blob().end());
    request.hits.resize(proto.global_ids_size());
    for (int i = 0; i < proto.global_ids_size(); ++i) {
        const auto &gid = proto.global_ids(i);
        if (gid.size() == document::GlobalId::LENGTH) {
            request.hits[i].gid = document::GlobalId(gid.data());
        }
    }
}

void
ProtoConverter::docsum_reply_to_proto(const DocsumReply &reply, ProtoDocsumReply &proto)
{
    if (reply.hasResult()) {
        vespalib::SmartBuffer buf(4_Ki);
        vespalib::slime::BinaryFormat::encode(reply.slime(), buf);
        proto.set_slime_summaries(buf.obtain().data, buf.obtain().size);
    }
    if (reply.hasIssues()) {
        reply.issues().for_each_message([&](const vespalib::string &err_msg)
                                        {
                                            auto *err_obj = proto.add_errors();
                                            err_obj->set_message(err_msg);
                                        });
    }
}

//-----------------------------------------------------------------------------

void
ProtoConverter::monitor_request_from_proto(const ProtoMonitorRequest &, MonitorRequest &)
{
}

void
ProtoConverter::monitor_reply_to_proto(const MonitorReply &reply, ProtoMonitorReply &proto)
{
    proto.set_online(reply.timestamp != 0);
    proto.set_active_docs(reply.activeDocs);
    proto.set_distribution_key(reply.distribution_key);
    proto.set_is_blocking_writes(reply.is_blocking_writes);
}

//-----------------------------------------------------------------------------

}
<commit_msg>feature values in SearchReply -> protobuf<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "proto_converter.h"
#include <vespa/searchlib/common/mapnames.h>
#include <vespa/vespalib/data/slime/slime.h>
#include <vespa/vespalib/data/slime/binary_format.h>
#include <vespa/vespalib/data/smart_buffer.h>
#include <vespa/vespalib/util/size_literals.h>
#include <vespa/log/log.h>

LOG_SETUP(".searchlib.engine.proto_converter");

namespace search::engine {

namespace {

template <typename T>
vespalib::string make_sort_spec(const T &sorting) {
    vespalib::string spec;
    for (const auto &field_spec: sorting) {
        if (!spec.empty()) {
            spec.push_back(' ');
        }
        if (field_spec.ascending()) {
            spec.push_back('+');
        } else {
            spec.push_back('-');
        }
        spec.append(field_spec.field());
    }
    return spec;
}

template <typename T>
void add_single_props(fef::Properties &dst, const T &src) {
    for (const auto &entry: src) {
        dst.add(entry.name(), entry.value());
    }
}

template <typename T>
void add_multi_props(fef::Properties &dst, const T &src) {
    for (const auto &entry: src) {
        for (int i = 0; i < entry.values_size(); ++i) {
            dst.add(entry.name(), entry.values(i));
        }
    }
}

}

//-----------------------------------------------------------------------------

void
ProtoConverter::search_request_from_proto(const ProtoSearchRequest &proto, SearchRequest &request)
{
    request.offset = proto.offset();
    request.maxhits = proto.hits();
    request.setTimeout(1ms * proto.timeout());
    request.setTraceLevel(proto.trace_level());
    request.sortSpec = make_sort_spec(proto.sorting());
    request.sessionId.assign(proto.session_key().begin(), proto.session_key().end());
    request.propertiesMap.lookupCreate(MapNames::MATCH).add("documentdb.searchdoctype", proto.document_type());
    if (proto.cache_grouping()) {
        request.propertiesMap.lookupCreate(MapNames::CACHES).add("grouping", "true");
    }
    if (proto.cache_query()) {
        request.propertiesMap.lookupCreate(MapNames::CACHES).add("query", "true");
    }
    request.ranking = proto.rank_profile();
    if ((proto.feature_overrides_size() + proto.tensor_feature_overrides_size()) > 0) {
        auto &feature_overrides = request.propertiesMap.lookupCreate(MapNames::FEATURE);
        add_multi_props(feature_overrides, proto.feature_overrides());
        add_single_props(feature_overrides, proto.tensor_feature_overrides());
    }
    if ((proto.rank_properties_size() + proto.tensor_rank_properties_size()) > 0) {
        auto &rank_props = request.propertiesMap.lookupCreate(MapNames::RANK);
        add_multi_props(rank_props, proto.rank_properties());
        add_single_props(rank_props, proto.tensor_rank_properties());
    }
    request.groupSpec.assign(proto.grouping_blob().begin(), proto.grouping_blob().end());
    request.location = proto.geo_location();
    request.stackDump.assign(proto.query_tree_blob().begin(), proto.query_tree_blob().end());
}

void
ProtoConverter::search_reply_to_proto(const SearchReply &reply, ProtoSearchReply &proto)
{
    proto.set_total_hit_count(reply.totalHitCount);
    proto.set_coverage_docs(reply.coverage.getCovered());
    proto.set_active_docs(reply.coverage.getActive());
    proto.set_soon_active_docs(reply.coverage.getSoonActive());
    proto.set_degraded_by_match_phase(reply.coverage.wasDegradedByMatchPhase());
    proto.set_degraded_by_soft_timeout(reply.coverage.wasDegradedByTimeout());
    bool has_sort_data = (reply.sortIndex.size() > 0);
    assert(!has_sort_data || (reply.sortIndex.size() == (reply.hits.size() + 1)));
    if (reply.request) {
        uint32_t asked_offset = reply.request->offset;
        uint32_t asked_hits = reply.request->maxhits;
        size_t got_hits = reply.hits.size();
        if (got_hits < asked_hits && asked_offset + got_hits < reply.totalHitCount) {
            LOG(warning, "asked for %u hits [at offset %u] but only returning %zu hits from %" PRIu64 " available",
                asked_hits, asked_offset, got_hits, reply.totalHitCount);
        }
    }
    size_t num_match_features = reply.match_features.names.size();
    using FeatureValuesIterator = std::vector<search::FeatureValues::Value>::const_iterator;
    FeatureValuesIterator mfv_iter;
    bool has_match_features = (num_match_features > 0 && reply.hits.size() > 0);
    if (has_match_features) {
        size_t num_match_feature_values = reply.match_features.values.size();

        fprintf(stderr, "reply with %zu hits has %zu match features, total %zu/%zu\n",
                reply.hits.size(), num_match_features,
                num_match_feature_values, reply.hits.size() * num_match_features);

        assert(num_match_feature_values == reply.hits.size() * num_match_features);
        for (const auto & name : reply.match_features.names) {
            *proto.add_match_feature_names() = name;
        }
        mfv_iter = reply.match_features.values.begin();
    }
    for (size_t i = 0; i < reply.hits.size(); ++i) {
        auto *hit = proto.add_hits();
        hit->set_global_id(reply.hits[i].gid.get(), document::GlobalId::LENGTH);
        hit->set_relevance(reply.hits[i].metric);
        if (has_sort_data) {
            size_t sort_data_offset = reply.sortIndex[i];
            size_t sort_data_size = (reply.sortIndex[i + 1] - reply.sortIndex[i]);
            assert((sort_data_offset + sort_data_size) <= reply.sortData.size());
            hit->set_sort_data(&reply.sortData[sort_data_offset], sort_data_size);
        }
        if (has_match_features) {
            for (size_t j = 0; j < num_match_features; ++j) {
                auto * obj = hit->add_match_features();
                const auto & feature_value = *mfv_iter++;
                if (feature_value.is_data()) {
                    auto mem = feature_value.as_data();
                    obj->set_tensor(mem.data, mem.size);
                } else if (feature_value.is_double()) {
                    obj->set_number(feature_value.as_double());
                }
            }
        }
    }
    if (has_match_features) {
        assert(mfv_iter == reply.match_features.values.end());
    }
    proto.set_grouping_blob(&reply.groupResult[0], reply.groupResult.size());
    const auto &slime_trace = reply.propertiesMap.trace().lookup("slime");
    proto.set_slime_trace(slime_trace.get().data(), slime_trace.get().size());
    if (reply.my_issues) {
        reply.my_issues->for_each_message([&](const vespalib::string &err_msg)
                                          {
                                              auto *err_obj = proto.add_errors();
                                              err_obj->set_message(err_msg);
                                          });
    }
}

//-----------------------------------------------------------------------------

void
ProtoConverter::docsum_request_from_proto(const ProtoDocsumRequest &proto, DocsumRequest &request)
{
    request.setTimeout(1ms * proto.timeout());
    request.sessionId.assign(proto.session_key().begin(), proto.session_key().end());
    request.propertiesMap.lookupCreate(MapNames::MATCH).add("documentdb.searchdoctype", proto.document_type());
    request.resultClassName = proto.summary_class();
    if (proto.cache_query()) {
        request.propertiesMap.lookupCreate(MapNames::CACHES).add("query", "true");
    }
    request.dumpFeatures = proto.dump_features();
    request.ranking = proto.rank_profile();
    if ((proto.feature_overrides_size() + proto.tensor_feature_overrides_size()) > 0) {
        auto &feature_overrides = request.propertiesMap.lookupCreate(MapNames::FEATURE);
        add_multi_props(feature_overrides, proto.feature_overrides());
        add_single_props(feature_overrides, proto.tensor_feature_overrides());
    }
    if ((proto.rank_properties_size() + proto.tensor_rank_properties_size()) > 0) {
        auto &rank_props = request.propertiesMap.lookupCreate(MapNames::RANK);
        add_multi_props(rank_props, proto.rank_properties());
        add_single_props(rank_props, proto.tensor_rank_properties());
    }
    if(proto.highlight_terms_size() > 0) {
        auto &highlight_terms = request.propertiesMap.lookupCreate(MapNames::HIGHLIGHTTERMS);
        add_multi_props(highlight_terms, proto.highlight_terms());
    }
    request.location = proto.geo_location();
    request.stackDump.assign(proto.query_tree_blob().begin(), proto.query_tree_blob().end());
    request.hits.resize(proto.global_ids_size());
    for (int i = 0; i < proto.global_ids_size(); ++i) {
        const auto &gid = proto.global_ids(i);
        if (gid.size() == document::GlobalId::LENGTH) {
            request.hits[i].gid = document::GlobalId(gid.data());
        }
    }
}

void
ProtoConverter::docsum_reply_to_proto(const DocsumReply &reply, ProtoDocsumReply &proto)
{
    if (reply.hasResult()) {
        vespalib::SmartBuffer buf(4_Ki);
        vespalib::slime::BinaryFormat::encode(reply.slime(), buf);
        proto.set_slime_summaries(buf.obtain().data, buf.obtain().size);
    }
    if (reply.hasIssues()) {
        reply.issues().for_each_message([&](const vespalib::string &err_msg)
                                        {
                                            auto *err_obj = proto.add_errors();
                                            err_obj->set_message(err_msg);
                                        });
    }
}

//-----------------------------------------------------------------------------

void
ProtoConverter::monitor_request_from_proto(const ProtoMonitorRequest &, MonitorRequest &)
{
}

void
ProtoConverter::monitor_reply_to_proto(const MonitorReply &reply, ProtoMonitorReply &proto)
{
    proto.set_online(reply.timestamp != 0);
    proto.set_active_docs(reply.activeDocs);
    proto.set_distribution_key(reply.distribution_key);
    proto.set_is_blocking_writes(reply.is_blocking_writes);
}

//-----------------------------------------------------------------------------

}
<|endoftext|>


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

#include "remoting/host/simple_host.h"

#include "base/stl_util-inl.h"
#include "build/build_config.h"
#include "remoting/base/constants.h"
#include "remoting/base/protocol_decoder.h"
#include "remoting/host/session_manager.h"
#include "remoting/jingle_glue/jingle_channel.h"

namespace remoting {

SimpleHost::SimpleHost(const std::string& username,
                       const std::string& auth_token,
                       Capturer* capturer,
                       Encoder* encoder,
                       EventExecutor* executor)
      : capture_thread_("CaptureThread"),
        encode_thread_("EncodeThread"),
        username_(username),
        auth_token_(auth_token),
        capturer_(capturer),
        encoder_(encoder),
        executor_(executor) {
}

void SimpleHost::Run() {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Submit a task to perform host registration. We'll also start
  // listening to connection if registration is done.
  RegisterHost();

  // Run the main message loop. This is the main loop of this host
  // object.
  main_loop_.Run();
}

// This method is called when we need to the host process.
void SimpleHost::DestroySession() {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // First we tell the session to pause and then we wait until all
  // the tasks are done.
  if (session_.get()) {
    session_->Pause();

    // TODO(hclam): Revise the order.
    DCHECK(encode_thread_.IsRunning());
    encode_thread_.Stop();

    DCHECK(capture_thread_.IsRunning());
    capture_thread_.Stop();
  }
}

// This method talks to the cloud to register the host process. If
// successful we will start listening to network requests.
void SimpleHost::RegisterHost() {
  DCHECK_EQ(&main_loop_, MessageLoop::current());
  DCHECK(!jingle_client_);

  // Connect to the talk network with a JingleClient.
  jingle_client_ = new JingleClient();
  jingle_client_->Init(username_, auth_token_,
                       kChromotingTokenServiceName, this);
}

// This method is called if a client is connected to this object.
void SimpleHost::OnClientConnected(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Create a new RecordSession if there was none.
  if (!session_.get()) {
    // The first we need to make sure capture and encode thread are
    // running.
    capture_thread_.Start();
    encode_thread_.Start();

    // Then we create a SessionManager passing the message loops that
    // it should run on.
    // Note that we pass the ownership of the capturer and encoder to
    // the session manager.
    DCHECK(capturer_.get());
    DCHECK(encoder_.get());
    session_ = new SessionManager(capture_thread_.message_loop(),
                                  encode_thread_.message_loop(),
                                  &main_loop_,
                                  capturer_.release(),
                                  encoder_.release());

    // Immediately add the client and start the session.
    session_->AddClient(client);
    session_->Start();
    LOG(INFO) << "Session manager started";
  } else {
    // If a session manager already exists we simply add the new client.
    session_->AddClient(client);
  }
}

void SimpleHost::OnClientDisconnected(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Remove the client from the session manager.
  if (session_.get())
    session_->RemoveClient(client);

  // Also remove reference to ClientConnection from this object.
  client_ = NULL;

  // TODO(hclam): If the last client has disconnected we need destroy
  // the session manager and shutdown the capture and encode threads.
  // Right now we assume there's only one client.
  DestroySession();
}

////////////////////////////////////////////////////////////////////////////
// ClientConnection::EventHandler implementations
void SimpleHost::HandleMessages(ClientConnection* client,
                                ClientMessageList* messages) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Delegate the messages to EventExecutor and delete the unhandled
  // messages.
  DCHECK(executor_.get());
  executor_->HandleInputEvents(messages);
  STLDeleteElements<ClientMessageList>(messages);
}

void SimpleHost::OnConnectionOpened(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Completes the client connection.
  LOG(INFO) << "Connection to client established.";
  OnClientConnected(client_.get());
}

void SimpleHost::OnConnectionClosed(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Completes the client connection.
  LOG(INFO) << "Connection to client closed.";
  OnClientDisconnected(client_.get());
}

void SimpleHost::OnConnectionFailed(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // The client has disconnected.
  LOG(ERROR) << "Connection failed unexpectedly.";
  OnClientDisconnected(client_.get());
}

////////////////////////////////////////////////////////////////////////////
// JingleClient::Callback implementations
void SimpleHost::OnStateChange(JingleClient* jingle_client,
                               JingleClient::State state) {
  DCHECK_EQ(jingle_client_.get(), jingle_client);

  if (state == JingleClient::CONNECTED) {
    LOG(INFO) << "Host connected as "
              << jingle_client->GetFullJid() << "." << std::endl;

    // Start heartbeating after we connected
    heartbeat_sender_ = new HeartbeatSender();
    // TODO(sergeyu): where do we get host id?
    heartbeat_sender_->Start(jingle_client_.get(), "HostID");
  } else if (state == JingleClient::CLOSED) {
    LOG(INFO) << "Host disconnected from talk network." << std::endl;
    heartbeat_sender_ = NULL;

    // Quit the message loop if disconected.
    main_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }
}

bool SimpleHost::OnAcceptConnection(
    JingleClient* jingle_client, const std::string& jid,
    JingleChannel::Callback** channel_callback) {
  DCHECK_EQ(jingle_client_.get(), jingle_client);

  // TODO(hclam): Allow multiple clients to connect to the host.
  if (client_.get())
    return false;

  LOG(INFO) << "Client connected: " << jid << std::endl;

  // If we accept the connected then create a client object and set the
  // callback.
  client_ = new ClientConnection(&main_loop_, new ProtocolDecoder(), this);
  *channel_callback = client_.get();
  return true;
}

void SimpleHost::OnNewConnection(JingleClient* jingle_client,
                                 scoped_refptr<JingleChannel> channel) {
  DCHECK_EQ(jingle_client_.get(), jingle_client);

  // Since the session manager has not started, it is still safe to access
  // the client directly. Note that we give the ownership of the channel
  // to the client.
  client_->set_jingle_channel(channel);
}

}  // namespace remoting
<commit_msg>Set up the message loop of the mac host to be UI based so that it can pick up the system callbacks about screen changes. Also clean up some comments.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/simple_host.h"

#include "base/stl_util-inl.h"
#include "build/build_config.h"
#include "remoting/base/constants.h"
#include "remoting/base/protocol_decoder.h"
#include "remoting/host/session_manager.h"
#include "remoting/jingle_glue/jingle_channel.h"

namespace remoting {

#if defined (OS_MACOSX)
// The Mac depends on system callbacks to tell it what rectangles need to
// be updated, so we need to use the system message loop.
const MessageLoop::Type kSimpleHostMessageLoopType = MessageLoop::TYPE_UI;
#else
const MessageLoop::Type kSimpleHostMessageLoopType = MessageLoop::TYPE_DEFAULT;
#endif //  defined (OS_MACOSX)

SimpleHost::SimpleHost(const std::string& username,
                       const std::string& auth_token,
                       Capturer* capturer,
                       Encoder* encoder,
                       EventExecutor* executor)
      : main_loop_(kSimpleHostMessageLoopType),
        capture_thread_("CaptureThread"),
        encode_thread_("EncodeThread"),
        username_(username),
        auth_token_(auth_token),
        capturer_(capturer),
        encoder_(encoder),
        executor_(executor) {
}

void SimpleHost::Run() {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Submit a task to perform host registration. We'll also start
  // listening to connection if registration is done.
  RegisterHost();

  // Run the main message loop. This is the main loop of this host
  // object.
  main_loop_.Run();
}

// This method is called when we need to destroy the host process.
void SimpleHost::DestroySession() {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // First we tell the session to pause and then we wait until all
  // the tasks are done.
  if (session_.get()) {
    session_->Pause();

    // TODO(hclam): Revise the order.
    DCHECK(encode_thread_.IsRunning());
    encode_thread_.Stop();

    DCHECK(capture_thread_.IsRunning());
    capture_thread_.Stop();
  }
}

// This method talks to the cloud to register the host process. If
// successful we will start listening to network requests.
void SimpleHost::RegisterHost() {
  DCHECK_EQ(&main_loop_, MessageLoop::current());
  DCHECK(!jingle_client_);

  // Connect to the talk network with a JingleClient.
  jingle_client_ = new JingleClient();
  jingle_client_->Init(username_, auth_token_,
                       kChromotingTokenServiceName, this);
}

// This method is called if a client is connected to this object.
void SimpleHost::OnClientConnected(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Create a new RecordSession if there was none.
  if (!session_.get()) {
    // The first we need to make sure capture and encode thread are
    // running.
    capture_thread_.Start();
    encode_thread_.Start();

    // Then we create a SessionManager passing the message loops that
    // it should run on.
    // Note that we pass the ownership of the capturer and encoder to
    // the session manager.
    DCHECK(capturer_.get());
    DCHECK(encoder_.get());
    session_ = new SessionManager(capture_thread_.message_loop(),
                                  encode_thread_.message_loop(),
                                  &main_loop_,
                                  capturer_.release(),
                                  encoder_.release());

    // Immediately add the client and start the session.
    session_->AddClient(client);
    session_->Start();
    LOG(INFO) << "Session manager started";
  } else {
    // If a session manager already exists we simply add the new client.
    session_->AddClient(client);
  }
}

void SimpleHost::OnClientDisconnected(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Remove the client from the session manager.
  if (session_.get())
    session_->RemoveClient(client);

  // Also remove reference to ClientConnection from this object.
  client_ = NULL;

  // TODO(hclam): If the last client has disconnected we need to destroy
  // the session manager and shutdown the capture and encode threads.
  // Right now we assume that there's only one client.
  DestroySession();
}

////////////////////////////////////////////////////////////////////////////
// ClientConnection::EventHandler implementations
void SimpleHost::HandleMessages(ClientConnection* client,
                                ClientMessageList* messages) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Delegate the messages to EventExecutor and delete the unhandled
  // messages.
  DCHECK(executor_.get());
  executor_->HandleInputEvents(messages);
  STLDeleteElements<ClientMessageList>(messages);
}

void SimpleHost::OnConnectionOpened(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Completes the client connection.
  LOG(INFO) << "Connection to client established.";
  OnClientConnected(client_.get());
}

void SimpleHost::OnConnectionClosed(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // Completes the client connection.
  LOG(INFO) << "Connection to client closed.";
  OnClientDisconnected(client_.get());
}

void SimpleHost::OnConnectionFailed(ClientConnection* client) {
  DCHECK_EQ(&main_loop_, MessageLoop::current());

  // The client has disconnected.
  LOG(ERROR) << "Connection failed unexpectedly.";
  OnClientDisconnected(client_.get());
}

////////////////////////////////////////////////////////////////////////////
// JingleClient::Callback implementations
void SimpleHost::OnStateChange(JingleClient* jingle_client,
                               JingleClient::State state) {
  DCHECK_EQ(jingle_client_.get(), jingle_client);

  if (state == JingleClient::CONNECTED) {
    LOG(INFO) << "Host connected as "
              << jingle_client->GetFullJid() << "." << std::endl;

    // Start heartbeating after we connected
    heartbeat_sender_ = new HeartbeatSender();
    // TODO(sergeyu): where do we get host id?
    heartbeat_sender_->Start(jingle_client_.get(), "HostID");
  } else if (state == JingleClient::CLOSED) {
    LOG(INFO) << "Host disconnected from talk network." << std::endl;
    heartbeat_sender_ = NULL;

    // Quit the message loop if disconected.
    main_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }
}

bool SimpleHost::OnAcceptConnection(
    JingleClient* jingle_client, const std::string& jid,
    JingleChannel::Callback** channel_callback) {
  DCHECK_EQ(jingle_client_.get(), jingle_client);

  // TODO(hclam): Allow multiple clients to connect to the host.
  if (client_.get())
    return false;

  LOG(INFO) << "Client connected: " << jid << std::endl;

  // If we accept the connected then create a client object and set the
  // callback.
  client_ = new ClientConnection(&main_loop_, new ProtocolDecoder(), this);
  *channel_callback = client_.get();
  return true;
}

void SimpleHost::OnNewConnection(JingleClient* jingle_client,
                                 scoped_refptr<JingleChannel> channel) {
  DCHECK_EQ(jingle_client_.get(), jingle_client);

  // Since the session manager has not started, it is still safe to access
  // the client directly. Note that we give the ownership of the channel
  // to the client.
  client_->set_jingle_channel(channel);
}

}  // namespace remoting
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include <iostream>

#include "db/test/Test.h"
#include "db/test/Tester.h"
#include "db/test/TestRunner.h"
#include "db/rt/Runnable.h"
#include "db/rt/System.h"

using namespace std;
using namespace db::test;
using namespace db::rt;

void runDynoIterTest1(TestRunner& tr, const char* name, int size, int iter)
{
   tr.test(name);
   {
      DynamicObject d1;
      for(int i = 0; i < size; i++)
      {
         d1[i] = i;
      }

      uint64_t start = System::getCurrentMilliseconds();

      for(int j = 0; j < iter; j++)
      {
         DynamicObjectIterator i = d1.getIterator();
         while(i->hasNext())
         {
            DynamicObject next = i->next();
         }
      }

      uint64_t stop = System::getCurrentMilliseconds();

      cout << "[dt:" << stop-start << "]";
   }
   tr.passIfNoException();
}

void runDynoIterTest(TestRunner& tr)
{
   tr.group("DynamicObject iter perf");

   runDynoIterTest1(tr, "array (10k * 1k)", 10000, 1000);
   runDynoIterTest1(tr, "array (1k * 10k)", 1000, 10000);
   runDynoIterTest1(tr, "array (100 * 100k)", 100, 100000);
   runDynoIterTest1(tr, "array (10 * 1M)", 10, 1000000);

   tr.ungroup();
}

class DbDynoPerfTester : public db::test::Tester
{
public:
   DbDynoPerfTester()
   {
      setName("dyno-perf");
   }

   /**
    * Run automatic unit tests.
    */
   virtual int runAutomaticTests(TestRunner& tr)
   {
      return 0;
   }

   /**
    * Runs interactive unit tests.
    */
   virtual int runInteractiveTests(TestRunner& tr)
   {
      runDynoIterTest(tr);
      return 0;
   }
};

#ifndef DB_TEST_NO_MAIN
DB_TEST_MAIN(DbDynoPerfTester)
#endif
<commit_msg>Expand dyno perf test.<commit_after>/*
 * Copyright (c) 2007-2008 Digital Bazaar, Inc.  All rights reserved.
 */
#include <iostream>

#include "db/test/Test.h"
#include "db/test/Tester.h"
#include "db/test/TestRunner.h"
#include "db/rt/Runnable.h"
#include "db/rt/System.h"

using namespace std;
using namespace db::config;
using namespace db::test;
using namespace db::rt;

static bool header = true;

static void runDynoIterTest1(
   TestRunner& tr, const char* name, int dynos, int iter)
{
   tr.test(name);
   {

      uint64_t start_init = System::getCurrentMilliseconds();
      DynamicObject d1;
      d1->setType(Array);
      for(int i = 0; i < dynos; i++)
      {
         d1[i] = i;
      }
      uint64_t start_iter = System::getCurrentMilliseconds();
      for(int j = 0; j < iter; j++)
      {
         DynamicObjectIterator i = d1.getIterator();
         while(i->hasNext())
         {
            DynamicObject next = i->next();
         }
      }
      uint64_t iter_dt = System::getCurrentMilliseconds() - start_iter;
      uint64_t init_dt = start_iter - start_init;

      if(header)
      {
         printf(
            "%9s %9s "
            "%8s %9s "
            "%8s %10s %9s "
            "%9s\n",
            "dynos", "iter",
            "init (s)", "d/ms",
            "iter (s)", "i/s", "(d*i)/ms",
            "total (s)");
         header = false;
      }
      printf(
         "%9d %9d "
         "%8.3f %9.3f "
         "%8.3f %10.3f %9.3f "
         "%9.3f\n",
         dynos, iter,
         init_dt/1000.0, dynos/(double)init_dt,
         iter_dt/1000.0, iter/(iter_dt/1000.0), (dynos*iter)/(double)iter_dt,
         (init_dt + iter_dt)/1000.0);
   }
   tr.passIfNoException();
}

void runDynoIterTest(TestRunner& tr)
{
   tr.group("DynamicObject iter perf");

   bool all = false;
   Config& cfg = tr.getApp()->getConfig();
   if(cfg->hasMember("all"))
   {
      all = cfg["all"]->getBoolean();
   }
   if(all)
   {
      //runDynoIterTest1(tr, "array s:10M  i:1    ", 10000000, 1);
      runDynoIterTest1(tr, "array s:1M   i:1    ", 1000000,  1);
      runDynoIterTest1(tr, "array s:1M   i:2    ", 1000000,  2);
      runDynoIterTest1(tr, "array s:1M   i:5    ", 1000000,  5);
      runDynoIterTest1(tr, "array s:1M   i:10   ", 1000000, 10);
   }
   runDynoIterTest1(tr, "array s:100K i:100  ", 100000, 100);
   runDynoIterTest1(tr, "array s:10K  i:1K   ", 10000, 1000);
   runDynoIterTest1(tr, "array s:1K   i:10K  ", 1000, 10000);
   runDynoIterTest1(tr, "array s:100  i:100K ", 100, 100000);
   runDynoIterTest1(tr, "array s:10   i:1M   ", 10, 1000000);
   if(all)
   {
      runDynoIterTest1(tr, "array s:5    i:1M   ", 5,  1000000);
      runDynoIterTest1(tr, "array s:2    i:1M   ", 2,  1000000);
      runDynoIterTest1(tr, "array s:1    i:1M   ", 1,  1000000);
      runDynoIterTest1(tr, "array s:0    i:1M   ", 0,  1000000);
      //runDynoIterTest1(tr, "array s:5    i:2M   ", 5,  2000000);
      //runDynoIterTest1(tr, "array s:2    i:5M   ", 2,  5000000);
      //runDynoIterTest1(tr, "array s:1    i:10M  ", 1, 10000000);
   }

   tr.ungroup();
}

class DbDynoPerfTester : public db::test::Tester
{
public:
   DbDynoPerfTester()
   {
      setName("dyno-perf");
   }

   /**
    * Run automatic unit tests.
    */
   virtual int runAutomaticTests(TestRunner& tr)
   {
      return 0;
   }

   /**
    * Runs interactive unit tests.
    */
   virtual int runInteractiveTests(TestRunner& tr)
   {
      runDynoIterTest(tr);
      return 0;
   }
};

#ifndef DB_TEST_NO_MAIN
DB_TEST_MAIN(DbDynoPerfTester)
#endif
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) 2011-2012 Clever Team
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef CLEVER_DEBUG
#include <stdio.h>
#include "core/opcode.h"
#endif
#include "core/cstring.h"
#include "core/scope.h"
#include "core/value.h"
#include "types/type.h"
#include "core/vm.h"

namespace clever {

// VM initialization phase
inline void VM::init()
{
	// Opcode handler mapping
	m_handlers[OP_RET]      = &VM::ret;
	m_handlers[OP_ASSIGN]   = &VM::assignment;
	m_handlers[OP_ADD]      = &VM::add;
	m_handlers[OP_SUB]      = &VM::sub;
	m_handlers[OP_MUL]      = &VM::mul;
	m_handlers[OP_DIV]      = &VM::div;
	m_handlers[OP_MOD]      = &VM::sub;
	m_handlers[OP_JMP]      = &VM::jmp;
	m_handlers[OP_FCALL]    = &VM::fcall;
	m_handlers[OP_LEAVE]    = &VM::leave;
	m_handlers[OP_SEND_VAL] = &VM::send_val;
	m_handlers[OP_JMPZ]     = &VM::jmpz;
	m_handlers[OP_PRE_INC]  = &VM::inc;
	m_handlers[OP_POS_INC]  = &VM::inc;
	m_handlers[OP_PRE_DEC]  = &VM::dec;
	m_handlers[OP_POS_DEC]  = &VM::dec;
}

inline Value* VM::getValue(size_t scope_id, size_t value_id) const
{
	return (*m_scope_pool)[scope_id]->getValue(value_id);
}

#ifdef CLEVER_DEBUG
void VM::dumpOpcodes() const
{
	const char *op_type[] = {
		"UNUSED", "FETCH_VAL", "JMP_ADDR"
	};

	for (size_t i = 0, j = m_inst.size(); i < j; ++i) {
		IR& ir = m_inst[i];
		::printf("[%03ld] %-12s | %3ld:%3ld (%-9s) | %3ld:%3ld (%-9s) | %p\n",
			i,
			get_opcode_name(ir.opcode),
			ir.op1, ir.op1_scope, op_type[ir.op1_type],
			ir.op2, ir.op2_scope, op_type[ir.op2_type],
			ir.result);
	}
}
#endif

// Return operation
VM_HANDLER(ret)
{
	if (m_call_stack.size()) {
		const StackFrame& frame = m_call_stack.top();
		const Value* val = getValue(op.op1_scope, op.op1);

		if (val) {
			m_call_stack.top().ret_val->copy(getValue(op.op1_scope, op.op1));
		}
		m_call_stack.pop();

		// Go back to the caller
		VM_GOTO(frame.ret_addr);
	} else {
		// Terminates the execution
		VM_GOTO(m_inst.size());
	}
}

// JMP operation
VM_HANDLER(jmp)
{
	VM_GOTO(op.op1);
}

// JMPZ operation
VM_HANDLER(jmpz)
{
	Value* value = getValue(op.op1_scope, op.op1);

	if (!value->getInt()) {
		VM_GOTO(op.op2);
	}

	VM_NEXT();
}

// Assignment operation
VM_HANDLER(assignment)
{
	Value* var = getValue(op.op1_scope, op.op1);
	Value* value = getValue(op.op2_scope, op.op2);

	var->copy(value);

	VM_NEXT();
}

// Math sum operation
VM_HANDLER(add)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() + rhs->getInt());
	}

	VM_NEXT();
}

// Math subtraction operation
VM_HANDLER(sub)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() - rhs->getInt());
	}

	VM_NEXT();
}

// Math multiplication operation
VM_HANDLER(mul)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() * rhs->getInt());
	}

	VM_NEXT();
}

// Math division operation
VM_HANDLER(div)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() / rhs->getInt());
	}

	VM_NEXT();
}

// Math modulus operation
VM_HANDLER(mod)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() % rhs->getInt());
	}

	VM_NEXT();
}

// Receives values to be used in the next function call
VM_HANDLER(send_val)
{
	m_call_args.push_back(getValue(op.op1_scope, op.op1));

	VM_NEXT();
}

// Saves function argument and local variables
void VM::saveVars()
{/*
	Scope* arg_vars   = m_call_stack.top().arg_vars;
	Scope* local_vars = m_call_stack.top().local_vars;

	if (arg_vars) {
		// Save the function argument values
		for (size_t i = 0, j = arg_vars->size(); i < j; ++i) {
			Value* tmp = new Value();

			tmp->copy(getValue(arg_vars->at(i).value_id));
			m_call_stack.top().vars.push_back(
				std::pair<size_t, Value*>(
					arg_vars->at(i).value_id, tmp));
		}
	}
	if (EXPECTED(local_vars != NULL)) {
		// Save the local variables
		for (size_t i = 0, j = local_vars->size(); i < j; ++i) {
			Value* tmp = new Value();

			tmp->copy(getValue(local_vars->at(i).value_id));
			m_call_stack.top().vars.push_back(
				std::pair<size_t, Value*>(
					local_vars->at(i).value_id, tmp));
		}
	}*/
}

// Restore the argument and local variables values
void VM::restoreVars() const
{/*
	FuncVars::const_iterator it = m_call_stack.top().vars.begin(),
		end = m_call_stack.top().vars.end();

	while (EXPECTED(it != end)) {
		Value* var = getValue((*it).first);
		var->copy((*it).second);
		++it;
	}*/
}

// Function call operation
VM_HANDLER(fcall)
{
	Value* func = getValue(op.op1_scope, op.op1);
	Function* fdata = static_cast<Function*>(func->getObj());

	if (fdata->isUserDefined()) {
		// Save arguments and local vars on possible recursion
		if (m_call_stack.size()) {
			saveVars();
		}

		// Pushs a new stack frame for the user function call on the call stack
		m_call_stack.push(StackFrame());

		// Sets the return address to the next instruction
		m_call_stack.top().ret_addr = m_pc + 1;

		// Save the function return value address
		m_call_stack.top().ret_val = op.result;

		// Function argument value binding
		if (fdata->hasArgs()) {
			Scope* arg_scope = fdata->getArgVars();

			m_call_stack.top().arg_vars = arg_scope;

			for (size_t i = 0, j = arg_scope->size(); i < j; ++i) {
				Value* arg_val = getValue(
					arg_scope->at(i).scope->getId(), arg_scope->at(i).value_id);
				arg_val->copy(m_call_args[i]);
			}

			m_call_args.clear();
		}

		VM_GOTO(fdata->getAddr());
	} else {
		fdata->getPtr()(m_call_args);
		m_call_args.clear();

		VM_NEXT();
	}
}

// Leave operation
VM_HANDLER(leave)
{
	const StackFrame& frame = m_call_stack.top();

	if (m_call_stack.size() > 1) {
		restoreVars();
	}

	m_call_stack.pop();

	// Go back to the next instruction after the caller
	VM_GOTO(frame.ret_addr);
}

// Increment operation
VM_HANDLER(inc)
{
	Value* value = getValue(op.op1_scope, op.op1);

	if (op.opcode == OP_PRE_INC) {
		value->getType()->increment(value);
		op.result->copy(value);
	} else {
		op.result->copy(value);
		value->getType()->increment(value);
	}

	VM_NEXT();
}

// Decrement operation
VM_HANDLER(dec)
{
	Value* value = getValue(op.op1_scope, op.op1);

	if (op.opcode == OP_PRE_DEC) {
		value->getType()->decrement(value);
		op.result->copy(value);
	} else {
		op.result->copy(value);
		value->getType()->decrement(value);
	}

	VM_NEXT();
}

// Executes the VM opcodes in a continuation-passing style
void VM::run()
{
	// Loads the opcode handlers
	init();

	for (size_t n = m_inst.size(); m_pc < n;) {
		(this->*m_handlers[m_inst[m_pc].opcode])(m_inst[m_pc]);
	}
}

} // clever
<commit_msg>- Removed some uneeded comments on VM<commit_after>/**
 * Clever programming language
 * Copyright (c) 2011-2012 Clever Team
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifdef CLEVER_DEBUG
#include <stdio.h>
#include "core/opcode.h"
#endif
#include "core/cstring.h"
#include "core/scope.h"
#include "core/value.h"
#include "types/type.h"
#include "core/vm.h"

namespace clever {

// VM initialization phase
inline void VM::init()
{
	// Opcode handler mapping
	m_handlers[OP_RET]      = &VM::ret;
	m_handlers[OP_ASSIGN]   = &VM::assignment;
	m_handlers[OP_ADD]      = &VM::add;
	m_handlers[OP_SUB]      = &VM::sub;
	m_handlers[OP_MUL]      = &VM::mul;
	m_handlers[OP_DIV]      = &VM::div;
	m_handlers[OP_MOD]      = &VM::sub;
	m_handlers[OP_JMP]      = &VM::jmp;
	m_handlers[OP_FCALL]    = &VM::fcall;
	m_handlers[OP_LEAVE]    = &VM::leave;
	m_handlers[OP_SEND_VAL] = &VM::send_val;
	m_handlers[OP_JMPZ]     = &VM::jmpz;
	m_handlers[OP_PRE_INC]  = &VM::inc;
	m_handlers[OP_POS_INC]  = &VM::inc;
	m_handlers[OP_PRE_DEC]  = &VM::dec;
	m_handlers[OP_POS_DEC]  = &VM::dec;
}

inline Value* VM::getValue(size_t scope_id, size_t value_id) const
{
	return (*m_scope_pool)[scope_id]->getValue(value_id);
}

#ifdef CLEVER_DEBUG
void VM::dumpOpcodes() const
{
	const char *op_type[] = {
		"UNUSED", "FETCH_VAL", "JMP_ADDR"
	};

	for (size_t i = 0, j = m_inst.size(); i < j; ++i) {
		IR& ir = m_inst[i];
		::printf("[%03ld] %-12s | %3ld:%3ld (%-9s) | %3ld:%3ld (%-9s) | %p\n",
			i,
			get_opcode_name(ir.opcode),
			ir.op1, ir.op1_scope, op_type[ir.op1_type],
			ir.op2, ir.op2_scope, op_type[ir.op2_type],
			ir.result);
	}
}
#endif

// Return operation
VM_HANDLER(ret)
{
	if (m_call_stack.size()) {
		const StackFrame& frame = m_call_stack.top();
		const Value* val = getValue(op.op1_scope, op.op1);

		if (val) {
			m_call_stack.top().ret_val->copy(getValue(op.op1_scope, op.op1));
		}
		m_call_stack.pop();

		// Go back to the caller
		VM_GOTO(frame.ret_addr);
	} else {
		// Terminates the execution
		VM_GOTO(m_inst.size());
	}
}

// JMP operation
VM_HANDLER(jmp)
{
	VM_GOTO(op.op1);
}

// JMPZ operation
VM_HANDLER(jmpz)
{
	Value* value = getValue(op.op1_scope, op.op1);

	if (!value->getInt()) {
		VM_GOTO(op.op2);
	}

	VM_NEXT();
}

// Assignment operation
VM_HANDLER(assignment)
{
	Value* var = getValue(op.op1_scope, op.op1);
	Value* value = getValue(op.op2_scope, op.op2);

	var->copy(value);

	VM_NEXT();
}

// Math sum operation
VM_HANDLER(add)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() + rhs->getInt());
	}

	VM_NEXT();
}

// Math subtraction operation
VM_HANDLER(sub)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() - rhs->getInt());
	}

	VM_NEXT();
}

// Math multiplication operation
VM_HANDLER(mul)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() * rhs->getInt());
	}

	VM_NEXT();
}

// Math division operation
VM_HANDLER(div)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() / rhs->getInt());
	}

	VM_NEXT();
}

// Math modulus operation
VM_HANDLER(mod)
{
	Value* lhs = getValue(op.op1_scope, op.op1);
	Value* rhs = getValue(op.op2_scope, op.op2);

	if (lhs->getType() == CLEVER_INT_TYPE
		&& rhs->getType() == CLEVER_INT_TYPE) {
		op.result->setInt(lhs->getInt() % rhs->getInt());
	}

	VM_NEXT();
}

// Receives values to be used in the next function call
VM_HANDLER(send_val)
{
	m_call_args.push_back(getValue(op.op1_scope, op.op1));

	VM_NEXT();
}

// Saves function argument and local variables
void VM::saveVars()
{/*
	Scope* arg_vars   = m_call_stack.top().arg_vars;
	Scope* local_vars = m_call_stack.top().local_vars;

	if (arg_vars) {
		// Save the function argument values
		for (size_t i = 0, j = arg_vars->size(); i < j; ++i) {
			Value* tmp = new Value();

			tmp->copy(getValue(arg_vars->at(i).value_id));
			m_call_stack.top().vars.push_back(
				std::pair<size_t, Value*>(
					arg_vars->at(i).value_id, tmp));
		}
	}
	if (EXPECTED(local_vars != NULL)) {
		// Save the local variables
		for (size_t i = 0, j = local_vars->size(); i < j; ++i) {
			Value* tmp = new Value();

			tmp->copy(getValue(local_vars->at(i).value_id));
			m_call_stack.top().vars.push_back(
				std::pair<size_t, Value*>(
					local_vars->at(i).value_id, tmp));
		}
	}*/
}

// Restore the argument and local variables values
void VM::restoreVars() const
{/*
	FuncVars::const_iterator it = m_call_stack.top().vars.begin(),
		end = m_call_stack.top().vars.end();

	while (EXPECTED(it != end)) {
		Value* var = getValue((*it).first);
		var->copy((*it).second);
		++it;
	}*/
}

// Function call operation
VM_HANDLER(fcall)
{
	Value* func = getValue(op.op1_scope, op.op1);
	Function* fdata = static_cast<Function*>(func->getObj());

	if (fdata->isUserDefined()) {
		if (m_call_stack.size()) {
			saveVars();
		}
		m_call_stack.push(StackFrame());
		m_call_stack.top().ret_addr = m_pc + 1;
		m_call_stack.top().ret_val  = op.result;

		// Function argument value binding
		if (fdata->hasArgs()) {
			Scope* arg_scope = fdata->getArgVars();

			m_call_stack.top().arg_vars = arg_scope;

			for (size_t i = 0, j = arg_scope->size(); i < j; ++i) {
				Value* arg_val = getValue(
					arg_scope->at(i).scope->getId(),
					arg_scope->at(i).value_id);

				arg_val->copy(m_call_args[i]);
			}
			m_call_args.clear();
		}
		VM_GOTO(fdata->getAddr());
	} else {
		fdata->getPtr()(m_call_args);
		m_call_args.clear();

		VM_NEXT();
	}
}

// Leave operation
VM_HANDLER(leave)
{
	const StackFrame& frame = m_call_stack.top();

	if (m_call_stack.size() > 1) {
		restoreVars();
	}

	m_call_stack.pop();

	// Go back to the next instruction after the caller
	VM_GOTO(frame.ret_addr);
}

// Increment operation
VM_HANDLER(inc)
{
	Value* value = getValue(op.op1_scope, op.op1);

	if (op.opcode == OP_PRE_INC) {
		value->getType()->increment(value);
		op.result->copy(value);
	} else {
		op.result->copy(value);
		value->getType()->increment(value);
	}

	VM_NEXT();
}

// Decrement operation
VM_HANDLER(dec)
{
	Value* value = getValue(op.op1_scope, op.op1);

	if (op.opcode == OP_PRE_DEC) {
		value->getType()->decrement(value);
		op.result->copy(value);
	} else {
		op.result->copy(value);
		value->getType()->decrement(value);
	}

	VM_NEXT();
}

// Executes the VM opcodes in a continuation-passing style
void VM::run()
{
	// Loads the opcode handlers
	init();

	for (size_t n = m_inst.size(); m_pc < n;) {
		(this->*m_handlers[m_inst[m_pc].opcode])(m_inst[m_pc]);
	}
}

} // clever
<|endoftext|>