<commit_before>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include "eventql/db/metadata_coordinator.h"

namespace eventql {

MetadataCoordinator::MetadataCoordinator(ConfigDirectory* cdir) : cdir_(cdir) {}

Status MetadataCoordinator::performAndCommitOperation(
    const String& ns,
    const String& table_name,
    MetadataOperation op) {
  auto table_config = cdir_->getTableConfig(ns, table_name);
  SHA1Hash input_txid(
      table_config.metadata_txnid().data(),
      table_config.metadata_txnid().size());

  if (!(input_txid == op.getInputTransactionID())) {
    return Status(eConcurrentModificationError, "concurrent modification");
  }

  Vector<String> servers;
  for (const auto& s : table_config.metadata_servers()) {
    servers.emplace_back(s);
  }

  auto rc = performOperation(ns, table_name, op, servers);
  if (!rc.isSuccess()) {
    return rc;
  }

  auto output_txid = op.getOutputTransactionID();
  table_config.set_metadata_txnid(output_txid.data(), output_txid.size());
  table_config.set_metadata_txnseq(table_config.metadata_txnseq() + 1);
  cdir_->updateTableConfig(table_config);
  return Status::success();
}

Status MetadataCoordinator::performOperation(
    const String& ns,
    const String& table_name,
    MetadataOperation op,
    const Vector<String>& servers) {
  size_t num_servers = servers.size();
  if (num_servers == 0) {
    return Status(eIllegalArgumentError, "server list can't be empty");
  }

  size_t failures = 0;
  for (const auto& s : servers) {
    auto rc = performOperation(ns, table_name, op, s);
    if (!rc.isSuccess()) {
      logWarning(
          "evqld",
          "error while performing metadata operation: $0",
          rc.message());
      ++failures;
    }
  }

  size_t max_failures = 0;
  if (num_servers > 1) {
    max_failures = (num_servers - 1) / 2;
  }

  if (failures <= max_failures) {
    return Status::success();
  } else {
    return Status(eRuntimeError, "error while performing metadata operation");
  }
}

Status MetadataCoordinator::performOperation(
    const String& ns,
    const String& table_name,
    MetadataOperation op,
    const String& server) {
  auto server_cfg = cdir_->getServerConfig(server);
  if (server_cfg.server_addr().empty()) {
    return Status(eRuntimeError, "server is offline");
  }

  logDebug(
      "evqld",
      "Performing metadata operation on: $0/$1 ($2->$3) on $3 ($4)",
      ns,
      table_name,
      op.getInputTransactionID().toString(),
      op.getOutputTransactionID().toString(),
      server,
      server_cfg.server_addr());

  auto url = StringUtil::format(
      "http://$0/rpc/perform_metadata_operation?namespace=$1&table=$2",
      server_cfg.server_addr(),
      URI::urlEncode(ns),
      URI::urlEncode(table_name));

  Buffer req_body;
  {
    auto os = BufferOutputStream::fromBuffer(&req_body);
    auto rc = op.encode(os.get());
    if (!rc.isSuccess()) {
      return rc;
    }
  }

  auto req = http::HTTPRequest::mkPost(url, req_body);
  //auth_->signRequest(static_cast<Session*>(txn_->getUserData()), &req);

  http::HTTPClient http_client;
  http::HTTPResponse res;
  auto rc = http_client.executeRequest(req, &res);
  if (!rc.isSuccess()) {
    return rc;
  }

  if (res.statusCode() == 201) {
    return Status::success();
  } else {
    return Status(eIOError, res.body().toString());
  }
}

Status MetadataCoordinator::createFile(
    const String& ns,
    const String& table_name,
    const MetadataFile& file,
    const Vector<String>& servers) {
  size_t num_servers = servers.size();
  if (num_servers == 0) {
    return Status(eIllegalArgumentError, "server list can't be empty");
  }

  size_t failures = 0;
  for (const auto& s : servers) {
    auto rc = createFile(ns, table_name, file, s);
    if (!rc.isSuccess()) {
      logWarning("evqld", "error while creating metadata file: $0", rc.message());
      ++failures;
    }
  }

  size_t max_failures = 0;
  if (num_servers > 1) {
    max_failures = (num_servers - 1) / 2;
  }

  if (failures <= max_failures) {
    return Status::success();
  } else {
    return Status(eRuntimeError, "error while creating metadata file");
  }
}

Status MetadataCoordinator::createFile(
    const String& ns,
    const String& table_name,
    const MetadataFile& file,
    const String& server) {
  auto server_cfg = cdir_->getServerConfig(server);
  if (server_cfg.server_addr().empty()) {
    return Status(eRuntimeError, "server is offline");
  }

  logDebug(
      "evqld",
      "Creating metadata file: $0/$1/$2 on $3 ($4)",
      ns,
      table_name,
      file.getTransactionID(),
      server,
      server_cfg.server_addr());

  auto url = StringUtil::format(
      "http://$0/rpc/create_metadata_file?namespace=$1&table=$2",
      server_cfg.server_addr(),
      URI::urlEncode(ns),
      URI::urlEncode(table_name));

  Buffer req_body;
  {
    auto os = BufferOutputStream::fromBuffer(&req_body);
    auto rc = file.encode(os.get());
    if (!rc.isSuccess()) {
      return rc;
    }
  }

  auto req = http::HTTPRequest::mkPost(url, req_body);
  //auth_->signRequest(static_cast<Session*>(txn_->getUserData()), &req);

  http::HTTPClient http_client;
  http::HTTPResponse res;
  auto rc = http_client.executeRequest(req, &res);
  if (!rc.isSuccess()) {
    return rc;
  }

  if (res.statusCode() == 201) {
    return Status::success();
  } else {
    return Status(eIOError, res.body().toString());
  }
}

Status MetadataCoordinator::discoverPartition(
    PartitionDiscoveryRequest request,
    PartitionDiscoveryResponse* response) {
  auto table_cfg = cdir_->getTableConfig(
      request.db_namespace(),
      request.table_id());

  if (table_cfg.metadata_txnseq() < request.min_txnseq()) {
    return Status(eConcurrentModificationError, "concurrent modification");
  }

  request.set_requester_id(cdir_->getServerID());

  http::HTTPClient http_client;
  for (const auto& s : table_cfg.metadata_servers()) {
    auto server = cdir_->getServerConfig(s);
    if (server.server_status() != SERVER_UP) {
      continue;
    }

    auto url = StringUtil::format(
        "http://$0/rpc/discover_partition_metadata",
        server.server_addr());

    Buffer req_body;
    auto req = http::HTTPRequest::mkPost(url, *msg::encode(request));
    //auth_->signRequest(static_cast<Session*>(txn_->getUserData()), &req);

    http::HTTPResponse res;
    auto rc = http_client.executeRequest(req, &res);
    if (!rc.isSuccess()) {
      logWarning("evqld", "metadata discovery failed: $0", rc.message());
      continue;
    }

    if (res.statusCode() == 200) {
      *response = msg::decode<PartitionDiscoveryResponse>(res.body());
      return Status::success();
    } else {
      logWarning(
          "evqld",
          "metadata discovery failed: $0",
          res.body().toString());
    }
  }

  return Status(eIOError, "no metadata server has the request transaction");
}

} // namespace eventql
<commit_msg>fix log message<commit_after>/**
 * Copyright (c) 2016 zScale Technology GmbH <legal@zscale.io>
 * Authors:
 *   - Paul Asmuth <paul@zscale.io>
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License ("the license") as
 * published by the Free Software Foundation, either version 3 of the License,
 * or any later version.
 *
 * In accordance with Section 7(e) of the license, the licensing of the Program
 * under the license does not imply a trademark license. Therefore any rights,
 * title and interest in our trademarks remain entirely with us.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the license for more details.
 *
 * You can be released from the requirements of the license by purchasing a
 * commercial license. Buying such a license is mandatory as soon as you develop
 * commercial activities involving this program without disclosing the source
 * code of your own applications
 */
#include "eventql/db/metadata_coordinator.h"

namespace eventql {

MetadataCoordinator::MetadataCoordinator(ConfigDirectory* cdir) : cdir_(cdir) {}

Status MetadataCoordinator::performAndCommitOperation(
    const String& ns,
    const String& table_name,
    MetadataOperation op) {
  auto table_config = cdir_->getTableConfig(ns, table_name);
  SHA1Hash input_txid(
      table_config.metadata_txnid().data(),
      table_config.metadata_txnid().size());

  if (!(input_txid == op.getInputTransactionID())) {
    return Status(eConcurrentModificationError, "concurrent modification");
  }

  Vector<String> servers;
  for (const auto& s : table_config.metadata_servers()) {
    servers.emplace_back(s);
  }

  auto rc = performOperation(ns, table_name, op, servers);
  if (!rc.isSuccess()) {
    return rc;
  }

  auto output_txid = op.getOutputTransactionID();
  table_config.set_metadata_txnid(output_txid.data(), output_txid.size());
  table_config.set_metadata_txnseq(table_config.metadata_txnseq() + 1);
  cdir_->updateTableConfig(table_config);
  return Status::success();
}

Status MetadataCoordinator::performOperation(
    const String& ns,
    const String& table_name,
    MetadataOperation op,
    const Vector<String>& servers) {
  size_t num_servers = servers.size();
  if (num_servers == 0) {
    return Status(eIllegalArgumentError, "server list can't be empty");
  }

  size_t failures = 0;
  for (const auto& s : servers) {
    auto rc = performOperation(ns, table_name, op, s);
    if (!rc.isSuccess()) {
      logWarning(
          "evqld",
          "error while performing metadata operation: $0",
          rc.message());
      ++failures;
    }
  }

  size_t max_failures = 0;
  if (num_servers > 1) {
    max_failures = (num_servers - 1) / 2;
  }

  if (failures <= max_failures) {
    return Status::success();
  } else {
    return Status(eRuntimeError, "error while performing metadata operation");
  }
}

Status MetadataCoordinator::performOperation(
    const String& ns,
    const String& table_name,
    MetadataOperation op,
    const String& server) {
  auto server_cfg = cdir_->getServerConfig(server);
  if (server_cfg.server_addr().empty()) {
    return Status(eRuntimeError, "server is offline");
  }

  logDebug(
      "evqld",
      "Performing metadata operation on: $0/$1 ($2->$3) on $4 ($5)",
      ns,
      table_name,
      op.getInputTransactionID().toString(),
      op.getOutputTransactionID().toString(),
      server,
      server_cfg.server_addr());

  auto url = StringUtil::format(
      "http://$0/rpc/perform_metadata_operation?namespace=$1&table=$2",
      server_cfg.server_addr(),
      URI::urlEncode(ns),
      URI::urlEncode(table_name));

  Buffer req_body;
  {
    auto os = BufferOutputStream::fromBuffer(&req_body);
    auto rc = op.encode(os.get());
    if (!rc.isSuccess()) {
      return rc;
    }
  }

  auto req = http::HTTPRequest::mkPost(url, req_body);
  //auth_->signRequest(static_cast<Session*>(txn_->getUserData()), &req);

  http::HTTPClient http_client;
  http::HTTPResponse res;
  auto rc = http_client.executeRequest(req, &res);
  if (!rc.isSuccess()) {
    return rc;
  }

  if (res.statusCode() == 201) {
    return Status::success();
  } else {
    return Status(eIOError, res.body().toString());
  }
}

Status MetadataCoordinator::createFile(
    const String& ns,
    const String& table_name,
    const MetadataFile& file,
    const Vector<String>& servers) {
  size_t num_servers = servers.size();
  if (num_servers == 0) {
    return Status(eIllegalArgumentError, "server list can't be empty");
  }

  size_t failures = 0;
  for (const auto& s : servers) {
    auto rc = createFile(ns, table_name, file, s);
    if (!rc.isSuccess()) {
      logWarning("evqld", "error while creating metadata file: $0", rc.message());
      ++failures;
    }
  }

  size_t max_failures = 0;
  if (num_servers > 1) {
    max_failures = (num_servers - 1) / 2;
  }

  if (failures <= max_failures) {
    return Status::success();
  } else {
    return Status(eRuntimeError, "error while creating metadata file");
  }
}

Status MetadataCoordinator::createFile(
    const String& ns,
    const String& table_name,
    const MetadataFile& file,
    const String& server) {
  auto server_cfg = cdir_->getServerConfig(server);
  if (server_cfg.server_addr().empty()) {
    return Status(eRuntimeError, "server is offline");
  }

  logDebug(
      "evqld",
      "Creating metadata file: $0/$1/$2 on $3 ($4)",
      ns,
      table_name,
      file.getTransactionID(),
      server,
      server_cfg.server_addr());

  auto url = StringUtil::format(
      "http://$0/rpc/create_metadata_file?namespace=$1&table=$2",
      server_cfg.server_addr(),
      URI::urlEncode(ns),
      URI::urlEncode(table_name));

  Buffer req_body;
  {
    auto os = BufferOutputStream::fromBuffer(&req_body);
    auto rc = file.encode(os.get());
    if (!rc.isSuccess()) {
      return rc;
    }
  }

  auto req = http::HTTPRequest::mkPost(url, req_body);
  //auth_->signRequest(static_cast<Session*>(txn_->getUserData()), &req);

  http::HTTPClient http_client;
  http::HTTPResponse res;
  auto rc = http_client.executeRequest(req, &res);
  if (!rc.isSuccess()) {
    return rc;
  }

  if (res.statusCode() == 201) {
    return Status::success();
  } else {
    return Status(eIOError, res.body().toString());
  }
}

Status MetadataCoordinator::discoverPartition(
    PartitionDiscoveryRequest request,
    PartitionDiscoveryResponse* response) {
  auto table_cfg = cdir_->getTableConfig(
      request.db_namespace(),
      request.table_id());

  if (table_cfg.metadata_txnseq() < request.min_txnseq()) {
    return Status(eConcurrentModificationError, "concurrent modification");
  }

  request.set_requester_id(cdir_->getServerID());

  http::HTTPClient http_client;
  for (const auto& s : table_cfg.metadata_servers()) {
    auto server = cdir_->getServerConfig(s);
    if (server.server_status() != SERVER_UP) {
      continue;
    }

    auto url = StringUtil::format(
        "http://$0/rpc/discover_partition_metadata",
        server.server_addr());

    Buffer req_body;
    auto req = http::HTTPRequest::mkPost(url, *msg::encode(request));
    //auth_->signRequest(static_cast<Session*>(txn_->getUserData()), &req);

    http::HTTPResponse res;
    auto rc = http_client.executeRequest(req, &res);
    if (!rc.isSuccess()) {
      logWarning("evqld", "metadata discovery failed: $0", rc.message());
      continue;
    }

    if (res.statusCode() == 200) {
      *response = msg::decode<PartitionDiscoveryResponse>(res.body());
      return Status::success();
    } else {
      logWarning(
          "evqld",
          "metadata discovery failed: $0",
          res.body().toString());
    }
  }

  return Status(eIOError, "no metadata server has the request transaction");
}

} // namespace eventql
<|endoftext|>


