<commit_before>#include "coldstakingpage.h"

#include "bitcoinunits.h"
#include "coldstakinglistfilterproxy.h"
#include "coldstakinglistitemdelegate.h"
#include "coldstakingmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "main.h"
#include "newstakedelegationdialog.h"
#include "optionsmodel.h"
#include "qt/coldstakingmodel.h"
#include "transactiontablemodel.h"
#include "wallet.h"
#include "walletmodel.h"

#include <QAction>
#include <QClipboard>
#include <QDesktopServices>
#include <QKeyEvent>
#include <QMenu>
#include <QUrl>

#include "txdb.h"

#define LOAD_MIN_TIME_INTERVAL 15

const QString ColdStakingPage::copyOwnerAddressText  = "Copy owner address";
const QString ColdStakingPage::copyStakerAddressText = "Copy staker address";
const QString ColdStakingPage::copyAmountText        = "Copy amount";
const QString ColdStakingPage::enableStakingText     = "Enable staking for this address";
const QString ColdStakingPage::disableStakingText    = "Disable staking for this address";
const QString ColdStakingPage::cantStakeText         = "Cannot stake an address you delegated";

ColdStakingPage::ColdStakingPage(QWidget* parent)
    : QWidget(parent), ui(new Ui_ColdStaking), model(new ColdStakingModel),
      itemDelegate(new ColdStakingListItemDelegate)
{
    ui->setupUi(this);

    ui->listColdStakingView->setItemDelegate(itemDelegate);
    ui->listColdStakingView->setIconSize(QSize(ColdStakingListItemDelegate::DECORATION_SIZE,
                                               ColdStakingListItemDelegate::DECORATION_SIZE));
    ui->listColdStakingView->setMinimumHeight(ColdStakingListItemDelegate::NUM_ITEMS *
                                              (ColdStakingListItemDelegate::DECORATION_SIZE + 2));
    ui->listColdStakingView->setAttribute(Qt::WA_MacShowFocusRect, false);

    connect(ui->listColdStakingView, &ColdStakingListView::clicked, this,
            &ColdStakingPage::handleElementClicked);

    setupContextMenu();

    filter = new ColdStakingListFilterProxy(ui->filter_lineEdit, this);
    filter->setDynamicSortFilter(true);
    setModel(model);

    refreshData();

    newStakeDelegationDialog = new NewStakeDelegationDialog(this);

    //    connect(ui->delegateStakeButton, &QPushButton::clicked, newStakeDelegationDialog,
    //            &NewStakeDelegationDialog::open);
    connect(ui->delegateStakeButton, &QPushButton::clicked, this,
            &ColdStakingPage::slot_messageColdStakeNotReady);
    connect(ui->filter_lineEdit, &QLineEdit::textChanged, filter,
            &ColdStakingListFilterProxy::setFilterWildcard);
}

void ColdStakingPage::handleElementClicked(const QModelIndex& index)
{
    if (filter)
        emit tokenClicked(filter->mapToSource(index));
}

void ColdStakingPage::keyPressEvent(QKeyEvent* event)
{
    if (event->key() == Qt::Key_F && (event->modifiers() & Qt::ControlModifier)) {
        ui->filter_lineEdit->setFocus();
    }
}

void ColdStakingPage::setupContextMenu()
{
    ui->listColdStakingView->setContextMenuPolicy(Qt::CustomContextMenu);
    contextMenu          = new QMenu(this);
    copyOwnerAddrAction  = new QAction(copyOwnerAddressText, this);
    copyStakerAddrAction = new QAction(copyStakerAddressText, this);
    copyAmountAction     = new QAction(copyAmountText, this);
    toggleStakingAction  = new QAction(enableStakingText, this);

    contextMenu->addAction(copyOwnerAddrAction);
    contextMenu->addAction(copyStakerAddrAction);
    contextMenu->addAction(copyAmountAction);
    contextMenu->addSeparator();
    contextMenu->addAction(toggleStakingAction);

    connect(ui->listColdStakingView, &ColdStakingListView::customContextMenuRequested, this,
            &ColdStakingPage::slot_contextMenuRequested);

    connect(copyOwnerAddrAction, &QAction::triggered, this, &ColdStakingPage::slot_copyOwnerAddr);
    connect(copyStakerAddrAction, &QAction::triggered, this, &ColdStakingPage::slot_copyStakerAddr);
    connect(copyAmountAction, &QAction::triggered, this, &ColdStakingPage::slot_copyAmount);
}

void ColdStakingPage::slot_copyOwnerAddr()
{
    copyField(ColdStakingModel::ColumnIndex::OWNER_ADDRESS, "owner address");
}

void ColdStakingPage::slot_copyStakerAddr()
{
    copyField(ColdStakingModel::ColumnIndex::STAKING_ADDRESS, "staker address");
}

void ColdStakingPage::slot_copyAmount()
{
    copyField(ColdStakingModel::ColumnIndex::TOTAL_STACKEABLE_AMOUNT_STR, "amount");
}

void ColdStakingPage::slot_enableStaking(const QModelIndex& idx) { model->whitelist(idx); }

void ColdStakingPage::slot_disableStaking(const QModelIndex& idx) { model->blacklist(idx); }

void ColdStakingPage::slot_messageColdStakeNotReady()
{
    QMessageBox::information(this, "No cold-staking yet", "Cold-staking is still not enabled in neblio");
}

ColdStakingPage::~ColdStakingPage()
{
    notifyWalletConnection.disconnect();
    delete ui;
}

ColdStakingModel* ColdStakingPage::getTokenListModel() const { return model; }

void ColdStakingPage::setModel(ColdStakingModel* model)
{
    if (model) {
        filter->setSourceModel(model);
        ui->listColdStakingView->setModel(filter);
    }
}

void ColdStakingPage::setWalletModel(WalletModel* wModel)
{
    model->setWalletModel(wModel);
    connect(model->getTransactionTableModel(), &TransactionTableModel::txArrived, this,
            &ColdStakingPage::onTxArrived);

    newStakeDelegationDialog->setWalletModel(model->getWalletModel());

    notifyWalletConnection = model->getWalletModel()->getWallet()->NotifyAddressBookChanged.connect(
        [this](CWallet* /*wallet*/, const CTxDestination& /*address*/, const std::string& /*label*/,
               bool /*isMine*/, const std::string& /*purpose*/,
               ChangeType /*status*/) { refreshData(); });
}

void ColdStakingPage::slot_contextMenuRequested(QPoint pos)
{
    QModelIndexList selected = ui->listColdStakingView->selectedIndexesP();
    if (selected.size() == 1) {
        contextMenu->popup(ui->listColdStakingView->viewport()->mapToGlobal(pos));
        configureToggleStakingAction(selected.front());
    }
}

void ColdStakingPage::onTxArrived(const QString& /*hash*/) { tryRefreshData(); }

void ColdStakingPage::tryRefreshData()
{
    // Check for min update time to not reload the UI so often if the node is syncing.
    int64_t now = GetTime();
    if (lastRefreshTime + LOAD_MIN_TIME_INTERVAL < now) {
        lastRefreshTime = now;
        refreshData();
    }
}

void ColdStakingPage::refreshData() { model->updateCSList(); }

void ColdStakingPage::copyField(ColdStakingModel::ColumnIndex column, const QString& columnName)
{
    const QModelIndexList selected = ui->listColdStakingView->selectedIndexesP();
    std::set<int>         rows;
    for (long i = 0; i < selected.size(); i++) {
        QModelIndex index = selected.at(i);
        int         row   = index.row();
        rows.insert(row);
    }
    if (rows.size() != 1) {
        QMessageBox::warning(this, "Failed to copy",
                             "Failed to copy " + columnName +
                                 "; selected items size is not equal to one");
        return;
    }
    const QModelIndex idx       = ui->listColdStakingView->model()->index(*rows.begin(), 0);
    QString           resultStr = ui->listColdStakingView->model()->data(idx, column).toString();
    if (!resultStr.isEmpty()) {
        QClipboard* clipboard = QGuiApplication::clipboard();
        clipboard->setText(resultStr);
    } else {
        QMessageBox::warning(this, "Failed to copy", "No information to include in the clipboard");
    }
}

void ColdStakingPage::configureToggleStakingAction(const QModelIndex& idx)
{
    bool isWhitelisted = ui->listColdStakingView->model()
                             ->data(idx, ColdStakingModel::ColumnIndex::IS_WHITELISTED)
                             .toBool();
    bool isStaker = ui->listColdStakingView->model()
                        ->data(idx, ColdStakingModel::ColumnIndex::IS_RECEIVED_DELEGATION)
                        .toBool();

    // disconnect everything and reconnect it below
    toggleStakingAction->disconnect();

    if (!isStaker) {
        if (isWhitelisted) {
            toggleStakingAction->setText(disableStakingText);
            connect(toggleStakingAction, &QAction::triggered, this, [=]() { slot_disableStaking(idx); });
        } else {
            toggleStakingAction->setText(enableStakingText);
            connect(toggleStakingAction, &QAction::triggered, this, [=]() { slot_enableStaking(idx); });
        }
        toggleStakingAction->setEnabled(true);
    } else {
        toggleStakingAction->setText(cantStakeText);
        toggleStakingAction->setEnabled(false);
    }
}
<commit_msg>Update coldstakingpage.cpp<commit_after>#include "coldstakingpage.h"

#include "bitcoinunits.h"
#include "coldstakinglistfilterproxy.h"
#include "coldstakinglistitemdelegate.h"
#include "coldstakingmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "main.h"
#include "newstakedelegationdialog.h"
#include "optionsmodel.h"
#include "qt/coldstakingmodel.h"
#include "transactiontablemodel.h"
#include "wallet.h"
#include "walletmodel.h"

#include <QAction>
#include <QClipboard>
#include <QDesktopServices>
#include <QKeyEvent>
#include <QMenu>
#include <QUrl>

#include "txdb.h"

#define LOAD_MIN_TIME_INTERVAL 15

const QString ColdStakingPage::copyOwnerAddressText  = "Copy owner address";
const QString ColdStakingPage::copyStakerAddressText = "Copy staker address";
const QString ColdStakingPage::copyAmountText        = "Copy amount";
const QString ColdStakingPage::enableStakingText     = "Enable staking for this address";
const QString ColdStakingPage::disableStakingText    = "Disable staking for this address";
const QString ColdStakingPage::cantStakeText         = "Cannot stake an address you delegated";

ColdStakingPage::ColdStakingPage(QWidget* parent)
    : QWidget(parent), ui(new Ui_ColdStaking), model(new ColdStakingModel),
      itemDelegate(new ColdStakingListItemDelegate)
{
    ui->setupUi(this);

    ui->listColdStakingView->setItemDelegate(itemDelegate);
    ui->listColdStakingView->setIconSize(QSize(ColdStakingListItemDelegate::DECORATION_SIZE,
                                               ColdStakingListItemDelegate::DECORATION_SIZE));
    ui->listColdStakingView->setMinimumHeight(ColdStakingListItemDelegate::NUM_ITEMS *
                                              (ColdStakingListItemDelegate::DECORATION_SIZE + 2));
    ui->listColdStakingView->setAttribute(Qt::WA_MacShowFocusRect, false);

    connect(ui->listColdStakingView, &ColdStakingListView::clicked, this,
            &ColdStakingPage::handleElementClicked);

    setupContextMenu();

    filter = new ColdStakingListFilterProxy(ui->filter_lineEdit, this);
    filter->setDynamicSortFilter(true);
    setModel(model);

    refreshData();

    newStakeDelegationDialog = new NewStakeDelegationDialog(this);

    //    connect(ui->delegateStakeButton, &QPushButton::clicked, newStakeDelegationDialog,
    //            &NewStakeDelegationDialog::open);
    connect(ui->delegateStakeButton, &QPushButton::clicked, this,
            &ColdStakingPage::slot_messageColdStakeNotReady);
    connect(ui->filter_lineEdit, &QLineEdit::textChanged, filter,
            &ColdStakingListFilterProxy::setFilterWildcard);
}

void ColdStakingPage::handleElementClicked(const QModelIndex& index)
{
    if (filter)
        emit tokenClicked(filter->mapToSource(index));
}

void ColdStakingPage::keyPressEvent(QKeyEvent* event)
{
    if (event->key() == Qt::Key_F && (event->modifiers() & Qt::ControlModifier)) {
        ui->filter_lineEdit->setFocus();
    }
}

void ColdStakingPage::setupContextMenu()
{
    ui->listColdStakingView->setContextMenuPolicy(Qt::CustomContextMenu);
    contextMenu          = new QMenu(this);
    copyOwnerAddrAction  = new QAction(copyOwnerAddressText, this);
    copyStakerAddrAction = new QAction(copyStakerAddressText, this);
    copyAmountAction     = new QAction(copyAmountText, this);
    toggleStakingAction  = new QAction(enableStakingText, this);

    contextMenu->addAction(copyOwnerAddrAction);
    contextMenu->addAction(copyStakerAddrAction);
    contextMenu->addAction(copyAmountAction);
    contextMenu->addSeparator();
    contextMenu->addAction(toggleStakingAction);

    connect(ui->listColdStakingView, &ColdStakingListView::customContextMenuRequested, this,
            &ColdStakingPage::slot_contextMenuRequested);

    connect(copyOwnerAddrAction, &QAction::triggered, this, &ColdStakingPage::slot_copyOwnerAddr);
    connect(copyStakerAddrAction, &QAction::triggered, this, &ColdStakingPage::slot_copyStakerAddr);
    connect(copyAmountAction, &QAction::triggered, this, &ColdStakingPage::slot_copyAmount);
}

void ColdStakingPage::slot_copyOwnerAddr()
{
    copyField(ColdStakingModel::ColumnIndex::OWNER_ADDRESS, "owner address");
}

void ColdStakingPage::slot_copyStakerAddr()
{
    copyField(ColdStakingModel::ColumnIndex::STAKING_ADDRESS, "staker address");
}

void ColdStakingPage::slot_copyAmount()
{
    copyField(ColdStakingModel::ColumnIndex::TOTAL_STACKEABLE_AMOUNT_STR, "amount");
}

void ColdStakingPage::slot_enableStaking(const QModelIndex& idx) { model->whitelist(idx); }

void ColdStakingPage::slot_disableStaking(const QModelIndex& idx) { model->blacklist(idx); }

void ColdStakingPage::slot_messageColdStakeNotReady()
{
    QMessageBox::information(this, "Cold Staking is Testnet-Only", "Neblio Cold Staking is not yet enabled on Mainnet.");
}

ColdStakingPage::~ColdStakingPage()
{
    notifyWalletConnection.disconnect();
    delete ui;
}

ColdStakingModel* ColdStakingPage::getTokenListModel() const { return model; }

void ColdStakingPage::setModel(ColdStakingModel* model)
{
    if (model) {
        filter->setSourceModel(model);
        ui->listColdStakingView->setModel(filter);
    }
}

void ColdStakingPage::setWalletModel(WalletModel* wModel)
{
    model->setWalletModel(wModel);
    connect(model->getTransactionTableModel(), &TransactionTableModel::txArrived, this,
            &ColdStakingPage::onTxArrived);

    newStakeDelegationDialog->setWalletModel(model->getWalletModel());

    notifyWalletConnection = model->getWalletModel()->getWallet()->NotifyAddressBookChanged.connect(
        [this](CWallet* /*wallet*/, const CTxDestination& /*address*/, const std::string& /*label*/,
               bool /*isMine*/, const std::string& /*purpose*/,
               ChangeType /*status*/) { refreshData(); });
}

void ColdStakingPage::slot_contextMenuRequested(QPoint pos)
{
    QModelIndexList selected = ui->listColdStakingView->selectedIndexesP();
    if (selected.size() == 1) {
        contextMenu->popup(ui->listColdStakingView->viewport()->mapToGlobal(pos));
        configureToggleStakingAction(selected.front());
    }
}

void ColdStakingPage::onTxArrived(const QString& /*hash*/) { tryRefreshData(); }

void ColdStakingPage::tryRefreshData()
{
    // Check for min update time to not reload the UI so often if the node is syncing.
    int64_t now = GetTime();
    if (lastRefreshTime + LOAD_MIN_TIME_INTERVAL < now) {
        lastRefreshTime = now;
        refreshData();
    }
}

void ColdStakingPage::refreshData() { model->updateCSList(); }

void ColdStakingPage::copyField(ColdStakingModel::ColumnIndex column, const QString& columnName)
{
    const QModelIndexList selected = ui->listColdStakingView->selectedIndexesP();
    std::set<int>         rows;
    for (long i = 0; i < selected.size(); i++) {
        QModelIndex index = selected.at(i);
        int         row   = index.row();
        rows.insert(row);
    }
    if (rows.size() != 1) {
        QMessageBox::warning(this, "Failed to copy",
                             "Failed to copy " + columnName +
                                 "; selected items size is not equal to one");
        return;
    }
    const QModelIndex idx       = ui->listColdStakingView->model()->index(*rows.begin(), 0);
    QString           resultStr = ui->listColdStakingView->model()->data(idx, column).toString();
    if (!resultStr.isEmpty()) {
        QClipboard* clipboard = QGuiApplication::clipboard();
        clipboard->setText(resultStr);
    } else {
        QMessageBox::warning(this, "Failed to copy", "No information to include in the clipboard");
    }
}

void ColdStakingPage::configureToggleStakingAction(const QModelIndex& idx)
{
    bool isWhitelisted = ui->listColdStakingView->model()
                             ->data(idx, ColdStakingModel::ColumnIndex::IS_WHITELISTED)
                             .toBool();
    bool isStaker = ui->listColdStakingView->model()
                        ->data(idx, ColdStakingModel::ColumnIndex::IS_RECEIVED_DELEGATION)
                        .toBool();

    // disconnect everything and reconnect it below
    toggleStakingAction->disconnect();

    if (!isStaker) {
        if (isWhitelisted) {
            toggleStakingAction->setText(disableStakingText);
            connect(toggleStakingAction, &QAction::triggered, this, [=]() { slot_disableStaking(idx); });
        } else {
            toggleStakingAction->setText(enableStakingText);
            connect(toggleStakingAction, &QAction::triggered, this, [=]() { slot_enableStaking(idx); });
        }
        toggleStakingAction->setEnabled(true);
    } else {
        toggleStakingAction->setText(cantStakeText);
        toggleStakingAction->setEnabled(false);
    }
}
<|endoftext|>


<commit_before>/// \file ROOT/TDrawingOptsBase.hxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2017-09-26
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_TDrawingOptsBase
#define ROOT7_TDrawingOptsBase

#include <ROOT/TColor.hxx>
#include <ROOT/TDrawingAttrs.hxx>
#include <ROOT/TStyle.hxx>

#include <RStringView.h>

#include <map>
#include <string>
#include <vector>

namespace ROOT {
namespace Experimental {
class TCanvas;
class TPadBase;

/** \class ROOT::Experimental::TDrawingOptsBase
  Base class for drawing options. Implements access to the default and the default's initialization
  from a config file.

  Drawing options are made up of three kinds of primitives:
    - TColor
    - integer (long long)
    - floating point (double)
  They register the primitives with their `TCanvas`, and then refer to the registered primitives.
  Upon destruction, the `TDrawingOptsBase` deregisters the use of its primitives with the `TCanvas`,
  which empties the respective slots in the tables of the `TCanvas`, unless other options reference
  the same primitives (through `SameAs()`), and until the last use has deregistered.

  In derived classes (e.g. drawing options for the class `MyFancyBox`), declare attribute members as
     TDrawingAttrRef<TColor> fLineColor{*this, "MyFancyBoxLineColor"};
  The attribute's value will be taken from the  will be initialized
  */

class TDrawingOptsBaseNoDefault {
public:
   template <class PRIMITIVE>
   class OptsAttrRefArr {
      /// Indexes of the `TCanvas`'s attribute table entries used by the options object.
      std::vector<TDrawingAttrRef<PRIMITIVE>> fRefArray;

   public:
      ~OptsAttrRefArr();
      /// Register an attribute.
      ///\returns the index of the new attribute.
      TDrawingAttrRef<PRIMITIVE> Register(TCanvas &canv, const PRIMITIVE &val);

      /// Re-use an existing attribute.
      ///\returns the index of the attribute (i.e. valRef).
      TDrawingAttrRef<PRIMITIVE> SameAs(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx);

      /// Re-use an existing attribute.
      ///\returns the index of the attribute, might be `IsInvalid()` if `val` could not be found.
      TDrawingAttrRef<PRIMITIVE> SameAs(TCanvas &canv, const PRIMITIVE &val);

      /// Update the attribute at index `idx` to the value `val`.
      void Update(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx, const PRIMITIVE &val);

      /// Clear all attribute references, removing their uses in `TCanvas`.
      void Release(TCanvas &canv);

      /// Once copied, elements of a OptsAttrRefArr need to increase their use count.
      void RegisterCopy(TCanvas &canv);

      /// Access to attribute (const version).
      const PRIMITIVE &Get(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx) const;

      /// Access to attribute (non-const version).
      PRIMITIVE &Get(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx);
   };

private:
   /// The `TCanvas` holding the `TDrawable` (or its `TPad`).
   TCanvas *fCanvas = nullptr;

   /// Name of these drawing options, e.g. "1D"; will cause a member `TLineAttr{*this, "Line"}` to
   /// look for a style setting called "1D.Line.Color".
   std::string fName;

   /// Indexes of the `TCanvas`'s color table entries used by this options object.
   OptsAttrRefArr<TColor> fColorIdx;

   /// Indexes of the `TCanvas`'s integer table entries used by this options object.
   OptsAttrRefArr<long long> fIntIdx;

   /// Indexes of the `TCanvas`'s floating point table entries used by this options object.
   OptsAttrRefArr<double> fFPIdx;