<commit_before>/*
    This file is part of kdepim.

    Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>

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

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qbuttongroup.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qradiobutton.h>

#include <kaccelmanager.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <kstdguiitem.h>

#include "egroupwarewizard.h"
#include "kolabwizard.h"
#include "sloxwizard.h"

#include "overviewpage.h"

OverViewPage::OverViewPage( QWidget *parent, const char *name )
  : QWidget( parent, name )
{
  QGridLayout *layout = new QGridLayout( this, 7, 4, KDialog::marginHint(),
                                         KDialog::spacingHint() );

  QString msg = i18n( "KDE Groupware Wizard" );
  QLabel *label = new QLabel( "<qt>
" + msg + "
</qt>" , this );
  layout->addMultiCellWidget( label, 0, 0, 0, 2 );

  label = new QLabel( this );
  label->setPixmap( KGlobal::iconLoader()->loadIcon( "network", KIcon::Desktop ) );
  layout->addWidget( label, 0, 3 );

  label = new QLabel( "", this );
  layout->addWidget( label, 1, 0 );
  layout->setRowSpacing( 1, 20 );

  label = new QLabel( i18n( "Select the type of server you want connect your KDE to:" ), this );
  layout->addMultiCellWidget( label, 2, 2, 0, 3 );

  QPushButton *button = new QPushButton( i18n("eGroupware"), this );
  layout->addMultiCellWidget( button, 3, 3, 0, 3 );
  connect( button, SIGNAL( clicked() ), SLOT( showWizardEGroupware() ) );

  // FIXME: Maybe hyperlinks would be better than buttons.

  button = new QPushButton( i18n("Kolab"), this );
  layout->addMultiCellWidget( button, 4, 4, 0, 3 );
  connect( button, SIGNAL( clicked() ), SLOT( showWizardKolab() ) );

  button = new QPushButton( i18n("SLOX"), this );
  layout->addMultiCellWidget( button, 5, 5, 0, 3 );
  connect( button, SIGNAL( clicked() ), SLOT( showWizardSlox() ) );

  QFrame *frame = new QFrame( this );
  frame->setFrameStyle( QFrame::HLine | QFrame::Sunken );
  layout->addMultiCellWidget( frame, 6, 6, 0, 3 );

  QPushButton *cancelButton = new KPushButton( KStdGuiItem::cancel(), this );
  layout->addWidget( cancelButton, 8, 3 );

  connect( cancelButton, SIGNAL( clicked() ), this, SIGNAL( cancel() ) );

  layout->setRowStretch( 7, 1 );

  KAcceleratorManager::manage( this );
}

OverViewPage::~OverViewPage()
{
}

void OverViewPage::showWizardEGroupware()
{
  EGroupwareWizard wizard;
  wizard.exec();
}

void OverViewPage::showWizardKolab()
{
  KolabWizard wizard;
  wizard.exec();
}

void OverViewPage::showWizardSlox()
{
  SloxWizard wizard;
  wizard.exec();
}

#include "overviewpage.moc"
<commit_msg>The button doesn't cancel anything.<commit_after>/*
    This file is part of kdepim.

    Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>

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

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <qbuttongroup.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qradiobutton.h>

#include <kaccelmanager.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <kstdguiitem.h>

#include "egroupwarewizard.h"
#include "kolabwizard.h"
#include "sloxwizard.h"

#include "overviewpage.h"

OverViewPage::OverViewPage( QWidget *parent, const char *name )
  : QWidget( parent, name )
{
  QGridLayout *layout = new QGridLayout( this, 7, 4, KDialog::marginHint(),
                                         KDialog::spacingHint() );

  QString msg = i18n( "KDE Groupware Wizard" );
  QLabel *label = new QLabel( "<qt>
" + msg + "
</qt>" , this );
  layout->addMultiCellWidget( label, 0, 0, 0, 2 );

  label = new QLabel( this );
  label->setPixmap( KGlobal::iconLoader()->loadIcon( "network", KIcon::Desktop ) );
  layout->addWidget( label, 0, 3 );

  label = new QLabel( "", this );
  layout->addWidget( label, 1, 0 );
  layout->setRowSpacing( 1, 20 );

  label = new QLabel( i18n( "Select the type of server you want connect your KDE to:" ), this );
  layout->addMultiCellWidget( label, 2, 2, 0, 3 );

  QPushButton *button = new QPushButton( i18n("eGroupware"), this );
  layout->addMultiCellWidget( button, 3, 3, 0, 3 );
  connect( button, SIGNAL( clicked() ), SLOT( showWizardEGroupware() ) );

  // FIXME: Maybe hyperlinks would be better than buttons.

  button = new QPushButton( i18n("Kolab"), this );
  layout->addMultiCellWidget( button, 4, 4, 0, 3 );
  connect( button, SIGNAL( clicked() ), SLOT( showWizardKolab() ) );

  button = new QPushButton( i18n("SLOX"), this );
  layout->addMultiCellWidget( button, 5, 5, 0, 3 );
  connect( button, SIGNAL( clicked() ), SLOT( showWizardSlox() ) );

  QFrame *frame = new QFrame( this );
  frame->setFrameStyle( QFrame::HLine | QFrame::Sunken );
  layout->addMultiCellWidget( frame, 6, 6, 0, 3 );

  QPushButton *cancelButton = new KPushButton( KStdGuiItem::close(), this );
  layout->addWidget( cancelButton, 8, 3 );

  connect( cancelButton, SIGNAL( clicked() ), this, SIGNAL( cancel() ) );

  layout->setRowStretch( 7, 1 );

  KAcceleratorManager::manage( this );
}

OverViewPage::~OverViewPage()
{
}

void OverViewPage::showWizardEGroupware()
{
  EGroupwareWizard wizard;
  wizard.exec();
}

void OverViewPage::showWizardKolab()
{
  KolabWizard wizard;
  wizard.exec();
}

void OverViewPage::showWizardSlox()
{
  SloxWizard wizard;
  wizard.exec();
}

#include "overviewpage.moc"
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "schema.hh"
#include "database_fwd.hh"

struct schema_builder {
public:
    enum class compact_storage { no, yes };
private:
    schema::raw_schema _raw;
    std::experimental::optional<compact_storage> _compact_storage;
    std::experimental::optional<table_schema_version> _version;
    schema_builder(const schema::raw_schema&);
public:
    schema_builder(const sstring& ks_name, const sstring& cf_name,
            std::experimental::optional<utils::UUID> = { },
            data_type regular_column_name_type = utf8_type);
    schema_builder(const schema_ptr);

    void set_uuid(const utils::UUID& id) {
        _raw._id = id;
    }
    const utils::UUID& uuid() const {
        return _raw._id;
    }
    void set_regular_column_name_type(const data_type& t) {
        _raw._regular_column_name_type = t;
    }
    const data_type& regular_column_name_type() const {
        return _raw._regular_column_name_type;
    }
    const sstring& ks_name() const {
        return _raw._ks_name;
    }
    const sstring& cf_name() const {
        return _raw._cf_name;
    }
    void set_comment(const sstring& s) {
        _raw._comment = s;
    }
    const sstring& comment() const {
        return _raw._comment;
    }
    void set_default_time_to_live(gc_clock::duration t) {
        _raw._default_time_to_live = t;
    }
    gc_clock::duration default_time_to_live() const {
        return _raw._default_time_to_live;
    }

    void set_default_validator(const data_type& validator) {
        _raw._default_validator = validator;
    }

    void set_gc_grace_seconds(int32_t gc_grace_seconds) {
        _raw._gc_grace_seconds = gc_grace_seconds;
    }

    int32_t get_gc_grace_seconds() {
        return _raw._gc_grace_seconds;
    }

    void set_dc_local_read_repair_chance(double chance) {
        _raw._dc_local_read_repair_chance = chance;
    }

    double get_dc_local_read_repair_chance() {
        return _raw._dc_local_read_repair_chance;
    }

    void set_read_repair_chance(double chance) {
        _raw._read_repair_chance = chance;
    }

    double get_read_repair_chance() {
        return _raw._read_repair_chance;
    }

    void set_min_compaction_threshold(int32_t t) {
        _raw._min_compaction_threshold = t;
    }

    int32_t get_min_compaction_threshold() {
        return _raw._min_compaction_threshold;
    }

    void set_max_compaction_threshold(int32_t t) {
        _raw._max_compaction_threshold = t;
    }

    int32_t get_max_compaction_threshold() {
        return _raw._max_compaction_threshold;
    }

    void set_min_index_interval(int32_t t) {
        _raw._min_index_interval = t;
    }

    int32_t get_min_index_interval() {
        return _raw._min_index_interval;
    }

    void set_max_index_interval(int32_t t) {
        _raw._max_index_interval = t;
    }

    int32_t get_max_index_interval() {
        return _raw._max_index_interval;
    }

    void set_memtable_flush_period(int32_t t) {
        _raw._memtable_flush_period = t;
    }

    int32_t get_memtable_flush_period() const {
        return _raw._memtable_flush_period;
    }

    void set_speculative_retry(sstring retry_sstring) {
        _raw._speculative_retry = speculative_retry::from_sstring(retry_sstring);
    }

    const speculative_retry& get_speculative_retry() {
        return _raw._speculative_retry;
    }

    void set_bloom_filter_fp_chance(double fp) {
        _raw._bloom_filter_fp_chance = fp;
    }
    double get_bloom_filter_fp_chance() const {
        return _raw._bloom_filter_fp_chance;
    }
    void set_compressor_params(const compression_parameters& cp) {
        _raw._compressor_params = cp;
    }

    void set_compaction_strategy(sstables::compaction_strategy_type type) {
        _raw._compaction_strategy = type;
    }

    void set_compaction_strategy_options(std::map<sstring, sstring> options) {
        _raw._compaction_strategy_options = std::move(options);
    }

    void set_caching_options(caching_options c) {
        _raw._caching_options = std::move(c);
    }

    void set_is_dense(bool is_dense) {
        _raw._is_dense = is_dense;
    }

    void set_is_compound(bool is_compound) {
        _raw._is_compound = is_compound;
    }

    column_definition& find_column(const cql3::column_identifier&);
    schema_builder& with_column(const column_definition& c);
    schema_builder& with_column(bytes name, data_type type, column_kind kind = column_kind::regular_column);
    schema_builder& with_column(bytes name, data_type type, index_info info, column_kind kind = column_kind::regular_column);
    schema_builder& with_column(bytes name, data_type type, index_info info, column_kind kind, column_id component_index);
    schema_builder& without_column(bytes name);
    schema_builder& without_column(sstring name, api::timestamp_type timestamp);
    schema_builder& with_column_rename(bytes from, bytes to);
    schema_builder& with_altered_column_type(bytes name, data_type new_type);

    // Adds information about collection that existed in the past but the column
    // has since been removed. For adding colllections that are still alive
    // use with_column().
    schema_builder& with_collection(bytes name, data_type type);

    schema_builder& with(compact_storage);
    schema_builder& with_version(table_schema_version);

    void add_default_index_names(database&);

    // Equivalent to with(cp).build()
    schema_ptr build(compact_storage cp);

    schema_ptr build();
};
<commit_msg>schema_builder: Fluentize property setters<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "schema.hh"
#include "database_fwd.hh"

struct schema_builder {
public:
    enum class compact_storage { no, yes };
private:
    schema::raw_schema _raw;
    std::experimental::optional<compact_storage> _compact_storage;
    std::experimental::optional<table_schema_version> _version;
    schema_builder(const schema::raw_schema&);
public:
    schema_builder(const sstring& ks_name, const sstring& cf_name,
            std::experimental::optional<utils::UUID> = { },
            data_type regular_column_name_type = utf8_type);
    schema_builder(const schema_ptr);

    schema_builder& set_uuid(const utils::UUID& id) {
        _raw._id = id;
        return *this;
    }
    const utils::UUID& uuid() const {
        return _raw._id;
    }
    schema_builder& set_regular_column_name_type(const data_type& t) {
        _raw._regular_column_name_type = t;
        return *this;
    }
    const data_type& regular_column_name_type() const {
        return _raw._regular_column_name_type;
    }
    const sstring& ks_name() const {
        return _raw._ks_name;
    }
    const sstring& cf_name() const {
        return _raw._cf_name;
    }
    schema_builder& set_comment(const sstring& s) {
        _raw._comment = s;
        return *this;
    }
    const sstring& comment() const {
        return _raw._comment;
    }
    schema_builder& set_default_time_to_live(gc_clock::duration t) {
        _raw._default_time_to_live = t;
        return *this;
    }
    gc_clock::duration default_time_to_live() const {
        return _raw._default_time_to_live;
    }

    schema_builder& set_default_validator(const data_type& validator) {
        _raw._default_validator = validator;
        return *this;
    }

    schema_builder& set_gc_grace_seconds(int32_t gc_grace_seconds) {
        _raw._gc_grace_seconds = gc_grace_seconds;
        return *this;
    }

    int32_t get_gc_grace_seconds() {
        return _raw._gc_grace_seconds;
    }

    schema_builder& set_dc_local_read_repair_chance(double chance) {
        _raw._dc_local_read_repair_chance = chance;
        return *this;
    }

    double get_dc_local_read_repair_chance() {
        return _raw._dc_local_read_repair_chance;
    }

    schema_builder& set_read_repair_chance(double chance) {
        _raw._read_repair_chance = chance;
        return *this;
    }

    double get_read_repair_chance() {
        return _raw._read_repair_chance;
    }

    schema_builder& set_min_compaction_threshold(int32_t t) {
        _raw._min_compaction_threshold = t;
        return *this;
    }

    int32_t get_min_compaction_threshold() {
        return _raw._min_compaction_threshold;
    }

    schema_builder& set_max_compaction_threshold(int32_t t) {
        _raw._max_compaction_threshold = t;
        return *this;
    }

    int32_t get_max_compaction_threshold() {
        return _raw._max_compaction_threshold;
    }

    schema_builder& set_min_index_interval(int32_t t) {
        _raw._min_index_interval = t;
        return *this;
    }

    int32_t get_min_index_interval() {
        return _raw._min_index_interval;
    }

    schema_builder& set_max_index_interval(int32_t t) {
        _raw._max_index_interval = t;
        return *this;
    }

    int32_t get_max_index_interval() {
        return _raw._max_index_interval;
    }

    schema_builder& set_memtable_flush_period(int32_t t) {
        _raw._memtable_flush_period = t;
        return *this;
    }

    int32_t get_memtable_flush_period() const {
        return _raw._memtable_flush_period;
    }

    schema_builder& set_speculative_retry(sstring retry_sstring) {
        _raw._speculative_retry = speculative_retry::from_sstring(retry_sstring);
        return *this;
    }

    const speculative_retry& get_speculative_retry() {
        return _raw._speculative_retry;
    }

    schema_builder& set_bloom_filter_fp_chance(double fp) {
        _raw._bloom_filter_fp_chance = fp;
        return *this;
    }
    double get_bloom_filter_fp_chance() const {
        return _raw._bloom_filter_fp_chance;
    }
    schema_builder& set_compressor_params(const compression_parameters& cp) {
        _raw._compressor_params = cp;
        return *this;
    }

    schema_builder& set_compaction_strategy(sstables::compaction_strategy_type type) {
        _raw._compaction_strategy = type;
        return *this;
    }

    schema_builder& set_compaction_strategy_options(std::map<sstring, sstring> options) {
        _raw._compaction_strategy_options = std::move(options);
        return *this;
    }

    schema_builder& set_caching_options(caching_options c) {
        _raw._caching_options = std::move(c);
        return *this;
    }

    schema_builder& set_is_dense(bool is_dense) {
        _raw._is_dense = is_dense;
        return *this;
    }

    schema_builder& set_is_compound(bool is_compound) {
        _raw._is_compound = is_compound;
        return *this;
    }

    column_definition& find_column(const cql3::column_identifier&);
    schema_builder& with_column(const column_definition& c);
    schema_builder& with_column(bytes name, data_type type, column_kind kind = column_kind::regular_column);
    schema_builder& with_column(bytes name, data_type type, index_info info, column_kind kind = column_kind::regular_column);
    schema_builder& with_column(bytes name, data_type type, index_info info, column_kind kind, column_id component_index);
    schema_builder& without_column(bytes name);
    schema_builder& without_column(sstring name, api::timestamp_type timestamp);
    schema_builder& with_column_rename(bytes from, bytes to);
    schema_builder& with_altered_column_type(bytes name, data_type new_type);

    // Adds information about collection that existed in the past but the column
    // has since been removed. For adding colllections that are still alive
    // use with_column().
    schema_builder& with_collection(bytes name, data_type type);

    schema_builder& with(compact_storage);
    schema_builder& with_version(table_schema_version);

    void add_default_index_names(database&);

    // Equivalent to with(cp).build()
    schema_ptr build(compact_storage cp);

    schema_ptr build();
};
<|endoftext|>


<commit_before>#include <cstdint>
#include <memory>
#include <string>
#include <algorithm>

#include "Buffer.h"
#include "StringRef.h"
#include "Diagnostics.h"

namespace slang {

const static StringRef diagnosticDescriptors[] = {
	// lexer
	"NonPrintableChar"
	"UTF8Char",
	"UnicodeBOM",
	"EmbeddedNull",
	"MisplacedDirectiveChar",
	"EscapedWhitespace",
	"NewlineInStringLiteral",
	"UnterminatedStringLiteral",
	"UnterminatedBlockComment",
	"NestedBlockComment",
	"SplitBlockCommentInDirective",
	"MissingExponentDigits",
	"MissingFractionalDigits",
	"OctalEscapeCodeTooBig",
	"InvalidHexEscapeCode",
	"UnknownEscapeCode",
	"RealExponentTooLarge",
	"SignedLiteralTooLarge",
	"IntegerSizeZero",
	"IntegerSizeTooLarge",
	"MissingVectorBase",
	"MissingVectorDigits",
	"ExpectedEndOfIncludeFileName",
	"ExpectedIncludeFileName",

	// preprocessor
	"CouldNotOpenIncludeFile",
	"ExceededMaxIncludeDepth",
	"UnknownDirective",
	"ExpectedEndOfDirective",
	"ExpectedEndOfMacroArgs",
	"ExpectedEndIfDirective",
	"UnexpectedDirective",
	"UnbalancedMacroArgDims",
	"ExpectedMacroArgs",

	// parser
	"SyntaxError",
	"ImplicitNotAllowed",
	"MultipleTypesInDeclaration",
	"DirectionOnInterfacePort",
	"ColonShouldBeDot"
};

Diagnostics::Diagnostics() :
	Buffer::Buffer(128)
{
}

DiagnosticReport Diagnostics::getReport(const Diagnostic& diagnostic) const {
	return DiagnosticReport(diagnostic, diagnosticDescriptors[(int)diagnostic.code]);
}

std::string DiagnosticReport::toString() const {
	return format.toString();
}

std::ostream& operator<<(std::ostream& os, DiagCode code) {
#define CASE(name) case DiagCode::name: os << #name; break
	switch (code) {
		CASE(NonPrintableChar);
		CASE(UTF8Char);
		CASE(UnicodeBOM);
		CASE(EmbeddedNull);
		CASE(MisplacedDirectiveChar);
		CASE(EscapedWhitespace);
		CASE(NewlineInStringLiteral);
		CASE(UnterminatedStringLiteral);
		CASE(UnterminatedBlockComment);
		CASE(NestedBlockComment);
		CASE(SplitBlockCommentInDirective);
		CASE(MissingExponentDigits);
		CASE(MissingFractionalDigits);
		CASE(OctalEscapeCodeTooBig);
		CASE(InvalidHexEscapeCode);
		CASE(UnknownEscapeCode);
		CASE(RealExponentTooLarge);
		CASE(SignedLiteralTooLarge);
		CASE(IntegerSizeZero);
		CASE(IntegerSizeTooLarge);
		CASE(MissingVectorBase);
		CASE(MissingVectorDigits);
		CASE(ExpectedEndOfIncludeFileName);
		CASE(ExpectedIncludeFileName);
		CASE(CouldNotOpenIncludeFile);
		CASE(ExceededMaxIncludeDepth);
		CASE(UnknownDirective);
		CASE(ExpectedEndOfDirective);
		CASE(ExpectedEndOfMacroArgs);
		CASE(ExpectedEndIfDirective);
		CASE(UnexpectedDirective);
		CASE(UnbalancedMacroArgDims);
		CASE(ExpectedMacroArgs);
		CASE(SyntaxError);
		CASE(ImplicitNotAllowed);
		CASE(MultipleTypesInDeclaration);
		CASE(DirectionOnInterfacePort);
		CASE(ColonShouldBeDot);
		default: ASSERT(false && "Missing case");
	}
	return os;
#undef CASE
}

}<commit_msg>Fix typo<commit_after>#include <cstdint>
#include <memory>
#include <string>
#include <algorithm>

#include "Buffer.h"
#include "StringRef.h"
#include "Diagnostics.h"

namespace slang {

const static StringRef diagnosticDescriptors[] = {
	// lexer
	"NonPrintableChar",
	"UTF8Char",
	"UnicodeBOM",
	"EmbeddedNull",
	"MisplacedDirectiveChar",
	"EscapedWhitespace",
	"NewlineInStringLiteral",
	"UnterminatedStringLiteral",
	"UnterminatedBlockComment",
	"NestedBlockComment",
	"SplitBlockCommentInDirective",
	"MissingExponentDigits",
	"MissingFractionalDigits",
	"OctalEscapeCodeTooBig",
	"InvalidHexEscapeCode",
	"UnknownEscapeCode",
	"RealExponentTooLarge",
	"SignedLiteralTooLarge",
	"IntegerSizeZero",
	"IntegerSizeTooLarge",
	"MissingVectorBase",
	"MissingVectorDigits",
	"ExpectedEndOfIncludeFileName",
	"ExpectedIncludeFileName",

	// preprocessor
	"CouldNotOpenIncludeFile",
	"ExceededMaxIncludeDepth",
	"UnknownDirective",
	"ExpectedEndOfDirective",
	"ExpectedEndOfMacroArgs",
	"ExpectedEndIfDirective",
	"UnexpectedDirective",
	"UnbalancedMacroArgDims",
	"ExpectedMacroArgs",

	// parser
	"SyntaxError",
	"ImplicitNotAllowed",
	"MultipleTypesInDeclaration",
	"DirectionOnInterfacePort",
	"ColonShouldBeDot"
};

Diagnostics::Diagnostics() :
	Buffer::Buffer(128)
{
}

DiagnosticReport Diagnostics::getReport(const Diagnostic& diagnostic) const {
	return DiagnosticReport(diagnostic, diagnosticDescriptors[(int)diagnostic.code]);
}

std::string DiagnosticReport::toString() const {
	return format.toString();
}

std::ostream& operator<<(std::ostream& os, DiagCode code) {
#define CASE(name) case DiagCode::name: os << #name; break
	switch (code) {
		CASE(NonPrintableChar);
		CASE(UTF8Char);
		CASE(UnicodeBOM);
		CASE(EmbeddedNull);
		CASE(MisplacedDirectiveChar);
		CASE(EscapedWhitespace);
		CASE(NewlineInStringLiteral);
		CASE(UnterminatedStringLiteral);
		CASE(UnterminatedBlockComment);
		CASE(NestedBlockComment);
		CASE(SplitBlockCommentInDirective);
		CASE(MissingExponentDigits);
		CASE(MissingFractionalDigits);
		CASE(OctalEscapeCodeTooBig);
		CASE(InvalidHexEscapeCode);
		CASE(UnknownEscapeCode);
		CASE(RealExponentTooLarge);
		CASE(SignedLiteralTooLarge);
		CASE(IntegerSizeZero);
		CASE(IntegerSizeTooLarge);
		CASE(MissingVectorBase);
		CASE(MissingVectorDigits);
		CASE(ExpectedEndOfIncludeFileName);
		CASE(ExpectedIncludeFileName);
		CASE(CouldNotOpenIncludeFile);
		CASE(ExceededMaxIncludeDepth);
		CASE(UnknownDirective);
		CASE(ExpectedEndOfDirective);
		CASE(ExpectedEndOfMacroArgs);
		CASE(ExpectedEndIfDirective);
		CASE(UnexpectedDirective);
		CASE(UnbalancedMacroArgDims);
		CASE(ExpectedMacroArgs);
		CASE(SyntaxError);
		CASE(ImplicitNotAllowed);
		CASE(MultipleTypesInDeclaration);
		CASE(DirectionOnInterfacePort);
		CASE(ColonShouldBeDot);
		default: ASSERT(false && "Missing case");
	}
	return os;
#undef CASE
}

}<|endoftext|>


<commit_before>// $Id: system.C,v 1.9 2000/05/09 16:21:42 amoll Exp $

#include <BALL/KERNEL/system.h>

#include <BALL/KERNEL/global.h>
#include <BALL/KERNEL/molecule.h>
#include <BALL/KERNEL/fragment.h>
#include <BALL/KERNEL/protein.h>

using namespace std;

namespace BALL
{

	System::System()
		:	BaseFragment()
	{
	}

	System::System(const System& system,bool deep)
	{
		set(system, deep);
	}

	System::System(const String& name)
		:	BaseFragment(name)
	{
	}

  void System::persistentWrite(PersistenceManager& pm, const char* name) const
  {
    pm.writeObjectHeader(this, name);
      BaseFragment::persistentWrite(pm);
    pm.writeObjectTrailer(name);
	}

  void System::persistentRead(PersistenceManager& pm)
  {
    pm.checkObjectHeader(RTTI::getStreamName<BaseFragment>());
			Composite::persistentRead(pm);
    pm.checkObjectTrailer(0);
	}

	System::~System()
	{
		destroy();
	}

	void System::set(const System& system, bool deep)
	{
		BaseFragment::set(system, deep);
	}

	System& System::operator = (const System& system)
	{
		BaseFragment::set(system);

		return *this;
	}

	void System::get(System& system, bool deep) const
	{
		system.set(*this, deep);
	}

	Molecule *System::getMolecule(Position position)
	{
		for (MoleculeIterator res_it = beginMolecule(); !res_it.isEnd(); ++res_it)
			if (position-- == 0)
				return &(*res_it);

		return 0;
	}

	const Molecule *System::getMolecule(Position position) const
	{
		return ((System *)this)->getMolecule(position);
	}

	Size System::countMolecules() const
	{
		Size size = 0;

		for (MoleculeIterator mol_it = beginMolecule(); !mol_it.isEnd(); ++mol_it)
		{
			++size;
		}

		return size;
	}

	Size  System::countFragments() const
	{
		Size size = 0;

		for (FragmentIterator frag_it = beginFragment(); !frag_it.isEnd(); ++frag_it)
		{
			++size;
		}

		return size;
	}

	Size System::countAtoms() const
	{
		Size size = 0;

		for (AtomIterator atom_it = beginAtom(); !atom_it.isEnd(); ++atom_it)
		{
			++size;
		}

		return size;
	}

	void System::prepend(Molecule& molecule)
	{
		Composite::prependChild(molecule);
	}

	void System::append(Molecule& molecule)
	{
		Composite::appendChild(molecule);
	}

	void System::insert(Molecule& molecule)
	{
		append(molecule);
	}

	void System::insertBefore(Molecule& molecule, Composite& before)
	{
		before.Composite::insertBefore(molecule);
	}

	void System::insertAfter(Molecule& molecule, Composite& after)
	{
		after.Composite::insertAfter(molecule);
	}

	bool System::remove(Molecule& molecule)
	{
		return Composite::removeChild(molecule);
	}

	void System::spliceBefore(System& system)
	{
		Composite::spliceBefore(system);
	}

	void System::spliceAfter(System& system)
	{
		Composite::spliceAfter(system);
	}

	void System::splice(System& system)
	{
		Composite::splice(system);
	}

	void System::destroyBonds()
	{
		for (AtomIterator atom_it = beginAtom(); !atom_it.isEnd(); ++atom_it)
		{
			atom_it->destroyBonds();
		}
	}

	void System::read(istream& /* s */)
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}

	void System::write(ostream& /* s */) const
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}
} // namespace BALL
<commit_msg>added:countResidues()<commit_after>// $Id: system.C,v 1.10 2000/05/15 21:18:04 amoll Exp $

#include <BALL/KERNEL/system.h>

#include <BALL/KERNEL/global.h>
#include <BALL/KERNEL/molecule.h>
#include <BALL/KERNEL/fragment.h>
#include <BALL/KERNEL/protein.h>

using namespace std;

namespace BALL
{

	System::System()
		:	BaseFragment()
	{
	}

	System::System(const System& system,bool deep)
	{
		set(system, deep);
	}

	System::System(const String& name)
		:	BaseFragment(name)
	{
	}

  void System::persistentWrite(PersistenceManager& pm, const char* name) const
  {
    pm.writeObjectHeader(this, name);
      BaseFragment::persistentWrite(pm);
    pm.writeObjectTrailer(name);
	}

  void System::persistentRead(PersistenceManager& pm)
  {
    pm.checkObjectHeader(RTTI::getStreamName<BaseFragment>());
			Composite::persistentRead(pm);
    pm.checkObjectTrailer(0);
	}

	System::~System()
	{
		destroy();
	}

	void System::set(const System& system, bool deep)
	{
		BaseFragment::set(system, deep);
	}

	System& System::operator = (const System& system)
	{
		BaseFragment::set(system);

		return *this;
	}

	void System::get(System& system, bool deep) const
	{
		system.set(*this, deep);
	}

	Molecule *System::getMolecule(Position position)
	{
		for (MoleculeIterator res_it = beginMolecule(); !res_it.isEnd(); ++res_it)
			if (position-- == 0)
				return &(*res_it);

		return 0;
	}