   /// Access to the attribute tables (non-const version).
   OptsAttrRefArr<TColor> &GetAttrsRefArr(TColor *) { return fColorIdx; }
   OptsAttrRefArr<long long> &GetAttrsRefArr(long long *) { return fIntIdx; }
   OptsAttrRefArr<double> &GetAttrsRefArr(double *) { return fFPIdx; }

   /// Access to the attribute tables (const version).
   const OptsAttrRefArr<TColor> &GetAttrsRefArr(TColor *) const { return fColorIdx; }
   const OptsAttrRefArr<long long> &GetAttrsRefArr(long long *) const { return fIntIdx; }
   const OptsAttrRefArr<double> &GetAttrsRefArr(double *) const { return fFPIdx; }

protected:
   /// Construct from the pad that holds our `TDrawable`.
   TDrawingOptsBaseNoDefault(TPadBase &pad, std::string_view name);

   /// Default attributes need to register their values in a pad - they will take this pad
   /// for default attributes of a style, as identified by the style's name.
   static TPadBase &GetDefaultCanvas(const TStyle &style);

   /// Whether the canvas is one of the canvases used to store attribute defaults.
   static bool IsDefaultCanvas(const TPadBase &canv);

   /// Get the (style config) name of this option set.
   const std::string &GetName() const { return fName; }

   /// The `TCanvas` holding the `TDrawable` (or its `TPad`) (non-const version).
   TCanvas &GetCanvas() { return *fCanvas; }

   /// The `TCanvas` holding the `TDrawable` (or its `TPad`) (const version).
   const TCanvas &GetCanvas() const { return *fCanvas; }

   template <class PRIMITIVE>
   TDrawingAttrRef<PRIMITIVE> Register(const PRIMITIVE &val)
   {
      return GetAttrsRefArr((PRIMITIVE *)nullptr).Register(GetCanvas(), val);
   }

   template <class PRIMITIVE>
   void Update(TDrawingAttrRef<PRIMITIVE> idx, const PRIMITIVE &val)
   {
      GetAttrsRefArr((PRIMITIVE *)nullptr).Update(GetCanvas(), idx, val);
   }

   template <class PRIMITIVE>
   TDrawingAttrRef<PRIMITIVE> SameAs(TDrawingAttrRef<PRIMITIVE> idx)
   {
      return GetAttrsRefArr((PRIMITIVE *)nullptr).SameAs(GetCanvas(), idx);
   }

   template <class PRIMITIVE>
   TDrawingAttrRef<PRIMITIVE> SameAs(const PRIMITIVE &val)
   {
      return GetAttrsRefArr((PRIMITIVE *)nullptr).SameAs(GetCanvas(), val);
   }

   template <class PRIMITIVE>
   friend class TDrawingAttrRef;

public:
   TDrawingOptsBaseNoDefault() = default;
   ~TDrawingOptsBaseNoDefault();
   TDrawingOptsBaseNoDefault(const TDrawingOptsBaseNoDefault &other);
   TDrawingOptsBaseNoDefault(TDrawingOptsBaseNoDefault &&other) = default;

   /// Access to the attribute (non-const version).
   template <class PRIMITIVE>
   PRIMITIVE &Get(TDrawingAttrRef<PRIMITIVE> ref) { return GetAttrsRefArr((PRIMITIVE*)nullptr).Get(GetCanvas(), ref); }
   /// Access to the attribute (const version).
   template <class PRIMITIVE>
   const PRIMITIVE &Get(TDrawingAttrRef<PRIMITIVE> ref) const { return GetAttrsRefArr((PRIMITIVE*)nullptr).Get(GetCanvas(), ref); }
};

extern template class TDrawingOptsBaseNoDefault::OptsAttrRefArr<TColor>;
extern template class TDrawingOptsBaseNoDefault::OptsAttrRefArr<long long>;
extern template class TDrawingOptsBaseNoDefault::OptsAttrRefArr<double>;

template <class DERIVED>
class TDrawingOptsBase: public TDrawingOptsBaseNoDefault {
public:
   TDrawingOptsBase() = default;
   /// Construct from the pad that holds our `TDrawable`.
   TDrawingOptsBase(TPadBase &pad, std::string_view name):
   TDrawingOptsBaseNoDefault(pad, name)
   {
      if (!IsDefaultCanvas(pad))
         Default();
   }

   /// Apply the given options to this option set.
   void Apply(const DERIVED& other) {
      static_cast<DERIVED&>(*this) = other;
   }

   /// Retrieve the default drawing options for the given style.
   static DERIVED GetDefaultForStyle(const TStyle& style)
   {
      return DERIVED(GetDefaultCanvas(style));
   }

   /// Retrieve the default drawing options for `DERIVED`. Can be used to query and adjust the
   /// default options.
   static DERIVED &Default()
   {
      static DERIVED defaultOpts = GetDefaultForStyle(TStyle::GetCurrent());
      return defaultOpts;
   }
};

} // namespace Experimental
} // namespace ROOT

#endif
<commit_msg>Fix doc.<commit_after>/// \file ROOT/TDrawingOptsBase.hxx
/// \ingroup Gpad ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2017-09-26
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_TDrawingOptsBase
#define ROOT7_TDrawingOptsBase

#include <ROOT/TColor.hxx>
#include <ROOT/TDrawingAttrs.hxx>
#include <ROOT/TStyle.hxx>

#include <RStringView.h>

#include <map>
#include <string>
#include <vector>

namespace ROOT {
namespace Experimental {
class TCanvas;
class TPadBase;

/** \class ROOT::Experimental::TDrawingOptsBase
  Base class for drawing options. Implements access to the default and the default's initialization
  from a config file.

  Drawing options are made up of three kinds of primitives:
    - TColor
    - integer (long long)
    - floating point (double)
  They register the primitives with their `TCanvas`, and then refer to the registered primitives.
  Upon destruction, the `TDrawingOptsBase` deregisters the use of its primitives with the `TCanvas`,
  which empties the respective slots in the tables of the `TCanvas`, unless other options reference
  the same primitives (through `SameAs()`), and until the last use has deregistered.

  In derived classes (e.g. drawing options for the class `MyFancyBox`), declare attribute members as
     TDrawingAttrRef<TColor> fLineColor{*this, "MyFancyBoxLineColor", kRed};
  The attribute's initial value will be taken from the current style or, if that has no setting for
  the attribute, from the argument passed to the constructor (`kRed` in the example above).
  */

class TDrawingOptsBaseNoDefault {
public:
   template <class PRIMITIVE>
   class OptsAttrRefArr {
      /// Indexes of the `TCanvas`'s attribute table entries used by the options object.
      std::vector<TDrawingAttrRef<PRIMITIVE>> fRefArray;

   public:
      ~OptsAttrRefArr();
      /// Register an attribute.
      ///\returns the index of the new attribute.
      TDrawingAttrRef<PRIMITIVE> Register(TCanvas &canv, const PRIMITIVE &val);

      /// Re-use an existing attribute.
      ///\returns the index of the attribute (i.e. valRef).
      TDrawingAttrRef<PRIMITIVE> SameAs(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx);

      /// Re-use an existing attribute.
      ///\returns the index of the attribute, might be `IsInvalid()` if `val` could not be found.
      TDrawingAttrRef<PRIMITIVE> SameAs(TCanvas &canv, const PRIMITIVE &val);

      /// Update the attribute at index `idx` to the value `val`.
      void Update(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx, const PRIMITIVE &val);

      /// Clear all attribute references, removing their uses in `TCanvas`.
      void Release(TCanvas &canv);

      /// Once copied, elements of a OptsAttrRefArr need to increase their use count.
      void RegisterCopy(TCanvas &canv);

      /// Access to attribute (const version).
      const PRIMITIVE &Get(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx) const;

      /// Access to attribute (non-const version).
      PRIMITIVE &Get(TCanvas &canv, TDrawingAttrRef<PRIMITIVE> idx);
   };

private:
   /// The `TCanvas` holding the `TDrawable` (or its `TPad`).
   TCanvas *fCanvas = nullptr;

   /// Name of these drawing options, e.g. "1D"; will cause a member `TLineAttr{*this, "Line"}` to
   /// look for a style setting called "1D.Line.Color".
   std::string fName;

   /// Indexes of the `TCanvas`'s color table entries used by this options object.
   OptsAttrRefArr<TColor> fColorIdx;

   /// Indexes of the `TCanvas`'s integer table entries used by this options object.
   OptsAttrRefArr<long long> fIntIdx;

   /// Indexes of the `TCanvas`'s floating point table entries used by this options object.
   OptsAttrRefArr<double> fFPIdx;

   /// Access to the attribute tables (non-const version).
   OptsAttrRefArr<TColor> &GetAttrsRefArr(TColor *) { return fColorIdx; }
   OptsAttrRefArr<long long> &GetAttrsRefArr(long long *) { return fIntIdx; }
   OptsAttrRefArr<double> &GetAttrsRefArr(double *) { return fFPIdx; }

   /// Access to the attribute tables (const version).
   const OptsAttrRefArr<TColor> &GetAttrsRefArr(TColor *) const { return fColorIdx; }
   const OptsAttrRefArr<long long> &GetAttrsRefArr(long long *) const { return fIntIdx; }
   const OptsAttrRefArr<double> &GetAttrsRefArr(double *) const { return fFPIdx; }

protected:
   /// Construct from the pad that holds our `TDrawable`.
   TDrawingOptsBaseNoDefault(TPadBase &pad, std::string_view name);

   /// Default attributes need to register their values in a pad - they will take this pad
   /// for default attributes of a style, as identified by the style's name.
   static TPadBase &GetDefaultCanvas(const TStyle &style);

   /// Whether the canvas is one of the canvases used to store attribute defaults.
   static bool IsDefaultCanvas(const TPadBase &canv);

   /// Get the (style config) name of this option set.
   const std::string &GetName() const { return fName; }

   /// The `TCanvas` holding the `TDrawable` (or its `TPad`) (non-const version).
   TCanvas &GetCanvas() { return *fCanvas; }

   /// The `TCanvas` holding the `TDrawable` (or its `TPad`) (const version).
   const TCanvas &GetCanvas() const { return *fCanvas; }

   template <class PRIMITIVE>
   TDrawingAttrRef<PRIMITIVE> Register(const PRIMITIVE &val)
   {
      return GetAttrsRefArr((PRIMITIVE *)nullptr).Register(GetCanvas(), val);
   }

   template <class PRIMITIVE>
   void Update(TDrawingAttrRef<PRIMITIVE> idx, const PRIMITIVE &val)
   {
      GetAttrsRefArr((PRIMITIVE *)nullptr).Update(GetCanvas(), idx, val);
   }

   template <class PRIMITIVE>
   TDrawingAttrRef<PRIMITIVE> SameAs(TDrawingAttrRef<PRIMITIVE> idx)
   {
      return GetAttrsRefArr((PRIMITIVE *)nullptr).SameAs(GetCanvas(), idx);
   }

   template <class PRIMITIVE>
   TDrawingAttrRef<PRIMITIVE> SameAs(const PRIMITIVE &val)
   {
      return GetAttrsRefArr((PRIMITIVE *)nullptr).SameAs(GetCanvas(), val);
   }

   template <class PRIMITIVE>
   friend class TDrawingAttrRef;

public:
   TDrawingOptsBaseNoDefault() = default;
   ~TDrawingOptsBaseNoDefault();
   TDrawingOptsBaseNoDefault(const TDrawingOptsBaseNoDefault &other);
   TDrawingOptsBaseNoDefault(TDrawingOptsBaseNoDefault &&other) = default;

   /// Access to the attribute (non-const version).
   template <class PRIMITIVE>
   PRIMITIVE &Get(TDrawingAttrRef<PRIMITIVE> ref) { return GetAttrsRefArr((PRIMITIVE*)nullptr).Get(GetCanvas(), ref); }
   /// Access to the attribute (const version).
   template <class PRIMITIVE>
   const PRIMITIVE &Get(TDrawingAttrRef<PRIMITIVE> ref) const { return GetAttrsRefArr((PRIMITIVE*)nullptr).Get(GetCanvas(), ref); }
};

extern template class TDrawingOptsBaseNoDefault::OptsAttrRefArr<TColor>;
extern template class TDrawingOptsBaseNoDefault::OptsAttrRefArr<long long>;
extern template class TDrawingOptsBaseNoDefault::OptsAttrRefArr<double>;

template <class DERIVED>
class TDrawingOptsBase: public TDrawingOptsBaseNoDefault {
public:
   TDrawingOptsBase() = default;
   /// Construct from the pad that holds our `TDrawable`.
   TDrawingOptsBase(TPadBase &pad, std::string_view name):
   TDrawingOptsBaseNoDefault(pad, name)
   {
      if (!IsDefaultCanvas(pad))
         Default();
   }

   /// Apply the given options to this option set.
   void Apply(const DERIVED& other) {
      static_cast<DERIVED&>(*this) = other;
   }

   /// Retrieve the default drawing options for the given style.
   static DERIVED GetDefaultForStyle(const TStyle& style)
   {
      return DERIVED(GetDefaultCanvas(style));
   }

   /// Retrieve the default drawing options for `DERIVED`. Can be used to query and adjust the
   /// default options.
   static DERIVED &Default()
   {
      static DERIVED defaultOpts = GetDefaultForStyle(TStyle::GetCurrent());
      return defaultOpts;
   }
};

} // namespace Experimental
} // namespace ROOT

#endif
<|endoftext|>


<commit_before>
// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_FEATURES_FEATURE_HPP
#define OPENMVG_FEATURES_FEATURE_HPP

#include "openMVG/numeric/numeric.h"
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>

namespace openMVG {
namespace features {

/**
 * Base class for Point features.
 * Store position of the feature point.
 */
class PointFeature {

  friend std::ostream& operator<<(std::ostream& out, const PointFeature& obj);
  friend std::istream& operator>>(std::istream& in, PointFeature& obj);

public:
  PointFeature(float x=0.0f, float y=0.0f)
   : _coords(x, y) {}

  float x() const { return _coords(0); }
  float y() const { return _coords(1); }
  const Vec2f & coords() const { return _coords;}

  float& x() { return _coords(0); }
  float& y() { return _coords(1); }
  Vec2f& coords() { return _coords;}

  template<class Archive>
  void serialize(Archive & ar)
  {
    ar (_coords(0), _coords(1));
  }

protected:
  Vec2f _coords;  // (x, y).
};

typedef std::vector<PointFeature> PointFeatures;

//with overloaded operators:
inline std::ostream& operator<<(std::ostream& out, const PointFeature& obj)
{
  return out << obj._coords(0) << " " << obj._coords(1);
}

inline std::istream& operator>>(std::istream& in, PointFeature& obj)
{
  return in >> obj._coords(0) >> obj._coords(1);
}

/**
 * Base class for ScaleInvariant Oriented Point features.
 * Add scale and orientation description to basis PointFeature.
 */
class SIOPointFeature : public PointFeature {

    friend std::ostream& operator<<(std::ostream& out, const SIOPointFeature& obj);
    friend std::istream& operator>>(std::istream& in, SIOPointFeature& obj);

public:
  SIOPointFeature(float x=0.0f, float y=0.0f,
                  float scale=0.0f, float orient=0.0f)
    : PointFeature(x,y)
    , _scale(scale)
    , _orientation(orient) {}

  float scale() const { return _scale; }
  float& scale() { return _scale; }
  float orientation() const { return _orientation; }
  float& orientation() { return _orientation; }

  bool operator ==(const SIOPointFeature& b) const {
    return (_scale == b.scale()) &&
           (_orientation == b.orientation()) &&
           (x() == b.x()) && (y() == b.y()) ;
  };

  bool operator !=(const SIOPointFeature& b) const {
    return !((*this)==b);
  };

  template<class Archive>
  void serialize(Archive & ar)
  {
    ar (
      _coords(0), _coords(1),
      _scale,
      _orientation);
  }

protected:
  float _scale;        // In pixels.
  float _orientation;  // In radians.
};

//
inline std::ostream& operator<<(std::ostream& out, const SIOPointFeature& obj)
{
  const PointFeature *pf = static_cast<const PointFeature*>(&obj);
  return out << *pf << " " << obj._scale << " " << obj._orientation;
}

inline std::istream& operator>>(std::istream& in, SIOPointFeature& obj)
{
  PointFeature *pf = static_cast<PointFeature*>(&obj);
  return in >> *pf >> obj._scale >> obj._orientation;
}

/// Read feats from file
template<typename FeaturesT >
static bool loadFeatsFromFile(
  const std::string & sfileNameFeats,
  FeaturesT & vec_feat)
{
  vec_feat.clear();

  std::ifstream fileIn(sfileNameFeats.c_str());
  if (!fileIn.is_open())
    return false;

  std::copy(
    std::istream_iterator<typename FeaturesT::value_type >(fileIn),
    std::istream_iterator<typename FeaturesT::value_type >(),
    std::back_inserter(vec_feat));
  const bool bOk = !fileIn.bad();
  fileIn.close();
  return bOk;
}

/// Write feats to file
template<typename FeaturesT >
static bool saveFeatsToFile(
  const std::string & sfileNameFeats,
  FeaturesT & vec_feat)
{
  std::ofstream file(sfileNameFeats.c_str());
  if (!file.is_open())
    return false;
  std::copy(vec_feat.begin(), vec_feat.end(),
            std::ostream_iterator<typename FeaturesT::value_type >(file,"\n"));
  bool bOk = file.good();
  file.close();
  return bOk;
}

/// Export point feature based vector to a matrix [(x,y)'T, (x,y)'T]
template< typename FeaturesT, typename MatT >
void PointsToMat(
  const FeaturesT & vec_feats,
  MatT & m)
{
  m.resize(2, vec_feats.size());
  typedef typename FeaturesT::value_type ValueT; // Container type

  size_t i = 0;
  for( typename FeaturesT::const_iterator iter = vec_feats.begin();
    iter != vec_feats.end(); ++iter, ++i)
  {
    const ValueT & feat = *iter;
    m.col(i) << feat.x(), feat.y();
  }
}

} // namespace features
} // namespace openMVG

#endif // OPENMVG_FEATURES_FEATURE_HPP
<commit_msg>forgot a const. #454<commit_after>
// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef OPENMVG_FEATURES_FEATURE_HPP
#define OPENMVG_FEATURES_FEATURE_HPP

#include "openMVG/numeric/numeric.h"
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <vector>

namespace openMVG {
namespace features {

/**
 * Base class for Point features.
 * Store position of a feature point.
 */
class PointFeature {

  friend std::ostream& operator<<(std::ostream& out, const PointFeature& obj);
  friend std::istream& operator>>(std::istream& in, PointFeature& obj);

public:
  PointFeature(float x=0.0f, float y=0.0f)
   : _coords(x, y) {}

  float x() const { return _coords(0); }
  float y() const { return _coords(1); }
  const Vec2f & coords() const { return _coords;}

  float& x() { return _coords(0); }
  float& y() { return _coords(1); }
  Vec2f& coords() { return _coords;}

  template<class Archive>
  void serialize(Archive & ar)
  {
    ar (_coords(0), _coords(1));
  }

protected:
  Vec2f _coords;  // (x, y).
};

typedef std::vector<PointFeature> PointFeatures;

//with overloaded operators:
inline std::ostream& operator<<(std::ostream& out, const PointFeature& obj)
{
  return out << obj._coords(0) << " " << obj._coords(1);
}

inline std::istream& operator>>(std::istream& in, PointFeature& obj)
{
  return in >> obj._coords(0) >> obj._coords(1);
}

/**
 * Base class for ScaleInvariant Oriented Point features.
 * Add scale and orientation description to basis PointFeature.
 */
class SIOPointFeature : public PointFeature {

  friend std::ostream& operator<<(std::ostream& out, const SIOPointFeature& obj);
  friend std::istream& operator>>(std::istream& in, SIOPointFeature& obj);

public:
  SIOPointFeature(float x=0.0f, float y=0.0f,
                  float scale=0.0f, float orient=0.0f)
    : PointFeature(x,y)
    , _scale(scale)
    , _orientation(orient) {}

  float scale() const { return _scale; }
  float& scale() { return _scale; }
  float orientation() const { return _orientation; }
  float& orientation() { return _orientation; }

  bool operator ==(const SIOPointFeature& b) const {
    return (_scale == b.scale()) &&
           (_orientation == b.orientation()) &&
           (x() == b.x()) && (y() == b.y()) ;
  };

  bool operator !=(const SIOPointFeature& b) const {
    return !((*this)==b);
  };

  template<class Archive>
  void serialize(Archive & ar)
  {
    ar (
      _coords(0), _coords(1),
      _scale,
      _orientation);
  }

protected:
  float _scale;        // In pixels.
  float _orientation;  // In radians.
};

//
inline std::ostream& operator<<(std::ostream& out, const SIOPointFeature& obj)
{
  const PointFeature *pf = static_cast<const PointFeature*>(&obj);
  return out << *pf << " " << obj._scale << " " << obj._orientation;
}

inline std::istream& operator>>(std::istream& in, SIOPointFeature& obj)
{
  PointFeature *pf = static_cast<PointFeature*>(&obj);
  return in >> *pf >> obj._scale >> obj._orientation;
}

/// Read feats from file
template<typename FeaturesT >
static bool loadFeatsFromFile(
  const std::string & sfileNameFeats,
  FeaturesT & vec_feat)
{
  vec_feat.clear();

  std::ifstream fileIn(sfileNameFeats.c_str());
  if (!fileIn.is_open())
    return false;

  std::copy(
    std::istream_iterator<typename FeaturesT::value_type >(fileIn),
    std::istream_iterator<typename FeaturesT::value_type >(),
    std::back_inserter(vec_feat));
  const bool bOk = !fileIn.bad();
  fileIn.close();
  return bOk;
}

/// Write feats to file
template<typename FeaturesT >
static bool saveFeatsToFile(
  const std::string & sfileNameFeats,
  FeaturesT & vec_feat)
{
  std::ofstream file(sfileNameFeats.c_str());
  if (!file.is_open())
    return false;
  std::copy(vec_feat.begin(), vec_feat.end(),
            std::ostream_iterator<typename FeaturesT::value_type >(file,"\n"));
  const bool bOk = file.good();
  file.close();
  return bOk;
}

/// Export point feature based vector to a matrix [(x,y)'T, (x,y)'T]
template< typename FeaturesT, typename MatT >
void PointsToMat(
  const FeaturesT & vec_feats,
  MatT & m)
{
  m.resize(2, vec_feats.size());
  typedef typename FeaturesT::value_type ValueT; // Container type

  size_t i = 0;
  for( typename FeaturesT::const_iterator iter = vec_feats.begin();
    iter != vec_feats.end(); ++iter, ++i)
  {
    const ValueT & feat = *iter;
    m.col(i) << feat.x(), feat.y();
  }
}

} // namespace features
} // namespace openMVG