	const Molecule *System::getMolecule(Position position) const
	{
		return ((System *)this)->getMolecule(position);
	}

	Size System::countMolecules() const
	{
		Size size = 0;

		for (MoleculeIterator mol_it = beginMolecule(); !mol_it.isEnd(); ++mol_it)
		{
			++size;
		}

		return size;
	}

	Size  System::countFragments() const
	{
		Size size = 0;

		for (FragmentIterator frag_it = beginFragment(); !frag_it.isEnd(); ++frag_it)
		{
			++size;
		}

		return size;
	}

	Size  System::countResidues() const
	{
		Size size = 0;

		for (ResidueIterator frag_it = beginResidue(); !frag_it.isEnd(); ++frag_it)
		{
			++size;
		}

		return size;
	}

	Size System::countAtoms() const
	{
		Size size = 0;

		for (AtomIterator atom_it = beginAtom(); !atom_it.isEnd(); ++atom_it)
		{
			++size;
		}

		return size;
	}

	void System::prepend(Molecule& molecule)
	{
		Composite::prependChild(molecule);
	}

	void System::append(Molecule& molecule)
	{
		Composite::appendChild(molecule);
	}

	void System::insert(Molecule& molecule)
	{
		append(molecule);
	}

	void System::insertBefore(Molecule& molecule, Composite& before)
	{
		before.Composite::insertBefore(molecule);
	}

	void System::insertAfter(Molecule& molecule, Composite& after)
	{
		after.Composite::insertAfter(molecule);
	}

	bool System::remove(Molecule& molecule)
	{
		return Composite::removeChild(molecule);
	}

	void System::spliceBefore(System& system)
	{
		Composite::spliceBefore(system);
	}

	void System::spliceAfter(System& system)
	{
		Composite::spliceAfter(system);
	}