#endif // OPENMVG_FEATURES_FEATURE_HPP
<|endoftext|>


<commit_before>#include <mjolnir/input/read_input_file.hpp>

int main(int argc, char** argv)
{
    if(argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " <input.toml>" << std::endl;
        return 1;
    }

    auto simulator = mjolnir::read_input_file(std::string(argv[1]));

    simulator->initialize();

    const auto start = std::chrono::system_clock::now();
    std::cerr << "start running simulation" << std::endl;

    while(simulator->step()){/* do nothing */;}

    const auto stop = std::chrono::system_clock::now();
    std::cout << "elapsed time: "
              << std::chrono::duration_cast<std::chrono::milliseconds>(
                      stop - start).count() << " [msec]" << std::endl;

    simulator->finalize();

    return 0;
}
<commit_msg>add some messages to main function<commit_after>#include <mjolnir/input/read_input_file.hpp>

int main(int argc, char** argv)
{
    if(argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " <input.toml>" << std::endl;
        return 1;
    }

    std::cerr << "reading input file...";
    auto simulator = mjolnir::read_input_file(std::string(argv[1]));
    std::cerr << " done." << std::endl;

    std::cerr << "initializing simulator...";
    simulator->initialize();
    std::cerr << " done." << std::endl;

    const auto start = std::chrono::system_clock::now();
    std::cerr << "start running simulation" << std::endl;

    while(simulator->step()){/* do nothing */;}

    const auto stop = std::chrono::system_clock::now();
    std::cout << "elapsed time: "
              << std::chrono::duration_cast<std::chrono::milliseconds>(
                      stop - start).count() << " [msec]" << std::endl;

    simulator->finalize();

    return 0;
}
<|endoftext|>


<commit_before>// bdlma_guardingallocator.cpp                                        -*-C++-*-
#include <bdlma_guardingallocator.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdlma_guardingallocator_cpp,"$Id$ $CSID$")

#include <bsls_alignmentutil.h>
#include <bsls_assert.h>
#include <bsls_atomic.h>
#include <bsls_exceptionutil.h>      // 'BSLS_THROW'
#include <bsls_performancehint.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#include <bsl_cstddef.h>             // 'bsl::size_t'
#include <bsl_new.h>                 // 'bsl::bad_alloc'

#ifdef BSLS_PLATFORM_OS_WINDOWS

#include <windows.h>   // 'GetSystemInfo', 'VirtualAlloc', 'VirtualFree',
                       // 'VirtualProtect'
#else

#include <stdlib.h>    // 'valloc'
#include <sys/mman.h>  // 'mprotect'
#include <unistd.h>    // 'sysconf'

#endif

#ifdef BSLS_PLATFORM_OS_DARWIN

#include <sys/mman.h> // 'mmap', 'munmap'

#endif

namespace BloombergLP {

namespace {

// HELPER FUNCTIONS

// Define the offset (in bytes) from the address returned to the user in which
// to stash reference addresses ('e_AFTER_USER_BLOCK' only).

const bslma::Allocator::size_type OFFSET =
                                       bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT;

int getSystemPageSize()
    // Return the size (in bytes) of a system memory page.
{
    static bsls::AtomicInt pageSize(0);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == pageSize.loadRelaxed())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;

#ifdef BSLS_PLATFORM_OS_WINDOWS

        SYSTEM_INFO info;
        GetSystemInfo(&info);
        pageSize = static_cast<int>(info.dwPageSize);

#else

        pageSize = static_cast<int>(sysconf(_SC_PAGESIZE));

#endif
    }

    return pageSize.loadRelaxed();
}

void *systemAlloc(bsl::size_t size)
    // Allocate a page-aligned block of memory of the specified 'size' (in
    // bytes), and return the address of the allocated block.  The behavior is
    // undefined unless 'size > 0'.
{
    BSLS_ASSERT(size > 0);

#ifdef BSLS_PLATFORM_OS_WINDOWS

    return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

#elif defined(BSLS_PLATFORM_OS_DARWIN)

    return mmap(0,
                size,
                PROT_READ | PROT_WRITE,
                MAP_ANON | MAP_PRIVATE,
                0,
                0);

#else

    return valloc(size);

#endif
}

void systemFree(void *address, size_t size)
    // Return the memory block at the specified 'address' back to its
    // allocator.  The behavior is undefined unless 'address' was returned by
    // 'systemAlloc' and has not already been freed.
{
    BSLS_ASSERT(address);

#ifdef BSLS_PLATFORM_OS_WINDOWS

    VirtualFree(address, 0, MEM_RELEASE);
    (void) size;

#elif defined(BSLS_PLATFORM_OS_DARWIN)

    munmap(address, size);

#else

    free(address);
    (void) size;

#endif
}

int systemProtect(void *address, int pageSize)
    // Protect from read/write access the page of memory at the specified
    // 'address' having the specified 'pageSize' (in bytes).  The behavior is
    // undefined unless 'pageSize == getSystemPageSize()'.
{
    BSLS_ASSERT(address);
    BSLS_ASSERT_SAFE(pageSize == getSystemPageSize());

#ifdef BSLS_PLATFORM_OS_WINDOWS

    DWORD oldProtect;

    return !VirtualProtect(address, pageSize, PAGE_NOACCESS, &oldProtect);

#else

    return mprotect(static_cast<char *>(address), pageSize, PROT_NONE);

#endif
}

int systemUnprotect(void *address, int pageSize)
    // Unprotect from read/write access the page of memory at the specified
    // 'address' having the specified 'pageSize' (in bytes).  The behavior is
    // undefined unless 'pageSize == getSystemPageSize()'.
{
    BSLS_ASSERT(address);
    BSLS_ASSERT_SAFE(pageSize == getSystemPageSize());

#ifdef BSLS_PLATFORM_OS_WINDOWS

    DWORD  oldProtect;

    return !VirtualProtect(address, pageSize, PAGE_READWRITE, &oldProtect);

#else

    return mprotect(static_cast<char *>(address),
                    pageSize,
                    PROT_READ | PROT_WRITE);

#endif
}

}  // close unnamed namespace

namespace bdlma {

                        // -----------------------
                        // class GuardingAllocator
                        // -----------------------

// CREATORS
GuardingAllocator::~GuardingAllocator()
{
}

// MANIPULATORS
void *GuardingAllocator::allocate(size_type size)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == size)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return 0;                                                     // RETURN
    }

    const size_type paddedSize =
                          bsls::AlignmentUtil::roundUpToMaximalAlignment(size);

    // Adjust for additional memory needed to stash reference addresses when
    // 'e_AFTER_USER_BLOCK' is in use.

    const int adjustedSize = e_AFTER_USER_BLOCK == d_guardPageLocation
                             ? paddedSize + OFFSET * 2
                             : paddedSize;

    // Calculate the number of pages to allocate, *not* counting the guard
    // page.

    const int pageSize = getSystemPageSize();
    const int numPages = (adjustedSize + pageSize - 1) / pageSize;

    const size_type totalSize = (numPages + 1) * pageSize;  // add 1 for guard

    void *firstPage = systemAlloc(totalSize);

    if (!firstPage) {
#ifdef BDE_BUILD_TARGET_EXC
        BSLS_THROW(bsl::bad_alloc());
#else
        return 0;                                                     // RETURN
#endif
    }

    void *userAddress;  // address to return to the caller
    void *guardPage;    // address of the guard page for this allocation

    if (e_BEFORE_USER_BLOCK == d_guardPageLocation) {
        // Protect the memory page before the block returned to the user.

        guardPage   = firstPage;
        userAddress = static_cast<char *>(firstPage) + pageSize;
    }
    else {
        // Protect the memory page after the block returned to the user.

        guardPage   = static_cast<char *>(firstPage) + (numPages * pageSize);
        userAddress = static_cast<char *>(guardPage) - paddedSize;

        // Stash the reference addresses required by 'deallocate'.

        *(void **)(static_cast<char *>(userAddress) - OFFSET)     = firstPage;
        *(void **)(static_cast<char *>(userAddress) - OFFSET * 2) = guardPage;
    }

    // Protect the guard page from read/write access.

    *(int *)(guardPage) = totalSize;

    if (0 != systemProtect(guardPage, pageSize)) {
        systemFree(firstPage, totalSize);
#ifdef BDE_BUILD_TARGET_EXC
        BSLS_THROW(bsl::bad_alloc());
#else
        return 0;                                                     // RETURN
#endif
    }

    return userAddress;
}

void GuardingAllocator::deallocate(void *address)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == address)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return;                                                       // RETURN
    }

    const int pageSize = getSystemPageSize();

    void *firstPage;  // address of the first page of the allocation
    void *guardPage;  // address of the guard page

    if (e_BEFORE_USER_BLOCK == d_guardPageLocation) {
        // The memory page before the block returned to the user is protected.

        firstPage = static_cast<char *>(address) - pageSize;
        guardPage = firstPage;
    }
    else {
        // The memory page after the block returned to the user is protected.

        firstPage = *(void **)(static_cast<char *>(address) - OFFSET);
        guardPage = *(void **)(static_cast<char *>(address) - OFFSET * 2);
    }

    // Unprotect the guard page and free the memory.

    const int rc = systemUnprotect(guardPage, pageSize);
    (void)rc;

    size_t totalSize = *(int *)(guardPage);

    BSLS_ASSERT_OPT(0 == rc);

    systemFree(firstPage, totalSize);
}

}  // close package namespace
}  // close enterprise namespace

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

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdlma_guardingallocator_cpp,"$Id$ $CSID$")

#include <bsls_alignmentutil.h>
#include <bsls_assert.h>
#include <bsls_atomic.h>
#include <bsls_exceptionutil.h>      // 'BSLS_THROW'
#include <bsls_performancehint.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#include <bsl_cstddef.h>             // 'bsl::size_t'
#include <bsl_new.h>                 // 'bsl::bad_alloc'

#ifdef BSLS_PLATFORM_OS_WINDOWS

#include <windows.h>   // 'GetSystemInfo', 'VirtualAlloc', 'VirtualFree',
                       // 'VirtualProtect'
#else

#include <errno.h>     // 'errno'
#include <stdio.h>     // 'fprintf'
#include <string.h>    // 'strerror'
#include <sys/mman.h>  // 'mmap', 'mprotect', 'munmap'
#include <unistd.h>    // 'sysconf'

#endif

namespace BloombergLP {

namespace {

// HELPER FUNCTIONS

// Define the offset (in bytes) from the address returned to the user in which
// to stash reference addresses ('e_AFTER_USER_BLOCK' only).

const bslma::Allocator::size_type OFFSET =
                                       bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT;

int getSystemPageSize()
    // Return the size (in bytes) of a system memory page.
{
    static bsls::AtomicInt pageSize(0);

    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == pageSize.loadRelaxed())) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;

#ifdef BSLS_PLATFORM_OS_WINDOWS

        SYSTEM_INFO info;
        GetSystemInfo(&info);
        pageSize = static_cast<int>(info.dwPageSize);

#else

        pageSize = static_cast<int>(sysconf(_SC_PAGESIZE));

#endif
    }

    return pageSize.loadRelaxed();
}

void *systemAlloc(bsl::size_t size)
    // Allocate a page-aligned block of memory of the specified 'size' (in
    // bytes), and return the address of the allocated block.  The behavior is
    // undefined unless 'size > 0'.
{
    BSLS_ASSERT(size > 0);

#ifdef BSLS_PLATFORM_OS_WINDOWS

    return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
                                                                      // RETURN

#else

    void *address =  mmap(0,
                          size,
                          PROT_READ | PROT_WRITE,
                          MAP_ANON | MAP_PRIVATE,
                          -1,
                          0);

    if (MAP_FAILED == address) {
        /*
        fprintf(stderr,
                "mmap failed, errno %d (%s)\n",
                errno,
                strerror(errno)
               );
        */

        return 0;                                                     // RETURN
    }

    return address;                                                   // RETURN

#endif
}

void systemFree(void *address, size_t size)
    // Return the memory block at the specified 'address' back to its
    // allocator.  The behavior is undefined unless 'address' was returned by
    // 'systemAlloc' and has not already been freed.
{
    BSLS_ASSERT(address);

#ifdef BSLS_PLATFORM_OS_WINDOWS

    VirtualFree(address, 0, MEM_RELEASE);
    (void) size;

#else

    // On some of our platforms, 'munmap' takes a 'char*' argument, while on
    // others it takes a 'void*'.  Casting to 'char*', which will work in both
    // cases.
    munmap(static_cast<char*>(address), size);

#endif
}

int systemProtect(void *address, int pageSize)
    // Protect from read/write access the page of memory at the specified
    // 'address' having the specified 'pageSize' (in bytes).  The behavior is
    // undefined unless 'pageSize == getSystemPageSize()'.
{
    BSLS_ASSERT(address);
    BSLS_ASSERT_SAFE(pageSize == getSystemPageSize());

#ifdef BSLS_PLATFORM_OS_WINDOWS

    DWORD oldProtect;

    return !VirtualProtect(address, pageSize, PAGE_NOACCESS, &oldProtect);
                                                                      // RETURN

#else

    return mprotect(static_cast<char *>(address), pageSize, PROT_NONE);
                                                                      // RETURN

#endif
}

int systemUnprotect(void *address, int pageSize)
    // Unprotect from read/write access the page of memory at the specified
    // 'address' having the specified 'pageSize' (in bytes).  The behavior is
    // undefined unless 'pageSize == getSystemPageSize()'.
{
    BSLS_ASSERT(address);
    BSLS_ASSERT_SAFE(pageSize == getSystemPageSize());

#ifdef BSLS_PLATFORM_OS_WINDOWS

    DWORD  oldProtect;

    return !VirtualProtect(address, pageSize, PAGE_READWRITE, &oldProtect);
                                                                      // RETURN

#else

    return mprotect(static_cast<char *>(address),
                    pageSize,
                    PROT_READ | PROT_WRITE);                          // RETURN

#endif
}

}  // close unnamed namespace

namespace bdlma {

                        // -----------------------
                        // class GuardingAllocator
                        // -----------------------

// CREATORS
GuardingAllocator::~GuardingAllocator()
{
}

// MANIPULATORS
void *GuardingAllocator::allocate(size_type size)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == size)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return 0;                                                     // RETURN
    }

    const size_type paddedSize =
                          bsls::AlignmentUtil::roundUpToMaximalAlignment(size);

    // Adjust for additional memory needed to stash reference addresses when
    // 'e_AFTER_USER_BLOCK' is in use.

    const int adjustedSize = e_AFTER_USER_BLOCK == d_guardPageLocation
                             ? paddedSize + OFFSET * 2
                             : paddedSize;

    // Calculate the number of pages to allocate, *not* counting the guard
    // page.

    const int pageSize = getSystemPageSize();
    const int numPages = (adjustedSize + pageSize - 1) / pageSize;

    const size_type totalSize = (numPages + 1) * pageSize;  // add 1 for guard

    void *firstPage = systemAlloc(totalSize);

    if (!firstPage) {
#ifdef BDE_BUILD_TARGET_EXC
        BSLS_THROW(bsl::bad_alloc());
#else
        return 0;                                                     // RETURN
#endif
    }

    void *userAddress;  // address to return to the caller
    void *guardPage;    // address of the guard page for this allocation

    if (e_BEFORE_USER_BLOCK == d_guardPageLocation) {
        // Protect the memory page before the block returned to the user.

        guardPage   = firstPage;
        userAddress = static_cast<char *>(firstPage) + pageSize;
    }
    else {
        // Protect the memory page after the block returned to the user.

        guardPage   = static_cast<char *>(firstPage) + (numPages * pageSize);
        userAddress = static_cast<char *>(guardPage) - paddedSize;

        // Stash the reference addresses required by 'deallocate'.

        *(void **)(static_cast<char *>(userAddress) - OFFSET)     = firstPage;
        *(void **)(static_cast<char *>(userAddress) - OFFSET * 2) = guardPage;
    }

    // Save 'totalSize' - we'll need it for 'systemFree' in 'deallocate'.

    *(int *)(guardPage) = totalSize;

    // Protect the guard page from read/write access.

    if (0 != systemProtect(guardPage, pageSize)) {
        systemFree(firstPage, totalSize);
#ifdef BDE_BUILD_TARGET_EXC
        BSLS_THROW(bsl::bad_alloc());
#else
        return 0;                                                     // RETURN
#endif
    }

    return userAddress;
}

void GuardingAllocator::deallocate(void *address)
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == address)) {
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
        return;                                                       // RETURN
    }

    const int pageSize = getSystemPageSize();

    void *firstPage;  // address of the first page of the allocation
    void *guardPage;  // address of the guard page

    if (e_BEFORE_USER_BLOCK == d_guardPageLocation) {
        // The memory page before the block returned to the user is protected.

        firstPage = static_cast<char *>(address) - pageSize;
        guardPage = firstPage;
    }
    else {
        // The memory page after the block returned to the user is protected.

        firstPage = *(void **)(static_cast<char *>(address) - OFFSET);
        guardPage = *(void **)(static_cast<char *>(address) - OFFSET * 2);
    }

    // Unprotect the guard page and free the memory.

    const int rc = systemUnprotect(guardPage, pageSize);
    (void)rc;

    BSLS_ASSERT_OPT(0 == rc);

    size_t totalSize = *(int *)(guardPage);

    systemFree(firstPage, totalSize);
}

}  // close package namespace
}  // close enterprise namespace

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


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// operator_to_plan_transformer.cpp
//
// Identification: src/optimizer/operator_to_plan_transformer.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "optimizer/plan_generator.h"

#include "optimizer/operator_expression.h"
#include "planner/aggregate_plan.h"
#include "planner/delete_plan.h"
#include "planner/hash_join_plan.h"
#include "planner/hash_plan.h"
#include "planner/index_scan_plan.h"
#include "planner/insert_plan.h"
#include "planner/limit_plan.h"
#include "planner/nested_loop_join_plan.h"
#include "planner/order_by_plan.h"
#include "planner/projection_plan.h"
#include "planner/seq_scan_plan.h"
#include "planner/update_plan.h"
#include "settings/settings_manager.h"
#include "storage/data_table.h"

using std::vector;
using std::make_pair;
using std::string;
using std::to_string;
using std::unique_ptr;
using std::shared_ptr;
using std::move;
using std::make_tuple;
using std::make_pair;
using std::pair;