	void System::splice(System& system)
	{
		Composite::splice(system);
	}

	void System::destroyBonds()
	{
		for (AtomIterator atom_it = beginAtom(); !atom_it.isEnd(); ++atom_it)
		{
			atom_it->destroyBonds();
		}
	}

	void System::read(istream& /* s */)
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}

	void System::write(ostream& /* s */) const
	{
		throw Exception::NotImplemented(__FILE__, __LINE__);
	}
} // namespace BALL
<|endoftext|>


<commit_before>#include "States/Play.hpp"

#include "Core/Game.hpp"
#include "Core/Metadata.hpp"
#include "Driver/Font.hpp"
#include "Driver/Platform.hpp"
#include "Driver/Player.hpp"
#include "Factories/Level.hpp"
#include "States/Over.hpp"
#include "States/Quit.hpp"
#include "States/Transition.hpp"
#include "States/Win.hpp"

#include <cmath>

namespace SuperHaxagon {

	Play::Play(Game& game, LevelFactory& factory, LevelFactory& selected, const float startScore) :
		_game(game),
		_platform(game.getPlatform()),
		_factory(factory),
		_selected(selected),
		_level(factory.instantiate(game.getTwister(), SCALE_BASE_DISTANCE)),
		_score(startScore)
	{}

	Play::~Play() = default;

	void Play::enter() {
		auto* bgm = _platform.getBGM();
		if (bgm) bgm->play();
		_platform.playSFX(_game.getSFXBegin());
		_game.setShadowAuto(true);
	}

	void Play::exit() {
		auto* bgm = _platform.getBGM();
		if (bgm) bgm->pause();
	}

	std::unique_ptr<State> Play::update(const float dilation) {
		const auto maxRenderDistance = SCALE_BASE_DISTANCE * (_game.getScreenDimMax() / 400);

		// Render the level with a skewed 3D look
		auto skewFrameMax = static_cast<float>(_level->getLevelFactory().getSpeedPulse()) * 2.5f;
		skewFrameMax = skewFrameMax < SKEW_MIN_FRAMES ? SKEW_MIN_FRAMES : skewFrameMax;
		_skewFrame += dilation * _skewDirection * (_level->getLevelFactory().getSpeedRotation() > 0 ? 1.0f : 0);
		_game.setSkew((-cos(_skewFrame / skewFrameMax * PI) + 1.0f) / 2.0f * SKEW_MAX);

		// It's technically possible that the BGM metadata was not set
		if (_game.getBGMMetadata()) {

			// Get effect data
			auto& metadata = *_game.getBGMMetadata();
			const auto* bgm = _platform.getBGM();
			const auto time = bgm ? bgm->getTime() : 0.0f;

			// Apply effects. More can be added here if needed.
			if (metadata.getMetadata(time, "S")) _level->spin();
			if (metadata.getMetadata(time, "I")) _level->invertBG();
			if (metadata.getMetadata(time, "BL")) _level->pulse(1.0f);
			if (metadata.getMetadata(time, "BS")) _level->pulse(0.5f);
		}

		// Update level
		const auto previousFrame = _level->getFrame();
		_level->update(_game.getTwister(), SCALE_HEX_LENGTH, maxRenderDistance, dilation);

		// Button presses
		const auto pressed = _platform.getPressed();

		// Check collision
		const auto cursorDistance = SCALE_HEX_LENGTH + SCALE_HUMAN_PADDING + SCALE_HUMAN_HEIGHT;
		const auto hit = _level->collision(cursorDistance, dilation);

		// Keys
		if(pressed.back || hit == Movement::DEAD) {
			if (&_factory != &_selected &&
			    _factory.getCreator() == "REDHAT" &&
			    _factory.getName() == "VOID" &&
			    _factory.getDifficulty() == "???" &&
			    _factory.getMode() == "???") {
				// Play the super special win animation if you are on the last level without selecting it
				// Congrats, you just won the game!
				return std::make_unique<Win>(_game, std::move(_level), _selected, _score, "WONDERFUL");
			}

			if (_factory.getCreator() == "REDHAT" &&
			    _factory.getName() == "CREDITS" &&
			    _factory.getDifficulty() == "SPOILERS" &&
			    _factory.getMode() == "(DUH)") {
				// Cheater
				return std::make_unique<Win>(_game, std::move(_level), _selected, 0.0f, "CHEATER");
			}

			return std::make_unique<Over>(_game, std::move(_level), _selected, _score, "GAME OVER");
		}

		if (pressed.quit) {
			return std::make_unique<Quit>(_game);
		}

		// Go to the next level
		const auto next = _factory.getNextIndex();
		if (next >= 0 &&
		    static_cast<size_t>(next) < _game.getLevels().size() &&
		    _level->getFrame() > 60.0f * _level->getLevelFactory().getNextTime()) {
			return std::make_unique<Transition>(_game, std::move(_level), _selected, _score);
		}

		// Process movement
		if (pressed.left && hit != Movement::CANNOT_MOVE_LEFT) {
			_level->left(dilation);
		} else if (pressed.right && hit != Movement::CANNOT_MOVE_RIGHT) {
			_level->right(dilation);
		}

		// Make sure the cursor doesn't extend too far
		_level->clamp();

		// Update score
		_score += dilation;

		const auto* lastScoreText = getScoreText(static_cast<int>(previousFrame), false);
		if (lastScoreText != getScoreText(static_cast<int>(_level->getFrame()), false)) {
			_level->increaseMultiplier();
			_platform.playSFX(_game.getSFXLevelUp());
		}

		return nullptr;
	}

	void Play::drawTop(const float scale) {
		_level->draw(_game, scale, 0);
	}

	void Play::drawBot(const float scale) {
		auto& small = _game.getFontSmall();

		// Makes it so the score text doesn't freak out
		// if getWidth returns slightly different values
		// each frame
		if (_scalePrev != scale) {
			_scalePrev = scale;
			small.setScale(scale);
			_scoreWidth = small.getWidth("TIME: " + getTime(0));
		}

		const auto pad = 3 * scale;

		small.setScale(scale);

		// Draw the top left POINT/LINE thing
		// Note, 400 is kind of arbitrary. Perhaps it's needed to update this later.
		const auto* levelUp = getScoreText(static_cast<int>(_level->getFrame()), _platform.getScreenDim().x <= 400);
		const Point levelUpPosText = {pad, pad};
		const Point levelUpBkgSize = {
			small.getWidth(levelUp) + pad * 2,
			small.getHeight() + pad * 2
		};

		// Clockwise, from top left
		const std::vector<Point> levelUpBkg = {
			{0, 0},
			{levelUpBkgSize.x + levelUpBkgSize.y / 2, 0},
			{levelUpBkgSize.x, levelUpBkgSize.y},
			{0, levelUpBkgSize.y},
		};

		_platform.drawPoly(COLOR_TRANSPARENT, levelUpBkg);
		small.draw(COLOR_WHITE, levelUpPosText, Alignment::LEFT, levelUp);

		// Draw the current score
		const auto screenWidth = _platform.getScreenDim().x;
		const auto textScore = "TIME: " + getTime(_platform.getBGM()->getTime() * 60.0f);
		const Point scorePosText = {screenWidth - pad - _scoreWidth, pad};
		Point scoreBkgSize = {_scoreWidth + pad * 2, small.getHeight() + pad * 2};

		// Before we draw the score, compute the best time graph.
		auto drawBar = false;
		auto drawHigh = false;
		const auto originalY = scoreBkgSize.y;
		const auto heightBar = 2 * scale;
		const auto highScore = static_cast<float>(_selected.getHighScore());

		// Adjust background size to accommodate for new record or bar
		if (highScore > 0) {
			if (_score < highScore) {
				scoreBkgSize.y += heightBar + pad;
				drawBar = true;
			} else {
				scoreBkgSize.y += small.getHeight() + pad;
				drawHigh = true;
			}
		}

		// Clockwise, from top left
		const std::vector<Point> scoreBkg = {
			{screenWidth - scoreBkgSize.x - scoreBkgSize.y / 2, 0},
			{screenWidth, 0},
			{screenWidth, scoreBkgSize.y},
			{screenWidth - scoreBkgSize.x, scoreBkgSize.y}
		};

		_platform.drawPoly(COLOR_TRANSPARENT, scoreBkg);
		small.draw(COLOR_WHITE, scorePosText, Alignment::LEFT, textScore);

		if (drawBar) {
			const Point barPos = {scorePosText.x, originalY};
			const Point barWidth = {_scoreWidth, heightBar};
			const Point barWidthScore = {_scoreWidth * (_score / highScore), heightBar};
			_game.drawRect(COLOR_BLACK, barPos, barWidth);
			_game.drawRect(COLOR_WHITE, barPos, barWidthScore);
		}

		if (drawHigh) {
			auto textColor = COLOR_WHITE;
			const Point posBest = {screenWidth - pad, originalY};
			if (_score - highScore <= PULSE_TIMES * PULSE_TIME) {
				const auto percent = getPulse(_score, PULSE_TIME, highScore);
				textColor = interpolateColor(PULSE_LOW, PULSE_HIGH, percent);
			}

			small.draw(textColor, posBest, Alignment::RIGHT, "NEW RECORD!");
		}
	}
}
<commit_msg>Revert play<commit_after>#include "States/Play.hpp"

#include "Core/Game.hpp"
#include "Core/Metadata.hpp"
#include "Driver/Font.hpp"
#include "Driver/Platform.hpp"
#include "Driver/Player.hpp"
#include "Factories/Level.hpp"
#include "States/Over.hpp"
#include "States/Quit.hpp"
#include "States/Transition.hpp"
#include "States/Win.hpp"

#include <cmath>

namespace SuperHaxagon {

	Play::Play(Game& game, LevelFactory& factory, LevelFactory& selected, const float startScore) :
		_game(game),
		_platform(game.getPlatform()),
		_factory(factory),
		_selected(selected),
		_level(factory.instantiate(game.getTwister(), SCALE_BASE_DISTANCE)),
		_score(startScore)
	{}

	Play::~Play() = default;

	void Play::enter() {
		auto* bgm = _platform.getBGM();
		if (bgm) bgm->play();
		_platform.playSFX(_game.getSFXBegin());
		_game.setShadowAuto(true);
	}

	void Play::exit() {
		auto* bgm = _platform.getBGM();
		if (bgm) bgm->pause();
	}

	std::unique_ptr<State> Play::update(const float dilation) {
		const auto maxRenderDistance = SCALE_BASE_DISTANCE * (_game.getScreenDimMax() / 400);

		// Render the level with a skewed 3D look
		auto skewFrameMax = static_cast<float>(_level->getLevelFactory().getSpeedPulse()) * 2.5f;
		skewFrameMax = skewFrameMax < SKEW_MIN_FRAMES ? SKEW_MIN_FRAMES : skewFrameMax;
		_skewFrame += dilation * _skewDirection * (_level->getLevelFactory().getSpeedRotation() > 0 ? 1.0f : 0);
		_game.setSkew((-cos(_skewFrame / skewFrameMax * PI) + 1.0f) / 2.0f * SKEW_MAX);

		// It's technically possible that the BGM metadata was not set
		if (_game.getBGMMetadata()) {

			// Get effect data
			auto& metadata = *_game.getBGMMetadata();
			const auto* bgm = _platform.getBGM();
			const auto time = bgm ? bgm->getTime() : 0.0f;

			// Apply effects. More can be added here if needed.
			if (metadata.getMetadata(time, "S")) _level->spin();
			if (metadata.getMetadata(time, "I")) _level->invertBG();
			if (metadata.getMetadata(time, "BL")) _level->pulse(1.0f);
			if (metadata.getMetadata(time, "BS")) _level->pulse(0.5f);
		}

		// Update level
		const auto previousFrame = _level->getFrame();
		_level->update(_game.getTwister(), SCALE_HEX_LENGTH, maxRenderDistance, dilation);

		// Button presses
		const auto pressed = _platform.getPressed();

		// Check collision
		const auto cursorDistance = SCALE_HEX_LENGTH + SCALE_HUMAN_PADDING + SCALE_HUMAN_HEIGHT;
		const auto hit = _level->collision(cursorDistance, dilation);

		// Keys
		if(pressed.back || hit == Movement::DEAD) {
			if (&_factory != &_selected &&
			    _factory.getCreator() == "REDHAT" &&
			    _factory.getName() == "VOID" &&
			    _factory.getDifficulty() == "???" &&
			    _factory.getMode() == "???") {
				// Play the super special win animation if you are on the last level without selecting it
				// Congrats, you just won the game!
				return std::make_unique<Win>(_game, std::move(_level), _selected, _score, "WONDERFUL");
			}

			if (_factory.getCreator() == "REDHAT" &&
			    _factory.getName() == "CREDITS" &&
			    _factory.getDifficulty() == "SPOILERS" &&
			    _factory.getMode() == "(DUH)") {
				// Cheater
				return std::make_unique<Win>(_game, std::move(_level), _selected, 0.0f, "CHEATER");
			}

			return std::make_unique<Over>(_game, std::move(_level), _selected, _score, "GAME OVER");
		}

		if (pressed.quit) {
			return std::make_unique<Quit>(_game);
		}

		// Go to the next level
		const auto next = _factory.getNextIndex();
		if (next >= 0 &&
		    static_cast<size_t>(next) < _game.getLevels().size() &&
		    _level->getFrame() > 60.0f * _level->getLevelFactory().getNextTime()) {
			return std::make_unique<Transition>(_game, std::move(_level), _selected, _score);
		}

		// Process movement
		if (pressed.left && hit != Movement::CANNOT_MOVE_LEFT) {
			_level->left(dilation);
		} else if (pressed.right && hit != Movement::CANNOT_MOVE_RIGHT) {
			_level->right(dilation);
		}

		// Make sure the cursor doesn't extend too far
		_level->clamp();

		// Update score
		_score += dilation;

		const auto* lastScoreText = getScoreText(static_cast<int>(previousFrame), false);
		if (lastScoreText != getScoreText(static_cast<int>(_level->getFrame()), false)) {
			_level->increaseMultiplier();
			_platform.playSFX(_game.getSFXLevelUp());
		}

		return nullptr;
	}

	void Play::drawTop(const float scale) {
		_level->draw(_game, scale, 0);
	}

	void Play::drawBot(const float scale) {
		auto& small = _game.getFontSmall();

		// Makes it so the score text doesn't freak out
		// if getWidth returns slightly different values
		// each frame
		if (_scalePrev != scale) {
			_scalePrev = scale;
			small.setScale(scale);
			_scoreWidth = small.getWidth("TIME: " + getTime(0));
		}

		const auto pad = 3 * scale;

		small.setScale(scale);

		// Draw the top left POINT/LINE thing
		// Note, 400 is kind of arbitrary. Perhaps it's needed to update this later.
		const auto* levelUp = getScoreText(static_cast<int>(_level->getFrame()), _platform.getScreenDim().x <= 400);
		const Point levelUpPosText = {pad, pad};
		const Point levelUpBkgSize = {
			small.getWidth(levelUp) + pad * 2,
			small.getHeight() + pad * 2
		};

		// Clockwise, from top left
		const std::vector<Point> levelUpBkg = {
			{0, 0},
			{levelUpBkgSize.x + levelUpBkgSize.y / 2, 0},
			{levelUpBkgSize.x, levelUpBkgSize.y},
			{0, levelUpBkgSize.y},
		};

		_platform.drawPoly(COLOR_TRANSPARENT, levelUpBkg);
		small.draw(COLOR_WHITE, levelUpPosText, Alignment::LEFT, levelUp);

		// Draw the current score
		const auto screenWidth = _platform.getScreenDim().x;
		const auto textScore = "TIME: " + getTime(_score);
		const Point scorePosText = {screenWidth - pad - _scoreWidth, pad};
		Point scoreBkgSize = {_scoreWidth + pad * 2, small.getHeight() + pad * 2};

		// Before we draw the score, compute the best time graph.
		auto drawBar = false;
		auto drawHigh = false;
		const auto originalY = scoreBkgSize.y;
		const auto heightBar = 2 * scale;
		const auto highScore = static_cast<float>(_selected.getHighScore());

		// Adjust background size to accommodate for new record or bar
		if (highScore > 0) {
			if (_score < highScore) {
				scoreBkgSize.y += heightBar + pad;
				drawBar = true;
			} else {
				scoreBkgSize.y += small.getHeight() + pad;
				drawHigh = true;
			}
		}

		// Clockwise, from top left
		const std::vector<Point> scoreBkg = {
			{screenWidth - scoreBkgSize.x - scoreBkgSize.y / 2, 0},
			{screenWidth, 0},
			{screenWidth, scoreBkgSize.y},
			{screenWidth - scoreBkgSize.x, scoreBkgSize.y}
		};

		_platform.drawPoly(COLOR_TRANSPARENT, scoreBkg);
		small.draw(COLOR_WHITE, scorePosText, Alignment::LEFT, textScore);

		if (drawBar) {
			const Point barPos = {scorePosText.x, originalY};
			const Point barWidth = {_scoreWidth, heightBar};
			const Point barWidthScore = {_scoreWidth * (_score / highScore), heightBar};
			_game.drawRect(COLOR_BLACK, barPos, barWidth);
			_game.drawRect(COLOR_WHITE, barPos, barWidthScore);
		}

		if (drawHigh) {
			auto textColor = COLOR_WHITE;
			const Point posBest = {screenWidth - pad, originalY};
			if (_score - highScore <= PULSE_TIMES * PULSE_TIME) {
				const auto percent = getPulse(_score, PULSE_TIME, highScore);
				textColor = interpolateColor(PULSE_LOW, PULSE_HIGH, percent);
			}

			small.draw(textColor, posBest, Alignment::RIGHT, "NEW RECORD!");
		}
	}
}
<|endoftext|>