namespace peloton {
namespace optimizer {

PlanGenerator::PlanGenerator() {}

unique_ptr<planner::AbstractPlan> PlanGenerator::ConvertOpExpression(
    shared_ptr<OperatorExpression> op, shared_ptr<PropertySet> required_props,
    vector<expression::AbstractExpression *> required_cols,
    vector<expression::AbstractExpression *> output_cols,
    vector<unique_ptr<planner::AbstractPlan>> &children_plans,
    vector<ExprMap> children_expr_map) {
  required_props_ = required_props;
  required_cols_ = required_cols;
  output_cols_ = output_cols;
  children_plans_ = move(children_plans);
  children_expr_map_ = move(children_expr_map);
  op->Op().Accept(this);
  BuildProjectionPlan();
  return move(output_plan_);
}

void PlanGenerator::Visit(const DummyScan *) {
  // DummyScan is used in case of SELECT without FROM so that enforcer
  // can enforce a PhysicalProjection on top of DummyScan to generate correct
  // result. But here, no need to translate DummyScan to any physical plan.
  output_plan_ = nullptr;
}

void PlanGenerator::Visit(const PhysicalSeqScan *op) {
  vector<oid_t> column_ids = GenerateColumnsForScan();
  auto predicate = GeneratePredicateForScan(
      expression::ExpressionUtil::JoinAnnotatedExprs(op->predicates),
      op->table_alias, op->table_);

  output_plan_.reset(
      new planner::SeqScanPlan(op->table_, predicate.release(), column_ids));
}

void PlanGenerator::Visit(const PhysicalIndexScan *op) {
  vector<oid_t> column_ids = GenerateColumnsForScan();
  auto predicate = GeneratePredicateForScan(
      expression::ExpressionUtil::JoinAnnotatedExprs(op->predicates),
      op->table_alias, op->table_);

  auto index = op->table_->GetIndex(op->index_id);
  vector<expression::AbstractExpression *> runtime_keys;

  // Create index scan desc
  planner::IndexScanPlan::IndexScanDesc index_scan_desc(
      index, op->key_column_id_list, op->expr_type_list, op->value_list,
      runtime_keys);
  output_plan_.reset(new planner::IndexScanPlan(
      op->table_, predicate.release(), column_ids, index_scan_desc, false));
}

void PlanGenerator::Visit(const QueryDerivedScan *) {}

void PlanGenerator::Visit(const PhysicalProject *) {}

void PlanGenerator::Visit(const PhysicalLimit *op) {

   unique_ptr<planner::AbstractPlan> limit_plan(
       new planner::LimitPlan(op->limit, op->offset));
   limit_plan->AddChild(move(children_plans_[0]));
   output_plan_ = move(limit_plan);
}

void PlanGenerator::Visit(const PhysicalOrderBy *) {
  vector<oid_t> column_ids;
  PL_ASSERT(children_expr_map_.size() == 1);
  auto &child_cols_map = children_expr_map_[0];
  for (size_t i = 0; i < required_cols_.size(); ++i) {
    column_ids.push_back(child_cols_map[required_cols_[i]]);
  }

  auto sort_prop = required_props_->GetPropertyOfType(PropertyType::SORT)
                       ->As<PropertySort>();
  auto sort_columns_size = sort_prop->GetSortColumnSize();
  vector<oid_t> sort_col_ids;
  vector<bool> sort_flags;
  for (size_t i = 0; i < sort_columns_size; ++i) {
    sort_col_ids.push_back(child_cols_map[sort_prop->GetSortColumn(i)]);
    // planner use desc flag
    sort_flags.push_back(!sort_prop->GetSortAscending(i));
  }
  output_plan_.reset(
      new planner::OrderByPlan(sort_col_ids, sort_flags, column_ids));
  output_plan_->AddChild(move(children_plans_[0]));
}

void PlanGenerator::Visit(const PhysicalHashGroupBy *) {}

void PlanGenerator::Visit(const PhysicalSortGroupBy *) {}

void PlanGenerator::Visit(const PhysicalAggregate *) {}

void PlanGenerator::Visit(const PhysicalDistinct *) {}

void PlanGenerator::Visit(const PhysicalFilter *) {}

void PlanGenerator::Visit(const PhysicalInnerNLJoin *) {}

void PlanGenerator::Visit(const PhysicalLeftNLJoin *) {}

void PlanGenerator::Visit(const PhysicalRightNLJoin *) {}

void PlanGenerator::Visit(const PhysicalOuterNLJoin *) {}

void PlanGenerator::Visit(const PhysicalInnerHashJoin *) {}

void PlanGenerator::Visit(const PhysicalLeftHashJoin *) {}

void PlanGenerator::Visit(const PhysicalRightHashJoin *) {}

void PlanGenerator::Visit(const PhysicalOuterHashJoin *) {}

void PlanGenerator::Visit(const PhysicalInsert *op) {
  unique_ptr<planner::AbstractPlan> insert_plan(
      new planner::InsertPlan(op->target_table, op->columns, op->values));
  output_plan_ = move(insert_plan);
}

void PlanGenerator::Visit(const PhysicalInsertSelect *op) {
  unique_ptr<planner::AbstractPlan> insert_plan(
      new planner::InsertPlan(op->target_table));
  // Add child
  insert_plan->AddChild(move(children_plans_[0]));
  output_plan_ = move(insert_plan);
}

void PlanGenerator::Visit(const PhysicalDelete *op) {
   unique_ptr<planner::AbstractPlan> delete_plan(
       new planner::DeletePlan(op->target_table));

   // Add child
   delete_plan->AddChild(move(children_plans_[0]));
   output_plan_ = move(delete_plan);
}

void PlanGenerator::Visit(const PhysicalUpdate *op) {
   DirectMapList dml;
   TargetList tl;
   std::unordered_set<oid_t> update_col_ids;
   auto schema = op->target_table->GetSchema();
   auto table_alias = op->target_table->GetName();
  ExprMap table_expr_map = GenerateTableExprMap(table_alias, op->target_table);

   // Evaluate update expression and add to target list
   for (auto &update : *(op->updates)) {
     auto column = update->column;
     auto col_id = schema->GetColumnID(column);
     if (update_col_ids.find(col_id) != update_col_ids.end())
       throw SyntaxException("Multiple assignments to same column " + column);
     update_col_ids.insert(col_id);
     expression::ExpressionUtil::EvaluateExpression({table_expr_map},
                                                    update->value.get());
     planner::DerivedAttribute attribute{update->value->Copy()};
     tl.emplace_back(col_id, attribute);
   }

   // Add other columns to direct map
   auto col_size = schema->GetColumnCount();
   for (size_t i = 0; i < col_size; i++) {
     if (update_col_ids.find(i) == update_col_ids.end())
       dml.emplace_back(i, std::pair<oid_t, oid_t>(0, i));
   }

   unique_ptr<const planner::ProjectInfo> proj_info(
       new planner::ProjectInfo(move(tl), move(dml)));

   unique_ptr<planner::AbstractPlan> update_plan(
       new planner::UpdatePlan(op->target_table, move(proj_info)));
   update_plan->AddChild(move(children_plans_[0]));
   output_plan_ = move(update_plan);
}

/************************* Private Functions *******************************/
ExprMap PlanGenerator::GenerateTableExprMap(const std::string &alias,
                                            const storage::DataTable *table) {
  ExprMap expr_map;
  auto db_id = table->GetDatabaseOid();
  oid_t table_id = table->GetOid();
  auto cols = table->GetSchema()->GetColumns();
  size_t num_col = cols.size();
  for (oid_t col_id = 0; col_id < num_col; ++col_id) {
    // Only bound_obj_id is needed for expr_map
    // TODO potential memory leak here?
    expression::TupleValueExpression *col_expr =
        new expression::TupleValueExpression(cols[col_id].column_name.c_str(),
                                             alias.c_str());
    col_expr->SetValueType(table->GetSchema()->GetColumn(col_id).GetType());
    col_expr->SetBoundOid(db_id, table_id, col_id);
    expr_map[col_expr] = col_id;
  }
  return expr_map;
}

// Generate columns for scan plan
vector<oid_t> PlanGenerator::GenerateColumnsForScan() {
  vector<oid_t> column_ids;
  for (oid_t idx = 0; idx < output_cols_.size(); ++idx) {
    auto &output_expr = output_cols_[idx];
    PL_ASSERT(output_expr->GetExpressionType() == ExpressionType::VALUE_TUPLE);
    auto output_tvexpr =
        reinterpret_cast<expression::TupleValueExpression *>(output_expr);

    // Set column offset
    PL_ASSERT(output_tvexpr->GetIsBound() == true);
    auto col_id = std::get<2>(output_tvexpr->GetBoundOid());
    column_ids.push_back(col_id);
  }

  return column_ids;
}

std::unique_ptr<expression::AbstractExpression>
PlanGenerator::GeneratePredicateForScan(
    const std::shared_ptr<expression::AbstractExpression> predicate_expr,
    const std::string &alias, const storage::DataTable *table) {
  if (predicate_expr == nullptr) {
    return nullptr;
  }
  ExprMap table_expr_map = GenerateTableExprMap(alias, table);
  unique_ptr<expression::AbstractExpression> predicate =
      std::unique_ptr<expression::AbstractExpression>(predicate_expr->Copy());
  expression::ExpressionUtil::ConvertToTvExpr(col_copy, child_expr_map);
  expression::ExpressionUtil::EvaluateExpression({table_expr_map},
                                                 predicate.get());
  return predicate;
}

void PlanGenerator::BuildProjectionPlan() {
  bool no_projection = false;
  if (output_cols_.size() == required_cols_.size()) {
    no_projection = true;
    size_t cols_size = output_cols_.size();
    for (size_t idx = 0; idx < cols_size; ++idx) {
      if (output_cols_[idx] != required_cols_[idx]) {
        no_projection = false;
        break;
      }
    }
  }

  if (no_projection) {
    return;
  }
  vector<ExprMap> output_expr_maps = {ExprMap{}};
  auto &child_expr_map = output_expr_maps[0];
  for (size_t idx = 0; idx < output_cols_.size(); ++idx) {
    auto &col = output_cols_[idx];
    child_expr_map[col] = idx;
  }
  TargetList tl;
  DirectMapList dml;
  vector<catalog::Column> columns;
  for (size_t idx = 0; idx < required_cols_.size(); ++idx) {
    auto &col = required_cols_[idx];
    if (child_expr_map.find(col) != child_expr_map.end()) {
      dml.emplace_back(idx, make_pair(0, child_expr_map[col]));
    } else {
      // Copy then evaluate the expression and add to target list
      auto col_copy = col->Copy();
      expression::ExpressionUtil::ConvertToTvExpr(col_copy, child_expr_map);
      expression::ExpressionUtil::EvaluateExpression(children_expr_map_,
                                                     col_copy);
      planner::DerivedAttribute attribute{col_copy};
      tl.emplace_back(idx, attribute);
    }
    columns.push_back(catalog::Column(
        col->GetValueType(), type::Type::GetTypeSize(col->GetValueType()),
        col->GetExpressionName()));
  }

  unique_ptr<planner::ProjectInfo> proj_info(
      new planner::ProjectInfo(move(tl), move(dml)));
  // TODO since the plan will own the schema, we may not want to use unique_ptr
  // to initialize the plan
  shared_ptr<catalog::Schema> schema_ptr(new catalog::Schema(columns));
  unique_ptr<planner::AbstractPlan> project_plan(
      new planner::ProjectionPlan(move(proj_info), schema_ptr));

  PL_ASSERT(children_plans_.size() < 2);
  if (!children_plans_.empty()) {
    project_plan->AddChild(move(children_plans_[0]));
  }
  output_plan_ = move(project_plan);
}

}  // namespace optimizer
}  // namespace peloton
<commit_msg>Minor fix for compilation error<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// operator_to_plan_transformer.cpp
//
// Identification: src/optimizer/operator_to_plan_transformer.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "optimizer/plan_generator.h"

#include "optimizer/operator_expression.h"
#include "planner/aggregate_plan.h"
#include "planner/delete_plan.h"
#include "planner/hash_join_plan.h"
#include "planner/hash_plan.h"
#include "planner/index_scan_plan.h"
#include "planner/insert_plan.h"
#include "planner/limit_plan.h"
#include "planner/nested_loop_join_plan.h"
#include "planner/order_by_plan.h"
#include "planner/projection_plan.h"
#include "planner/seq_scan_plan.h"
#include "planner/update_plan.h"
#include "settings/settings_manager.h"
#include "storage/data_table.h"

using std::vector;
using std::make_pair;
using std::string;
using std::to_string;
using std::unique_ptr;
using std::shared_ptr;
using std::move;
using std::make_tuple;
using std::make_pair;
using std::pair;

namespace peloton {
namespace optimizer {

PlanGenerator::PlanGenerator() {}

unique_ptr<planner::AbstractPlan> PlanGenerator::ConvertOpExpression(
    shared_ptr<OperatorExpression> op, shared_ptr<PropertySet> required_props,
    vector<expression::AbstractExpression *> required_cols,
    vector<expression::AbstractExpression *> output_cols,
    vector<unique_ptr<planner::AbstractPlan>> &children_plans,
    vector<ExprMap> children_expr_map) {
  required_props_ = required_props;
  required_cols_ = required_cols;
  output_cols_ = output_cols;
  children_plans_ = move(children_plans);
  children_expr_map_ = move(children_expr_map);
  op->Op().Accept(this);
  BuildProjectionPlan();
  return move(output_plan_);
}

void PlanGenerator::Visit(const DummyScan *) {
  // DummyScan is used in case of SELECT without FROM so that enforcer
  // can enforce a PhysicalProjection on top of DummyScan to generate correct
  // result. But here, no need to translate DummyScan to any physical plan.
  output_plan_ = nullptr;
}

void PlanGenerator::Visit(const PhysicalSeqScan *op) {
  vector<oid_t> column_ids = GenerateColumnsForScan();
  auto predicate = GeneratePredicateForScan(
      expression::ExpressionUtil::JoinAnnotatedExprs(op->predicates),
      op->table_alias, op->table_);

  output_plan_.reset(
      new planner::SeqScanPlan(op->table_, predicate.release(), column_ids));
}

void PlanGenerator::Visit(const PhysicalIndexScan *op) {
  vector<oid_t> column_ids = GenerateColumnsForScan();
  auto predicate = GeneratePredicateForScan(
      expression::ExpressionUtil::JoinAnnotatedExprs(op->predicates),
      op->table_alias, op->table_);

  auto index = op->table_->GetIndex(op->index_id);
  vector<expression::AbstractExpression *> runtime_keys;

  // Create index scan desc
  planner::IndexScanPlan::IndexScanDesc index_scan_desc(
      index, op->key_column_id_list, op->expr_type_list, op->value_list,
      runtime_keys);
  output_plan_.reset(new planner::IndexScanPlan(
      op->table_, predicate.release(), column_ids, index_scan_desc, false));
}

void PlanGenerator::Visit(const QueryDerivedScan *) {}

void PlanGenerator::Visit(const PhysicalProject *) {}

void PlanGenerator::Visit(const PhysicalLimit *op) {
  unique_ptr<planner::AbstractPlan> limit_plan(
      new planner::LimitPlan(op->limit, op->offset));
  limit_plan->AddChild(move(children_plans_[0]));
  output_plan_ = move(limit_plan);
}

void PlanGenerator::Visit(const PhysicalOrderBy *) {
  vector<oid_t> column_ids;
  PL_ASSERT(children_expr_map_.size() == 1);
  auto &child_cols_map = children_expr_map_[0];
  for (size_t i = 0; i < required_cols_.size(); ++i) {
    column_ids.push_back(child_cols_map[required_cols_[i]]);
  }

  auto sort_prop = required_props_->GetPropertyOfType(PropertyType::SORT)
                       ->As<PropertySort>();
  auto sort_columns_size = sort_prop->GetSortColumnSize();
  vector<oid_t> sort_col_ids;
  vector<bool> sort_flags;
  for (size_t i = 0; i < sort_columns_size; ++i) {
    sort_col_ids.push_back(child_cols_map[sort_prop->GetSortColumn(i)]);
    // planner use desc flag
    sort_flags.push_back(!sort_prop->GetSortAscending(i));
  }
  output_plan_.reset(
      new planner::OrderByPlan(sort_col_ids, sort_flags, column_ids));
  output_plan_->AddChild(move(children_plans_[0]));
}

void PlanGenerator::Visit(const PhysicalHashGroupBy *) {}

void PlanGenerator::Visit(const PhysicalSortGroupBy *) {}

void PlanGenerator::Visit(const PhysicalAggregate *) {}

void PlanGenerator::Visit(const PhysicalDistinct *) {}

void PlanGenerator::Visit(const PhysicalFilter *) {}

void PlanGenerator::Visit(const PhysicalInnerNLJoin *) {}

void PlanGenerator::Visit(const PhysicalLeftNLJoin *) {}

void PlanGenerator::Visit(const PhysicalRightNLJoin *) {}

void PlanGenerator::Visit(const PhysicalOuterNLJoin *) {}

void PlanGenerator::Visit(const PhysicalInnerHashJoin *) {}

void PlanGenerator::Visit(const PhysicalLeftHashJoin *) {}

void PlanGenerator::Visit(const PhysicalRightHashJoin *) {}

void PlanGenerator::Visit(const PhysicalOuterHashJoin *) {}

void PlanGenerator::Visit(const PhysicalInsert *op) {
  unique_ptr<planner::AbstractPlan> insert_plan(
      new planner::InsertPlan(op->target_table, op->columns, op->values));
  output_plan_ = move(insert_plan);
}

void PlanGenerator::Visit(const PhysicalInsertSelect *op) {
  unique_ptr<planner::AbstractPlan> insert_plan(
      new planner::InsertPlan(op->target_table));
  // Add child
  insert_plan->AddChild(move(children_plans_[0]));
  output_plan_ = move(insert_plan);
}

void PlanGenerator::Visit(const PhysicalDelete *op) {
  unique_ptr<planner::AbstractPlan> delete_plan(
      new planner::DeletePlan(op->target_table));

  // Add child
  delete_plan->AddChild(move(children_plans_[0]));
  output_plan_ = move(delete_plan);
}

void PlanGenerator::Visit(const PhysicalUpdate *op) {
  DirectMapList dml;
  TargetList tl;
  std::unordered_set<oid_t> update_col_ids;
  auto schema = op->target_table->GetSchema();
  auto table_alias = op->target_table->GetName();
  ExprMap table_expr_map = GenerateTableExprMap(table_alias, op->target_table);

  // Evaluate update expression and add to target list
  for (auto &update : *(op->updates)) {
    auto column = update->column;
    auto col_id = schema->GetColumnID(column);
    if (update_col_ids.find(col_id) != update_col_ids.end())
      throw SyntaxException("Multiple assignments to same column " + column);
    update_col_ids.insert(col_id);
    expression::ExpressionUtil::EvaluateExpression({table_expr_map},
                                                   update->value.get());
    planner::DerivedAttribute attribute{update->value->Copy()};
    tl.emplace_back(col_id, attribute);
  }

  // Add other columns to direct map
  auto col_size = schema->GetColumnCount();
  for (size_t i = 0; i < col_size; i++) {
    if (update_col_ids.find(i) == update_col_ids.end())
      dml.emplace_back(i, std::pair<oid_t, oid_t>(0, i));
  }

  unique_ptr<const planner::ProjectInfo> proj_info(
      new planner::ProjectInfo(move(tl), move(dml)));

  unique_ptr<planner::AbstractPlan> update_plan(
      new planner::UpdatePlan(op->target_table, move(proj_info)));
  update_plan->AddChild(move(children_plans_[0]));
  output_plan_ = move(update_plan);
}

/************************* Private Functions *******************************/
ExprMap PlanGenerator::GenerateTableExprMap(const std::string &alias,
                                            const storage::DataTable *table) {
  ExprMap expr_map;
  auto db_id = table->GetDatabaseOid();
  oid_t table_id = table->GetOid();
  auto cols = table->GetSchema()->GetColumns();
  size_t num_col = cols.size();
  for (oid_t col_id = 0; col_id < num_col; ++col_id) {
    // Only bound_obj_id is needed for expr_map
    // TODO potential memory leak here?
    expression::TupleValueExpression *col_expr =
        new expression::TupleValueExpression(cols[col_id].column_name.c_str(),
                                             alias.c_str());
    col_expr->SetValueType(table->GetSchema()->GetColumn(col_id).GetType());
    col_expr->SetBoundOid(db_id, table_id, col_id);
    expr_map[col_expr] = col_id;
  }
  return expr_map;
}

// Generate columns for scan plan
vector<oid_t> PlanGenerator::GenerateColumnsForScan() {
  vector<oid_t> column_ids;
  for (oid_t idx = 0; idx < output_cols_.size(); ++idx) {
    auto &output_expr = output_cols_[idx];
    PL_ASSERT(output_expr->GetExpressionType() == ExpressionType::VALUE_TUPLE);
    auto output_tvexpr =
        reinterpret_cast<expression::TupleValueExpression *>(output_expr);

    // Set column offset
    PL_ASSERT(output_tvexpr->GetIsBound() == true);
    auto col_id = std::get<2>(output_tvexpr->GetBoundOid());
    column_ids.push_back(col_id);
  }

  return column_ids;
}

std::unique_ptr<expression::AbstractExpression>
PlanGenerator::GeneratePredicateForScan(
    const std::shared_ptr<expression::AbstractExpression> predicate_expr,
    const std::string &alias, const storage::DataTable *table) {
  if (predicate_expr == nullptr) {
    return nullptr;
  }
  ExprMap table_expr_map = GenerateTableExprMap(alias, table);
  unique_ptr<expression::AbstractExpression> predicate =
      std::unique_ptr<expression::AbstractExpression>(predicate_expr->Copy());
  expression::ExpressionUtil::ConvertToTvExpr(predicate.get(), table_expr_map);
  expression::ExpressionUtil::EvaluateExpression({table_expr_map},
                                                 predicate.get());
  return predicate;
}

void PlanGenerator::BuildProjectionPlan() {
  bool no_projection = false;
  if (output_cols_.size() == required_cols_.size()) {
    no_projection = true;
    size_t cols_size = output_cols_.size();
    for (size_t idx = 0; idx < cols_size; ++idx) {
      if (output_cols_[idx] != required_cols_[idx]) {
        no_projection = false;
        break;
      }
    }
  }

  if (no_projection) {
    return;
  }
  vector<ExprMap> output_expr_maps = {ExprMap{}};
  auto &child_expr_map = output_expr_maps[0];
  for (size_t idx = 0; idx < output_cols_.size(); ++idx) {
    auto &col = output_cols_[idx];
    child_expr_map[col] = idx;
  }
  TargetList tl;
  DirectMapList dml;
  vector<catalog::Column> columns;
  for (size_t idx = 0; idx < required_cols_.size(); ++idx) {
    auto &col = required_cols_[idx];
    if (child_expr_map.find(col) != child_expr_map.end()) {
      dml.emplace_back(idx, make_pair(0, child_expr_map[col]));
    } else {
      // Copy then evaluate the expression and add to target list
      auto col_copy = col->Copy();
      expression::ExpressionUtil::ConvertToTvExpr(col_copy, child_expr_map);
      expression::ExpressionUtil::EvaluateExpression(children_expr_map_,
                                                     col_copy);
      planner::DerivedAttribute attribute{col_copy};
      tl.emplace_back(idx, attribute);
    }
    columns.push_back(catalog::Column(
        col->GetValueType(), type::Type::GetTypeSize(col->GetValueType()),
        col->GetExpressionName()));
  }

  unique_ptr<planner::ProjectInfo> proj_info(
      new planner::ProjectInfo(move(tl), move(dml)));
  // TODO since the plan will own the schema, we may not want to use unique_ptr
  // to initialize the plan
  shared_ptr<catalog::Schema> schema_ptr(new catalog::Schema(columns));
  unique_ptr<planner::AbstractPlan> project_plan(
      new planner::ProjectionPlan(move(proj_info), schema_ptr));

  PL_ASSERT(children_plans_.size() < 2);
  if (!children_plans_.empty()) {
    project_plan->AddChild(move(children_plans_[0]));
  }
  output_plan_ = move(project_plan);
}

}  // namespace optimizer
}  // namespace peloton
<|endoftext|>