<commit_before>namespace dd{

	inline double dd::CompactFactor::_potential_equal(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid, const VariableValue & proposal) const{

	  const VariableInFactor & vif = vifs[n_start_i_vif];
	  const bool firstsat = (vif.vid == vid) ? vif.satisfiedUsing(proposal) :
	  	  vif.satisfiedUsing(var_values[vif.vid]);

	  for(long i_vif=n_start_i_vif; (i_vif<n_start_i_vif+n_variables);i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    bool satisfied = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    if(satisfied != firstsat) return 0.0;
	  }
	  return 1.0;
	}

	inline double dd::CompactFactor::_potential_and(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  for(long i_vif=n_start_i_vif; (i_vif<n_start_i_vif+n_variables);i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    bool satisfied = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    if(!satisfied) return 0.0;
	  }
	  return 1.0;

	}

	inline double dd::CompactFactor::_potential_or(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  for(long i_vif=n_start_i_vif; (i_vif<n_start_i_vif+n_variables);i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    bool satisfied = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    if(satisfied) return 1.0;
	  }
	  return 0.0;

	}

	inline double dd::CompactFactor::_potential_imply_mln(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  bool bBody = true; //
	  for(long i_vif=n_start_i_vif;
	    (i_vif<n_start_i_vif+n_variables - 1) // shortcut && bBody
	      ;i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    // if it is the proposal variable, we use the truth value of the proposal
	    // This is a crazy abstraction here, why doesn't vif able to say that it is true or false
	    //bool bTrue = (vif.vid == vif) ? vif.value.equal(proposal) : vif.value.equal(var_values[vif.vid]) ;
	    bBody &= (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	  }
	  if(bBody) {
	    const VariableInFactor & vif = vifs[n_start_i_vif + n_variables - 1]; // encoding of the head, should be more structured.
	    // const VariableInFactor & vif = head(vifs); // encoding of the head, should be more structured.
	    bool bHead = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    return bHead ? 1.0 : 0.0;
	  } else {
	    return 1.0;
	  }

	}

	inline double dd::CompactFactor::_potential_imply(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  bool bBody = true; //
	  for(long i_vif=n_start_i_vif;
	    (i_vif<n_start_i_vif+n_variables - 1) // shortcut && bBody
	      ;i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    // if it is the proposal variable, we use the truth value of the proposal
	    // This is a crazy abstraction here, why doesn't vif able to say that it is true or false
	    //bool bTrue = (vif.vid == vif) ? vif.value.equal(proposal) : vif.value.equal(var_values[vif.vid]) ;
	    bBody &= (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	  }
	  if(bBody) {
	    const VariableInFactor & vif = vifs[n_start_i_vif + n_variables - 1]; // encoding of the head, should be more structured.
	    bool bHead = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    return bHead ? 1.0 : -1.0;
	  } else {
	    return 0.0;
	  }

	}

	// potential for multinomial variable
	inline double dd::CompactFactor::_potential_multinomial(const VariableInFactor * vifs,
	  const VariableValue * var_values, const VariableIndex & vid, const VariableValue & proposal) const {

	  return 1.0;
	}

}
<commit_msg>Constify variables<commit_after>namespace dd{

	inline double dd::CompactFactor::_potential_equal(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid, const VariableValue & proposal) const{

	  const VariableInFactor & vif = vifs[n_start_i_vif];
	  const bool firstsat = (vif.vid == vid) ? vif.satisfiedUsing(proposal) :
	  	  vif.satisfiedUsing(var_values[vif.vid]);

	  for(long i_vif=n_start_i_vif; (i_vif<n_start_i_vif+n_variables);i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    const bool satisfied = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    if(satisfied != firstsat) return 0.0;
	  }
	  return 1.0;
	}

	inline double dd::CompactFactor::_potential_and(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  for(long i_vif=n_start_i_vif; (i_vif<n_start_i_vif+n_variables);i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    const bool satisfied = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    if(!satisfied) return 0.0;
	  }
	  return 1.0;

	}

	inline double dd::CompactFactor::_potential_or(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  for(long i_vif=n_start_i_vif; (i_vif<n_start_i_vif+n_variables);i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    const bool satisfied = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    if(satisfied) return 1.0;
	  }
	  return 0.0;

	}

	inline double dd::CompactFactor::_potential_imply_mln(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  bool bBody = true; //
	  for(long i_vif=n_start_i_vif;
	    (i_vif<n_start_i_vif+n_variables - 1) // shortcut && bBody
	      ;i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    // if it is the proposal variable, we use the truth value of the proposal
	    // This is a crazy abstraction here, why doesn't vif able to say that it is true or false
	    //bool bTrue = (vif.vid == vif) ? vif.value.equal(proposal) : vif.value.equal(var_values[vif.vid]) ;
	    bBody &= (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	  }
	  if(bBody) {
	    const VariableInFactor & vif = vifs[n_start_i_vif + n_variables - 1]; // encoding of the head, should be more structured.
	    const bool bHead = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    return bHead ? 1.0 : 0.0;
	  } else {
	    return 1.0;
	  }

	}

	inline double dd::CompactFactor::_potential_imply(
	  const VariableInFactor * const vifs,
	  const VariableValue * const var_values,
	  const VariableIndex & vid,
	  const VariableValue & proposal) const{

	  bool bBody = true; //
	  for(long i_vif=n_start_i_vif;
	    (i_vif<n_start_i_vif+n_variables - 1) // shortcut && bBody
	      ;i_vif++){
	    const VariableInFactor & vif = vifs[i_vif];
	    // if it is the proposal variable, we use the truth value of the proposal
	    // This is a crazy abstraction here, why doesn't vif able to say that it is true or false
	    //bool bTrue = (vif.vid == vif) ? vif.value.equal(proposal) : vif.value.equal(var_values[vif.vid]) ;
	    bBody &= (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	  }
	  if(bBody) {
	    const VariableInFactor & vif = vifs[n_start_i_vif + n_variables - 1]; // encoding of the head, should be more structured.
	    bool bHead = (vif.vid == vid) ? vif.satisfiedUsing(proposal) : vif.satisfiedUsing(var_values[vif.vid]) ;
	    return bHead ? 1.0 : -1.0;
	  } else {
	    return 0.0;
	  }

	}

	// potential for multinomial variable
	inline double dd::CompactFactor::_potential_multinomial(const VariableInFactor * vifs,
	  const VariableValue * var_values, const VariableIndex & vid, const VariableValue & proposal) const {

	  return 1.0;
	}

}
<|endoftext|>


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

#ifndef __OZCALLS_H
#define __OZCALLS_H

#include "mozartcore.hh"
#include "emulate.hh"

#include <type_traits>

#ifndef MOZART_GENERATOR

namespace mozart {

namespace ozcalls {

//////////////////////////////
// Calling Oz code from C++ //
//////////////////////////////

namespace internal {

/**
 * Specializable routine to initialize the input arguments of an ozcall.
 */
template <typename T, bool synchronous>
struct InitOneArg {
  static void call(VM vm, UnstableNode& dest, T&& value) {
    dest.init(vm, std::forward<T>(value));
  }
};

// Specializations for asynchronous calls

template <>
struct InitOneArg<OutputParam<UnstableNode>, false> {
  static void call(VM vm, UnstableNode& dest, OutputParam<UnstableNode> param) {
    StableNode* variable = new (vm) StableNode(vm, OptVar::build(vm));
    param.value = Reference::build(vm, variable);
    dest = Reference::build(vm, variable);
  }
};

template <>
struct InitOneArg<OutputParam<RichNode>, false> {
  static void call(VM vm, UnstableNode& dest, OutputParam<RichNode> param) {
    StableNode* variable = new (vm) StableNode(vm, OptVar::build(vm));
    param.value = *variable;
    dest = Reference::build(vm, variable);
  }
};

template <typename T>
struct InitOneArg<OutputParam<T>, false> {
  static_assert(!std::is_same<T, T>::value,
    "out(V) with a C++ value is only permitted in synchronous calls");
};

// Specializations for synchronous calls

template <typename T>
struct InitOneArg<OutputParam<T>, true> {
  static void call(VM vm, UnstableNode& dest, OutputParam<T> param) {
    dest = OptVar::build(vm);
  }
};

template <typename T>
struct InitOneArg<nullable<T&>, true> {
  static void call(VM vm, UnstableNode& dest, nullable<T&> param) {
    if (param.isNull())
      dest = buildTuple(vm, MOZART_STR("none"));
    else
      dest = buildTuple(vm, MOZART_STR("some"), OptVar::build(vm));
  }
};

template <typename T>
struct InitOneArg<nullable<T&>&, true>: public InitOneArg<nullable<T&>, true> {
};

template <size_t i, bool synchronous>
inline
void initNodesFromVariadicArgs(VM vm, UnstableNode nodes[]) {
}

template <size_t i, bool synchronous, typename Head, typename... Tail>
inline
void initNodesFromVariadicArgs(VM vm, UnstableNode nodes[],
                               Head&& head, Tail&&... tail) {
  InitOneArg<Head, synchronous>::call(vm, nodes[i],
                                      std::forward<Head>(head));
  initNodesFromVariadicArgs<i+1, synchronous>(vm, nodes,
                                              std::forward<Tail>(tail)...);
}

template <bool synchronous, typename... Args>
inline
void initInputArguments(VM vm, UnstableNode unstables[], RichNode riches[],
                        Args&&... args) {
  constexpr size_t argc = sizeof...(args);

  internal::initNodesFromVariadicArgs<0, synchronous>(
    vm, unstables, std::forward<Args>(args)...);

  for (size_t i = 0; i < argc; i++)
    riches[i] = unstables[i];
}

/** Metastruct that defines how to process the output arguments */
template <size_t inputIdx, size_t outputIdx, typename... Args>
struct OutputProcessing {
};

/** Base case specialization */
template <size_t inputIdx, size_t outputIdx>
struct OutputProcessing<inputIdx, outputIdx> {
  static constexpr size_t outArgc() {
    return outputIdx;
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs) {
  }
};

/** Input parameter specialization */
template <size_t inputIdx, size_t outputIdx, typename Head, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, Head, Tail...> {
  typedef OutputProcessing<inputIdx+1, outputIdx, Tail...> Next;

  static constexpr size_t outArgc() {
    return Next::outArgc();
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
    Next::initOutputArguments(vm, outputs, inputs);
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                     Head&& head, Tail&&... tail) {
    Next::processOutputArguments(vm, outputs, std::forward<Tail>(tail)...);
  }
};

/** Output parameter specialization */
template <size_t inputIdx, size_t outputIdx, typename T, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, OutputParam<T>, Tail...> {
  typedef OutputProcessing<inputIdx+1, outputIdx+1, Tail...> Next;

  static constexpr size_t outArgc() {
    return Next::outArgc();
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
    outputs[outputIdx].init(vm, inputs[inputIdx]);
    Next::initOutputArguments(vm, outputs, inputs);
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                     OutputParam<T> head, Tail&&... tail) {
    head.value = getArgument<T>(vm, outputs[outputIdx]);
    Next::processOutputArguments(vm, outputs, std::forward<Tail>(tail)...);
  }
};

/** Optional output parameter specialization */
template <size_t inputIdx, size_t outputIdx, typename T, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, nullable<T&>, Tail...> {
  typedef OutputProcessing<inputIdx+1, outputIdx+1, Tail...> Next;

  static constexpr size_t outArgc() {
    return Next::outArgc();
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
    outputs[outputIdx].init(vm, inputs[inputIdx]);
    Next::initOutputArguments(vm, outputs, inputs);
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                     nullable<T&> head, Tail&&... tail) {
    using namespace patternmatching;

    if (!head.isNull()) {
      RichNode value;
      matchesTuple(vm, outputs[outputIdx], MOZART_STR("some"), capture(value));
      head.get() = getArgument<T>(vm, value);
    }

    Next::processOutputArguments(vm, outputs, std::forward<Tail>(tail)...);
  }
};

template <size_t inputIdx, size_t outputIdx, typename T, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, nullable<T&>&, Tail...>
  : public OutputProcessing<inputIdx, outputIdx, nullable<T&>, Tail...> {
};

} // namespace internal

void asyncOzCall(VM vm, Space* space, RichNode callable) {
  new (vm) Thread(vm, space, callable, 0, nullptr);
}

template <typename... Args>
void asyncOzCall(VM vm, Space* space, RichNode callable, Args&&... args) {
  constexpr size_t argc = sizeof...(args);

  UnstableNode unstableArgs[argc];
  RichNode arguments[argc];
  internal::initInputArguments<false>(
    vm, unstableArgs, arguments, std::forward<Args>(args)...);

  new (vm) Thread(vm, space, callable, argc, arguments);
}

template <typename... Args>
void asyncOzCall(VM vm, RichNode callable, Args&&... args) {
  asyncOzCall(vm, vm->getCurrentSpace(), callable,
              std::forward<Args>(args)...);
}

namespace internal {

template <bool reflective, typename Effect, typename... Args>
bool syncCallGeneric(VM vm, const nchar* identity, const Effect& effect,
                     Args&&... args) {
  constexpr size_t argc = sizeof...(args);

  typedef internal::OutputProcessing<0, 0, Args...> OutputProcessing;

  constexpr size_t outArgc = OutputProcessing::outArgc();

  /* Most unfortunately, gcc does not yet support capturing a parameter pack
   * in a lambda. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41934
   * It makes it awkward to reuse performNonIdempotentStep. This is why we have
   * some code duplication with this routine.
   */

  assert(vm->isIntermediateStateAvailable());

  IntermediateState& intermediateState = vm->getIntermediateState();
  auto checkPoint = intermediateState.makeCheckPoint(vm);
  RichNode state;

  if (!intermediateState.fetch(vm, identity,
                               patternmatching::capture(state))) {
    // Initialize the input arguments

    UnstableNode unstableArgs[argc];
    internal::initNodesFromVariadicArgs<0, /* synchronous = */ true>(
      vm, unstableArgs, std::forward<Args>(args)...);

    // Perform the effect

    UnstableNode terminationVar;
    effect(vm, unstableArgs, terminationVar);

    // Build the output of the first step

    UnstableNode outputTuple = Tuple::build(vm, outArgc+1,
                                            vm->coreatoms.sharp);
    StaticArray<StableNode> outputs =
      RichNode(outputTuple).as<Tuple>().getElementsArray();

    OutputProcessing::initOutputArguments(vm, outputs, unstableArgs);
    outputs[outArgc].init(vm, std::move(terminationVar));

    // Store the result of the first step in the intermediate state

    intermediateState.resetAndStore(vm, checkPoint, identity, outputTuple);
    state = outputTuple;
    state.ensureStable(vm);
  }

  {
    StaticArray<StableNode> outputs =
      state.as<Tuple>().getElementsArray();

    RichNode terminationVar = outputs[outArgc];
    if (terminationVar.isTransient())
      waitFor(vm, terminationVar);

    if (reflective && !terminationVar.is<Unit>())
      return false;

    // Now the thread is terminated, we can fetch the arguments

    OutputProcessing::processOutputArguments(vm, outputs,
                                             std::forward<Args>(args)...);

    return true;
  }
}

template <size_t count, size_t i = 0, typename F>
inline
auto static_for(const F& f) -> typename std::enable_if<i != count, void>::type {
  f(i);
  static_for<count, i+1, F>(f);
}

template <size_t count, size_t i = 0, typename F>
inline
auto static_for(const F& f) -> typename std::enable_if<i == count, void>::type {
}

}

template <typename... Args>
void ozCall(VM vm, const nchar* identity, RichNode callable, Args&&... args) {
  internal::syncCallGeneric</* reflective = */ false>(
    vm, identity,
    [callable] (VM vm, UnstableNode unstableArgs[],
                UnstableNode& terminationVar) {
      constexpr size_t argc = sizeof...(Args);

      RichNode arguments[argc];
      internal::static_for<argc>(
        [&] (size_t i) {
          arguments[i] = unstableArgs[i];
        }
      );

      Thread* thr = new (vm) Thread(vm, vm->getCurrentSpace(),
                                    callable, argc, arguments);

      terminationVar.copy(vm, thr->getTerminationVar());
    },
    std::forward<Args>(args)...
  );
}

template <typename... Args>
void ozCall(VM vm, RichNode callable, Args&&... args) {
  ozCall(vm, MOZART_STR("::mozart::ozcalls::ozCall"), callable,
         std::forward<Args>(args)...);
}

namespace internal {

template <typename Label, typename... Args>
inline
bool doReflectiveCall(VM vm, const nchar* identity, UnstableNode& stream,
                      Label&& label, Args&&... args) {
  return internal::syncCallGeneric</* reflective = */ true>(
    vm, identity,
    [&stream, &label] (VM vm, UnstableNode unstableArgs[],
                       UnstableNode& terminationVar) {
      constexpr size_t argc = sizeof...(Args);

      // Create the message

      auto message = Tuple::build(vm, argc, std::forward<Label>(label));
      auto messageElements = RichNode(message).as<Tuple>().getElementsArray();
      internal::static_for<argc>(
        [&] (size_t i) {
          messageElements[i].init(vm, unstableArgs[i]);
        }
      );

      // Create the termination variable

      terminationVar = Variable::build(vm);

      // Send the message#terminationVar to the stream

      sendToReadOnlyStream(vm, stream, buildSharp(vm, message, terminationVar));
    },
    std::forward<Args>(args)...
  );
}

} // namespace internal

} // namespace ozcalls

} // namespace mozart

#endif

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

#ifndef __OZCALLS_H
#define __OZCALLS_H

#include "mozartcore.hh"
#include "emulate.hh"

#include <type_traits>

#ifndef MOZART_GENERATOR

namespace mozart {

namespace ozcalls {

//////////////////////////////
// Calling Oz code from C++ //
//////////////////////////////

namespace internal {

/**
 * Specializable routine to initialize the input arguments of an ozcall.
 */
template <typename T, bool synchronous>
struct InitOneArg {
  static void call(VM vm, UnstableNode& dest, T&& value) {
    dest.init(vm, std::forward<T>(value));
  }
};

// Specializations for asynchronous calls

template <>
struct InitOneArg<OutputParam<UnstableNode>, false> {
  static void call(VM vm, UnstableNode& dest, OutputParam<UnstableNode> param) {
    StableNode* variable = new (vm) StableNode(vm, OptVar::build(vm));
    param.value = Reference::build(vm, variable);
    dest = Reference::build(vm, variable);
  }
};

template <>
struct InitOneArg<OutputParam<RichNode>, false> {
  static void call(VM vm, UnstableNode& dest, OutputParam<RichNode> param) {
    StableNode* variable = new (vm) StableNode(vm, OptVar::build(vm));
    param.value = *variable;
    dest = Reference::build(vm, variable);
  }
};

template <typename T>
struct InitOneArg<OutputParam<T>, false> {
  static_assert(!std::is_same<T, T>::value,
    "out(V) with a C++ value is only permitted in synchronous calls");
};

// Specializations for synchronous calls

template <typename T>
struct InitOneArg<OutputParam<T>, true> {
  static void call(VM vm, UnstableNode& dest, OutputParam<T> param) {
    dest = OptVar::build(vm);
  }
};

template <typename T>
struct InitOneArg<nullable<T&>, true> {
  static void call(VM vm, UnstableNode& dest, nullable<T&> param) {
    if (param.isNull())
      dest = buildTuple(vm, MOZART_STR("none"));
    else
      dest = buildTuple(vm, MOZART_STR("some"), OptVar::build(vm));
  }
};

template <typename T>
struct InitOneArg<nullable<T&>&, true>: public InitOneArg<nullable<T&>, true> {
};

template <size_t i, bool synchronous>
inline
void initNodesFromVariadicArgs(VM vm, UnstableNode nodes[]) {
}

template <size_t i, bool synchronous, typename Head, typename... Tail>
inline
void initNodesFromVariadicArgs(VM vm, UnstableNode nodes[],
                               Head&& head, Tail&&... tail) {
  InitOneArg<Head, synchronous>::call(vm, nodes[i],
                                      std::forward<Head>(head));
  initNodesFromVariadicArgs<i+1, synchronous>(vm, nodes,
                                              std::forward<Tail>(tail)...);
}

template <bool synchronous, typename... Args>
inline
void initInputArguments(VM vm, UnstableNode unstables[], RichNode riches[],
                        Args&&... args) {
  constexpr size_t argc = sizeof...(args);

  internal::initNodesFromVariadicArgs<0, synchronous>(
    vm, unstables, std::forward<Args>(args)...);

  for (size_t i = 0; i < argc; i++)
    riches[i] = unstables[i];
}

/** Metastruct that defines how to process the output arguments */
template <size_t inputIdx, size_t outputIdx, typename... Args>
struct OutputProcessing {
};

/** Base case specialization */
template <size_t inputIdx, size_t outputIdx>
struct OutputProcessing<inputIdx, outputIdx> {
  static constexpr size_t outArgc() {
    return outputIdx;
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs) {
  }
};

/** Input parameter specialization */
template <size_t inputIdx, size_t outputIdx, typename Head, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, Head, Tail...> {
  typedef OutputProcessing<inputIdx+1, outputIdx, Tail...> Next;

  static constexpr size_t outArgc() {
    return Next::outArgc();
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
    Next::initOutputArguments(vm, outputs, inputs);
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                     Head&& head, Tail&&... tail) {
    Next::processOutputArguments(vm, outputs, std::forward<Tail>(tail)...);
  }
};

/** Output parameter specialization */
template <size_t inputIdx, size_t outputIdx, typename T, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, OutputParam<T>, Tail...> {
  typedef OutputProcessing<inputIdx+1, outputIdx+1, Tail...> Next;

  static constexpr size_t outArgc() {
    return Next::outArgc();
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
    outputs[outputIdx].init(vm, inputs[inputIdx]);
    Next::initOutputArguments(vm, outputs, inputs);
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                     OutputParam<T> head, Tail&&... tail) {
    head.value = getArgument<T>(vm, outputs[outputIdx]);
    Next::processOutputArguments(vm, outputs, std::forward<Tail>(tail)...);
  }
};

/** Optional output parameter specialization */
template <size_t inputIdx, size_t outputIdx, typename T, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, nullable<T&>, Tail...> {
  typedef OutputProcessing<inputIdx+1, outputIdx+1, Tail...> Next;

  static constexpr size_t outArgc() {
    return Next::outArgc();
  }

  static void initOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                  UnstableNode inputs[]) {
    outputs[outputIdx].init(vm, inputs[inputIdx]);
    Next::initOutputArguments(vm, outputs, inputs);
  }

  static void processOutputArguments(VM vm, StaticArray<StableNode> outputs,
                                     nullable<T&> head, Tail&&... tail) {
    using namespace patternmatching;

    if (!head.isNull()) {
      RichNode value;
      matchesTuple(vm, outputs[outputIdx], MOZART_STR("some"), capture(value));
      head.get() = getArgument<T>(vm, value);
    }

    Next::processOutputArguments(vm, outputs, std::forward<Tail>(tail)...);
  }
};

template <size_t inputIdx, size_t outputIdx, typename T, typename... Tail>
struct OutputProcessing<inputIdx, outputIdx, nullable<T&>&, Tail...>
  : public OutputProcessing<inputIdx, outputIdx, nullable<T&>, Tail...> {
};

} // namespace internal

void asyncOzCall(VM vm, Space* space, RichNode callable) {
  new (vm) Thread(vm, space, callable, 0, nullptr);
}

template <typename... Args>
void asyncOzCall(VM vm, Space* space, RichNode callable, Args&&... args) {
  constexpr size_t argc = sizeof...(args);

  UnstableNode unstableArgs[argc];
  RichNode arguments[argc];
  internal::initInputArguments<false>(
    vm, unstableArgs, arguments, std::forward<Args>(args)...);

  new (vm) Thread(vm, space, callable, argc, arguments);
}

template <typename... Args>
void asyncOzCall(VM vm, RichNode callable, Args&&... args) {
  asyncOzCall(vm, vm->getCurrentSpace(), callable,
              std::forward<Args>(args)...);
}

namespace internal {

template <bool reflective, typename Effect, typename... Args>
bool syncCallGeneric(VM vm, const nchar* identity, const Effect& effect,
                     Args&&... args) {
  constexpr size_t argc = sizeof...(args);

  typedef internal::OutputProcessing<0, 0, Args...> OutputProcessing;

  constexpr size_t outArgc = OutputProcessing::outArgc();

  /* Most unfortunately, gcc does not yet support capturing a parameter pack
   * in a lambda. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41934
   * It makes it awkward to reuse performNonIdempotentStep. This is why we have
   * some code duplication with this routine.
   */

  assert(vm->isIntermediateStateAvailable());

  IntermediateState& intermediateState = vm->getIntermediateState();
  auto checkPoint = intermediateState.makeCheckPoint(vm);
  RichNode state;

  if (!intermediateState.fetch(vm, identity,
                               patternmatching::capture(state))) {
    // Initialize the input arguments

    UnstableNode unstableArgs[argc];
    internal::initNodesFromVariadicArgs<0, /* synchronous = */ true>(
      vm, unstableArgs, std::forward<Args>(args)...);

    // Perform the effect

    UnstableNode terminationVar;
    effect(vm, unstableArgs, terminationVar);

    // Build the output of the first step

    UnstableNode outputTuple = Tuple::build(vm, outArgc+1,
                                            vm->coreatoms.sharp);
    StaticArray<StableNode> outputs =
      RichNode(outputTuple).as<Tuple>().getElementsArray();

    OutputProcessing::initOutputArguments(vm, outputs, unstableArgs);
    outputs[outArgc].init(vm, std::move(terminationVar));

    // Store the result of the first step in the intermediate state

    intermediateState.resetAndStore(vm, checkPoint, identity, outputTuple);
    state = outputTuple;
    state.ensureStable(vm);
  }

  {
    StaticArray<StableNode> outputs =
      state.as<Tuple>().getElementsArray();

    RichNode terminationVar = outputs[outArgc];
    if (terminationVar.isTransient())
      waitFor(vm, terminationVar);

    if (reflective && !terminationVar.is<Unit>())
      return false;

    // Now the thread is terminated, we can fetch the arguments

    OutputProcessing::processOutputArguments(vm, outputs,
                                             std::forward<Args>(args)...);

    return true;
  }
}

template <size_t count, size_t i = 0, typename F>
inline
auto static_for(const F& f) -> typename std::enable_if<i == count, void>::type {
}

template <size_t count, size_t i = 0, typename F>
inline
auto static_for(const F& f) -> typename std::enable_if<i != count, void>::type {
  f(i);
  static_for<count, i+1, F>(f);
}

}

template <typename... Args>
void ozCall(VM vm, const nchar* identity, RichNode callable, Args&&... args) {
  internal::syncCallGeneric</* reflective = */ false>(
    vm, identity,
    [callable] (VM vm, UnstableNode unstableArgs[],
                UnstableNode& terminationVar) {
      constexpr size_t argc = sizeof...(Args);

      RichNode arguments[argc];
      internal::static_for<argc>(
        [&] (size_t i) {
          arguments[i] = unstableArgs[i];
        }
      );

      Thread* thr = new (vm) Thread(vm, vm->getCurrentSpace(),
                                    callable, argc, arguments);

      terminationVar.copy(vm, thr->getTerminationVar());
    },
    std::forward<Args>(args)...
  );
}

template <typename... Args>
void ozCall(VM vm, RichNode callable, Args&&... args) {
  ozCall(vm, MOZART_STR("::mozart::ozcalls::ozCall"), callable,
         std::forward<Args>(args)...);
}

namespace internal {

template <typename Label, typename... Args>
inline
bool doReflectiveCall(VM vm, const nchar* identity, UnstableNode& stream,
                      Label&& label, Args&&... args) {
  return internal::syncCallGeneric</* reflective = */ true>(
    vm, identity,
    [&stream, &label] (VM vm, UnstableNode unstableArgs[],
                       UnstableNode& terminationVar) {
      constexpr size_t argc = sizeof...(Args);

      // Create the message

      auto message = Tuple::build(vm, argc, std::forward<Label>(label));
      auto messageElements = RichNode(message).as<Tuple>().getElementsArray();
      internal::static_for<argc>(
        [&] (size_t i) {
          messageElements[i].init(vm, unstableArgs[i]);
        }
      );

      // Create the termination variable

      terminationVar = Variable::build(vm);

      // Send the message#terminationVar to the stream

      sendToReadOnlyStream(vm, stream, buildSharp(vm, message, terminationVar));
    },
    std::forward<Args>(args)...
  );
}

} // namespace internal

} // namespace ozcalls

} // namespace mozart

#endif

#endif // __OZCALLS_H
<|endoftext|>