<commit_before>/*
 * ValueContainerMessage.hpp
 *
 *  Created on: 18.04.2016
 *      Author: Marc Hartung
 */

#ifndef INCLUDE_MESSAGES_VALUECONTAINERMESSAGE_HPP_
#define INCLUDE_MESSAGES_VALUECONTAINERMESSAGE_HPP_

#include "AbstractMessage.hpp"
#include "../network_impl/SimNetworkFunctions.hpp"
#include "../VariableList.hpp"
#include "../ValueContainer.hpp"

namespace NetOff
{

    template<typename Specifyer>
    class ValueContainerMessage : public AbstractMessage<Specifyer>
    {
     public:

        ValueContainerMessage(const int & simId, const VariableList & vars, const Specifyer & spec)
                : AbstractMessage<Specifyer>(spec),
                  _data(nullptr),
                  _dataSize(0),
                  _spec(nullptr),
                  _id(nullptr),
                  _time(nullptr),
                  _container()
        {
            _dataSize = sizeof(Specifyer) + sizeof(int) + sizeof(double)
                    + ValueContainer::calcDataSize(vars.getReals().size(), vars.getInts().size(), vars.getBools().size());
            _data = std::shared_ptr<char>(new char[_dataSize]);
            char * p = _data.get();
            _spec = reinterpret_cast<Specifyer *>(p);
            p = saveShiftIntegralInData<Specifyer>(spec, p);
            _id = reinterpret_cast<int *>(p);
            p = saveShiftIntegralInData(simId, p);
            _time = reinterpret_cast<double *>(p);
            p = saveShiftIntegralInData<double>(0.0,p);
            _container = ValueContainer(_data, p, vars.getReals().size(), vars.getInts().size(), vars.getBools().size(),simId);
        }

        ValueContainerMessage()
                : AbstractMessage<Specifyer>(),
                  _data(nullptr),
                  _dataSize(0),
                  _spec(nullptr),
                  _id(nullptr),
                  _time(nullptr),
                  _container()
        {
            _data = std::shared_ptr<char>(new char[_dataSize]);
        }

        ValueContainer & getContainer()
        {
            return _container;
        }

        const ValueContainer & getContainer() const
        {
            return _container;
        }

        void setTime(const double & time)
        {
            *_time = time;
        }

        void setSpecifyer(const Specifyer & spec)
        {
            *_spec = spec;
        }

        const int & getId() const
        {
            return *_id;
        }

        const double & getTime() const
        {
            return *_time;
        }

        const Specifyer getSpecifyer() const
        {
            return *_spec;
        }

        char * data() override
        {
            return _data.get();
        }

        const char * data() const override
        {
            return _data.get();
        }

        size_t dataSize() const override
        {
            return _dataSize;
        }

     private:

        std::shared_ptr<char> _data;
        size_t _dataSize;

        Specifyer * _spec;
        int * _id;
        double * _time;

        ValueContainer _container;

    };
}

#endif /* INCLUDE_MESSAGES_VALUECONTAINERMESSAGE_HPP_ */
<commit_msg>Implement copy and assignment operator<commit_after>/*
 * ValueContainerMessage.hpp
 *
 *  Created on: 18.04.2016
 *      Author: Marc Hartung
 */

#ifndef INCLUDE_MESSAGES_VALUECONTAINERMESSAGE_HPP_
#define INCLUDE_MESSAGES_VALUECONTAINERMESSAGE_HPP_

#include "AbstractMessage.hpp"
#include "network_impl/SimNetworkFunctions.hpp"
#include "VariableList.hpp"
#include "ValueContainer.hpp"

namespace NetOff
{

    template<typename Specifyer>
    class ValueContainerMessage : public AbstractMessage<Specifyer>
    {
     public:

        ValueContainerMessage(const int & simId, const VariableList & vars, const Specifyer & spec)
                : AbstractMessage<Specifyer>(spec),
                  _data(nullptr),
                  _dataSize(0),
                  _spec(nullptr),
                  _id(nullptr),
                  _time(nullptr),
                  _container()
        {
            _dataSize = sizeof(Specifyer) + sizeof(int) + sizeof(double)
                    + ValueContainer::calcDataSize(vars.getReals().size(), vars.getInts().size(),
                                                   vars.getBools().size());
            _data = std::shared_ptr<char>(new char[_dataSize], std::default_delete<char[]>());
            char * p = _data.get();
            _spec = reinterpret_cast<Specifyer *>(p);
            p = saveShiftIntegralInData<Specifyer>(spec, p);
            _id = reinterpret_cast<int *>(p);
            p = saveShiftIntegralInData(simId, p);
            _time = reinterpret_cast<double *>(p);
            p = saveShiftIntegralInData<double>(0.0, p);
            _container = ValueContainer(_data, p, vars.getReals().size(), vars.getInts().size(), vars.getBools().size(),
                                        simId);
        }

        ValueContainerMessage()
                : AbstractMessage<Specifyer>(),
                  _data(nullptr),
                  _dataSize(0),
                  _spec(nullptr),
                  _id(nullptr),
                  _time(nullptr),
                  _container()
        {
        }

        ValueContainerMessage(ValueContainerMessage && in)
                : ValueContainerMessage()
        {
            *this = std::move(in);
        }

        ValueContainerMessage & operator=(ValueContainerMessage && in)
        {
            std::swap(_data, in._data);
            std::swap(_dataSize, in._dataSize);
            std::swap(_spec, in._spec);
            std::swap(_id, in._id);
            std::swap(_time, in._time);
            std::swap(_container, in._container);
            return *this;
        }

        ~ValueContainerMessage() = default;

        ValueContainer & getContainer()
        {
            return _container;
        }

        const ValueContainer & getContainer() const
        {
            return _container;
        }

        void setTime(const double & time)
        {
            *_time = time;
        }

        void setSpecifyer(const Specifyer & spec)
        {
            *_spec = spec;
        }

        const int & getId() const
        {
            return *_id;
        }

        const double & getTime() const
        {
            return *_time;
        }

        const Specifyer getSpecifyer() const
        {
            return *_spec;
        }

        char * data() override
        {
            return _data.get();
        }

        const char * data() const override
        {
            return _data.get();
        }

        size_t dataSize() const override
        {
            return _dataSize;
        }

     private:

        std::shared_ptr<char> _data;
        size_t _dataSize;

        Specifyer * _spec;
        int * _id;
        double * _time;

        ValueContainer _container;

    };
}

#endif /* INCLUDE_MESSAGES_VALUECONTAINERMESSAGE_HPP_ */
<|endoftext|>


<commit_before>// ui_Qt_run.C -- Qt based top level user interface for running a program.
//
// Copyright 2007 Per Abrahamsen and KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy 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 Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "ui_Qt_run.h"
#include "log_Qt.h"
#include "run_Qt.h"
#include "time.h"
#include "toplevel.h"
#include "program.h"
#include "metalib.h"
#include "library.h"
#include "librarian.h"
#include "block_top.h"
#include "assertion.h"
#include "path.h"
#include "treelog.h"
#include "frame_submodel.h"
#include <sstream>

#include <QtGui/QMenuBar>
#include <QtGui/QFileDialog>
#include <QtGui/QStatusBar>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QCheckBox>

struct UIRun::WidgetState
{
  QPointer<QWidget> widget;
  const std::string active_tip;
  const std::string inactive_tip;
  const bool notify;
  std::vector<Toplevel::state_t> active_state;

  WidgetState (QWidget *const w, const std::string& a, const std::string& i,
	       const bool n)
    : widget (w),
      active_tip (a),
      inactive_tip (i),
      notify (n)
  { }
};

void
UIRun::manage_widget (QWidget* widget, const std::string& active_tip,
		      const std::string& inactive_tip, bool notify)
{
  for (size_t i = 0; i < widget_state.size (); i++)
    daisy_assert (widget != widget_state[i]->widget);

  widget_state.push_back (new WidgetState (widget,
					   active_tip, inactive_tip, notify));
}

void
UIRun::manage_widget_active (QWidget* widget, Toplevel::state_t state)
{
  for (size_t i = 0; i < widget_state.size (); i++)
    if (widget == widget_state[i]->widget)
      {
	widget_state[i]->active_state.push_back (state);
	return;
      }
  daisy_notreached ();
}

void
UIRun::build_log (Metalib& metalib, Block& block, const std::string& name)
{
  const symbol id (name);
  const std::map<symbol, LogQt*>::const_iterator i = logs.find (id);
  if (i != logs.end ())
    return;

  Treelog& msg = block.msg ();

  const Library& library = metalib.library (Log::component);
  if (!library.complete (metalib, id))
    return;

  std::auto_ptr<Log> log_raw
    (Librarian::build_stock<Log> (metalib, msg, id, __FUNCTION__));
  LogQt *const log = dynamic_cast<LogQt*> (log_raw.get ());
  if (log)
    {
      log->initialize_common (metalib, msg);
      all_logs.push_back (log);
      logs[id] = log;
      log_raw.release ();
      msg.debug ("Qt log '" + name + "' attached.");
    }
}

bool
UIRun::attach_log (const std::string& name, VisQtLog *const vis) const
{
  const symbol id (name);
  const std::map<symbol, LogQt*>::const_iterator i = logs.find (id);
  if (i == logs.end ())
    return false;

  vis->attach_log ((*i).second);
  return true;
}

void
UIRun::attach (Toplevel& toplevel)
{
  daisy_assert (top_level == NULL);
  top_level = &toplevel;

  // We start by loading special log used by UI.
  try
    {
      if (!has_loaded_log_file
          && toplevel.state () == Toplevel::is_uninitialized)
        {
          has_loaded_log_file = true;
          toplevel.parse_system_file ("ui-Qt.dai");
        }
    }
  catch (...)
    { toplevel.msg ().warning ("Problems loading utility file 'ui-Qt.dai'"); }

  // Build log.
  {
    BlockTop block (toplevel.metalib (), toplevel.msg (),
                    toplevel.metalib ());
    build_log (toplevel.metalib (), block, "QtTime");
  }

  // Fetch data.
  const Frame& frame = toplevel.program_frame ();

  // Attach menubar.
  QMenuBar* menuBar = qt_main.menuBar ();

  // Create File menu.
  QMenu* fileMenu = menuBar->addMenu ("&File");

  // Open setup.
  QAction* openAction = new QAction ("&Open setup...", this);
  openAction->setToolTip ("Open a setup file");
  connect (openAction, SIGNAL(triggered()), this, SLOT(open_setup()));
  fileMenu->addAction (openAction);

  // Run setup.
  QAction* runAction = new QAction ("&Run", this);
  runAction->setToolTip ("Run the selected program.");
  connect (runAction, SIGNAL(triggered()), this, SLOT(run_program()));
  fileMenu->addAction (runAction);

  // We organize items in a boxes.
  QWidget *const center = new QWidget (&qt_main);
  QVBoxLayout *const layout = new QVBoxLayout (center);

  // The top line.
  QHBoxLayout *const top_layout = new QHBoxLayout;
  layout->addLayout (top_layout);

  // The program name.
  qt_name->setToolTip ("The name of the program or simulation to run.");
  QFont font = qt_name->font ();
  font.setBold (true);
  qt_name->setFont (font);
  const symbol type_name = frame.type_name ();
  if (type_name != Attribute::None ())
    qt_name->setText (type_name.name ().c_str ());
  else
    qt_name->setText ("No program");
  top_layout->addWidget (qt_name /* , Qt::AlignLeft */);
  top_layout->addStretch ();

  // The simulation time.
  VisQtTime *const qt_time = new VisQtTime;
  qt_time->setToolTip ("The simulation time.");
  if (frame.check ("time")
      && frame.lookup ("time") == Attribute::Submodel
      && frame.type_size ("time") == Attribute::Singleton
      && frame.check (toplevel.metalib (), "time", Treelog::null ()))
    {
      Time time (frame.submodel ("time"));
      qt_time->set_time (time);
    }
  if (!attach_log ("QtTime", qt_time)
      && toplevel.state () == Toplevel::is_uninitialized)
    toplevel.msg ().warning ("Log 'QtTime' not found"
                             ", user interface may be crippled");
  top_layout->addWidget (qt_time /* , Qt::AlignCenter */);

  // The file name.
  const std::vector<std::string> files = toplevel.files_found ();
  switch (files.size ())
    {
    case 0:
      qt_file->setToolTip ("No file has been loaded.");
      qt_file->setText ("No file");
      break;
    case 1:
      qt_file->setToolTip ("This is the name of the loaded file.");
      qt_file->setText (files[0].c_str ());
      break;
    default:
      qt_file->setToolTip ("Multiple files have been loaded.");
      qt_file->setText ("Multiple files");
    }
  top_layout->addStretch ();
  top_layout->addWidget (qt_file /* , Qt::AlignRight */);

  // The program description.
  qt_description->setToolTip ("The description of the selected program.");
  if (frame.description () != Attribute::None ()
      && frame.description () != Toplevel::default_description)
    qt_description->setText (frame.description ().name ().c_str ());
  else
    qt_description->hide (); // setText ("No description.");
  layout->addWidget (qt_description /* , Qt::AlignLeft */);

  // A text window for simulation messages.
  // Use a special treelog to relay messages to window.
  TreelogQtText* tlog = new TreelogQtText;
  VisQtText *const qt_vis = new VisQtText;
  qt_vis->setToolTip ("Textual feedback from the program.");
  QObject::connect(tlog->tracker (), SIGNAL(text_ready (std::string)),
                   qt_vis, SLOT(new_text (std::string)));
  boost::shared_ptr<Treelog> tlog_share (tlog);
  toplevel.add_treelog (tlog_share);
  layout->addWidget (qt_vis);

  // The bottom line
  QWidget *const bottom = new QWidget (center);
  QHBoxLayout *const bottom_layout = new QHBoxLayout (bottom);
  layout->addWidget (bottom);

  // Emergency stop.
  qt_stop = new QPushButton ("Stop");
  qt_stop->setToolTip ("Press here to stop the program.");
  qt_stop->setDisabled (true);
  bottom_layout->addWidget (qt_stop);
  bottom_layout->addStretch ();
  daisy_assert (!qt_stop.isNull ());
  // Track newest messages.
  QCheckBox *const qt_track = new QCheckBox ("Track");
  qt_track->setToolTip ("Check this box to always show new text.");
  QObject::connect(qt_track, SIGNAL(stateChanged (int)),
                   qt_vis, SLOT(track_tracking (int)));
  qt_track->setCheckState (Qt::Checked);
  bottom_layout->addWidget (qt_track /* , Qt::AlignCenter */);

  // Dismiss window.
  QPushButton *const qt_dismiss = new QPushButton ("Dismiss");
  qt_dismiss->setToolTip ("Press here to end the application.");
  QObject::connect(qt_dismiss, SIGNAL(clicked ()),
                   &qt_main, SLOT(close ()));
  bottom_layout->addStretch ();
  bottom_layout->addWidget (qt_dismiss);

  // All of this in our central widget.
  qt_main.setCentralWidget (center);

  // A progress bar in the bottom.
  qt_progress = new VisQtProgress;
  qt_progress->setToolTip ("Display progress of program.");
  QObject::connect(tlog->tracker (), SIGNAL(error_occured ()),
                   qt_progress, SLOT(found_error ()));
  qt_progress->new_state (toplevel.state ());
  qt_main.statusBar ()->addPermanentWidget (qt_progress);

  // The title.
  if (files.size () == 1)
    qt_main.set_file_name (files[0].c_str ());
  else
    qt_main.set_file_name ("");
  qt_main.set_title ();

  // Show it all.
  qt_main.show ();
}

void
UIRun::run_program ()
{
  // New thread.
  daisy_assert (qt_run.isNull ());
  qt_run = new RunQtMain (*top_level, all_logs);
  daisy_assert (!qt_run.isNull ());

  // Progress bar.
  daisy_assert (!qt_progress.isNull ());
  QObject::connect(qt_run, SIGNAL(progress_changed (double)),
		   qt_progress, SLOT(new_progress (double)));
  QObject::connect(qt_run, SIGNAL(progress_state (Toplevel::state_t)),
		   qt_progress, SLOT(new_state (Toplevel::state_t)));

  // Main window.
  QObject::connect(qt_run, SIGNAL(progress_changed (double)),
		   &qt_main, SLOT(new_progress (double)));
  QObject::connect(qt_run, SIGNAL(progress_state (Toplevel::state_t)),
		   &qt_main, SLOT(new_state (Toplevel::state_t)));
  QObject::connect(&qt_main, SIGNAL(stop_program ()),
		   this, SLOT(stop_program ()));

  // Stop button.
  daisy_assert (!qt_stop.isNull ());
  QObject::connect(qt_run, SIGNAL(is_now_running (bool)),
		   qt_stop, SLOT(setEnabled (bool)));
  QObject::connect(qt_stop, SIGNAL(clicked ()),
		   qt_run, SLOT(stop ()));

  // Start thread.
  qt_run->start (QThread::QThread::IdlePriority);
}

void
UIRun::stop_program ()
{
  if (!qt_run.isNull ())
    {
      qt_run->stop ();              // Tell program to stop.
      qt_run->wait ();              // Wait for it to happen.
      daisy_assert (qt_run->isFinished ());
      delete qt_run;
      qt_run = NULL;
    }
  if (!qt_run.isNull ())
    daisy_bug ("qt_run should be NULL after process has been stopped");
}

void
UIRun::run (Toplevel& toplevel)
{

  run_user_interface ();	// Start the UI.
  if (!qt_run.isNull ())
    daisy_bug ("qt_run should be NULL after user interface has finished");
}

void
UIRun::failure (Toplevel& toplevel)
{

  run_user_interface ();	// Start the UI.
  stop_program ();		// Stop the simulation.
}

void
UIRun::reset ()
{
  // Fetch data.
  daisy_assert (top_level);
  const Frame& frame = top_level->program_frame ();
  const std::vector<std::string> files = top_level->files_found ();

  // The program name.
  const symbol type_name = frame.type_name ();
  if (type_name != Attribute::None ())
    qt_name->setText (type_name.name ().c_str ());
  else
    qt_name->setText ("No program");

  // The file name.
  switch (files.size ())
    {
    case 0:
      qt_file->setToolTip ("No setup file has been loaded.");
      qt_file->setText ("No file");
      break;
    case 1:
      qt_file->setToolTip ("This is the name of the loaded setup file.");
      qt_file->setText (Path::nodir (files[0]).name ().c_str ());
      break;
    default:
      qt_file->setToolTip ("Multiple setup files have been loaded.");
      qt_file->setText ("Multiple files");
    }

  // The program description.
  if (frame.description () != Attribute::None ()
      && frame.description () != Toplevel::default_description)
    qt_description->setText (frame.description ().name ().c_str ());
  else
    qt_description->setText ("No setup file has been loaded.\n\
You can drag a setup file to the Daisy icon to run a simulation.");

  // The title.
  if (files.size () == 1)
    qt_main.set_file_name (Path::nodir (files[0]).name ().c_str ());
  else
    qt_main.set_file_name ("");
  qt_main.set_title ();
}

void
UIRun::open_setup ()
{
  QString fileName
    = QFileDialog::getOpenFileName (this,
				    "Open Daisy Setup", NULL,
				    "Daisy Setup Files (*.dai)");

  if (!fileName.isEmpty())
    {
      qt_main.statusBar ()->showMessage ("Loading...");
      top_level->reset ();
      top_level->parse_file (fileName.toStdString ());
      reset ();
      qt_main.statusBar ()->showMessage ("Setup loaded", 2000);
    }
}

UIRun::UIRun (const BlockModel& al)
  : UIQt (al),
    qt_main (application_name ()),
    qt_name (new QLabel),
    qt_file (new QLabel),
    qt_description (new QLabel),
    has_loaded_log_file (false),
    top_level (NULL)
{ }

UIRun::~UIRun ()
{ stop_program (); }

static struct UIRunSyntax : public DeclareModel
{
  Model* make (const BlockModel& al) const
  { return new UIRun (al); }

  UIRunSyntax ()
    : DeclareModel (UI::component, "GUI", "Run the program in a window.")
  { }
  void load_frame (Frame& frame) const
  {

  }
} UIRun_syntax;

// ui_Qt_run.C ends here.
<commit_msg>x61<commit_after>// ui_Qt_run.C -- Qt based top level user interface for running a program.
//
// Copyright 2007 Per Abrahamsen and KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy 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 Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "ui_Qt_run.h"
#include "log_Qt.h"
#include "run_Qt.h"
#include "time.h"
#include "toplevel.h"
#include "program.h"
#include "metalib.h"
#include "library.h"
#include "librarian.h"
#include "block_top.h"
#include "assertion.h"
#include "path.h"
#include "treelog.h"
#include "frame_submodel.h"
#include <sstream>

#include <QtGui/QMenuBar>
#include <QtGui/QFileDialog>
#include <QtGui/QStatusBar>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QCheckBox>

struct UIRun::WidgetState
{
  QPointer<QWidget> widget;
  const std::string active_tip;
  const std::string inactive_tip;
  const bool notify;
  std::vector<Toplevel::state_t> active_state;

  WidgetState (QWidget *const w, const std::string& a, const std::string& i,
	       const bool n)
    : widget (w),
      active_tip (a),
      inactive_tip (i),
      notify (n)
  { }
};

void
UIRun::manage_widget (QWidget* widget, const std::string& active_tip,
		      const std::string& inactive_tip, bool notify)
{
  for (size_t i = 0; i < widget_state.size (); i++)
    daisy_assert (widget != widget_state[i]->widget);

  widget_state.push_back (new WidgetState (widget,
					   active_tip, inactive_tip, notify));
}

void
UIRun::manage_widget_active (QWidget* widget, Toplevel::state_t state)
{
  for (size_t i = 0; i < widget_state.size (); i++)
    if (widget == widget_state[i]->widget)
      {
	widget_state[i]->active_state.push_back (state);
	return;
      }
  daisy_notreached ();
}

void
UIRun::build_log (Metalib& metalib, Block& block, const std::string& name)
{
  const symbol id (name);
  const std::map<symbol, LogQt*>::const_iterator i = logs.find (id);
  if (i != logs.end ())
    return;

  Treelog& msg = block.msg ();

  const Library& library = metalib.library (Log::component);
  if (!library.complete (metalib, id))
    return;

  std::auto_ptr<Log> log_raw
    (Librarian::build_stock<Log> (metalib, msg, id, __FUNCTION__));
  LogQt *const log = dynamic_cast<LogQt*> (log_raw.get ());
  if (log)
    {
      log->initialize_common (id, metalib, msg);
      all_logs.push_back (log);
      logs[id] = log;
      log_raw.release ();
      msg.debug ("Qt log '" + name + "' attached.");
    }
}

bool
UIRun::attach_log (const std::string& name, VisQtLog *const vis) const
{
  const symbol id (name);
  const std::map<symbol, LogQt*>::const_iterator i = logs.find (id);
  if (i == logs.end ())
    return false;

  vis->attach_log ((*i).second);
  return true;
}

void
UIRun::attach (Toplevel& toplevel)
{
  daisy_assert (top_level == NULL);
  top_level = &toplevel;

  // We start by loading special log used by UI.
  try
    {
      if (!has_loaded_log_file
          && toplevel.state () == Toplevel::is_uninitialized)
        {
          has_loaded_log_file = true;
          toplevel.parse_system_file ("ui-Qt.dai");
        }
    }
  catch (...)
    { toplevel.msg ().warning ("Problems loading utility file 'ui-Qt.dai'"); }

  // Build log.
  {
    BlockTop block (toplevel.metalib (), toplevel.msg (),
                    toplevel.metalib ());
    build_log (toplevel.metalib (), block, "QtTime");
  }

  // Fetch data.
  const Frame& frame = toplevel.program_frame ();

  // Attach menubar.
  QMenuBar* menuBar = qt_main.menuBar ();

  // Create File menu.
  QMenu* fileMenu = menuBar->addMenu ("&File");

  // Open setup.
  QAction* openAction = new QAction ("&Open setup...", this);
  openAction->setToolTip ("Open a setup file");
  connect (openAction, SIGNAL(triggered()), this, SLOT(open_setup()));
  fileMenu->addAction (openAction);

  // Run setup.
  QAction* runAction = new QAction ("&Run", this);
  runAction->setToolTip ("Run the selected program.");
  connect (runAction, SIGNAL(triggered()), this, SLOT(run_program()));
  fileMenu->addAction (runAction);

  // We organize items in a boxes.
  QWidget *const center = new QWidget (&qt_main);
  QVBoxLayout *const layout = new QVBoxLayout (center);

  // The top line.
  QHBoxLayout *const top_layout = new QHBoxLayout;
  layout->addLayout (top_layout);

  // The program name.
  qt_name->setToolTip ("The name of the program or simulation to run.");
  QFont font = qt_name->font ();
  font.setBold (true);
  qt_name->setFont (font);
  const symbol type_name = frame.type_name ();
  if (type_name != Attribute::None ())
    qt_name->setText (type_name.name ().c_str ());
  else
    qt_name->setText ("No program");
  top_layout->addWidget (qt_name /* , Qt::AlignLeft */);
  top_layout->addStretch ();

  // The simulation time.
  VisQtTime *const qt_time = new VisQtTime;
  qt_time->setToolTip ("The simulation time.");
  if (frame.check ("time")
      && frame.lookup ("time") == Attribute::Submodel
      && frame.type_size ("time") == Attribute::Singleton
      && frame.check (toplevel.metalib (), "time", Treelog::null ()))
    {
      Time time (frame.submodel ("time"));
      qt_time->set_time (time);
    }
  if (!attach_log ("QtTime", qt_time)
      && toplevel.state () == Toplevel::is_uninitialized)
    toplevel.msg ().warning ("Log 'QtTime' not found"
                             ", user interface may be crippled");
  top_layout->addWidget (qt_time /* , Qt::AlignCenter */);

  // The file name.
  const std::vector<std::string> files = toplevel.files_found ();
  switch (files.size ())
    {
    case 0:
      qt_file->setToolTip ("No file has been loaded.");
      qt_file->setText ("No file");
      break;
    case 1:
      qt_file->setToolTip ("This is the name of the loaded file.");
      qt_file->setText (files[0].c_str ());
      break;
    default:
      qt_file->setToolTip ("Multiple files have been loaded.");
      qt_file->setText ("Multiple files");
    }
  top_layout->addStretch ();
  top_layout->addWidget (qt_file /* , Qt::AlignRight */);

  // The program description.
  qt_description->setToolTip ("The description of the selected program.");
  if (frame.description () != Attribute::None ()
      && frame.description () != Toplevel::default_description)
    qt_description->setText (frame.description ().name ().c_str ());
  else
    qt_description->hide (); // setText ("No description.");
  layout->addWidget (qt_description /* , Qt::AlignLeft */);

  // A text window for simulation messages.
  // Use a special treelog to relay messages to window.
  TreelogQtText* tlog = new TreelogQtText;
  VisQtText *const qt_vis = new VisQtText;
  qt_vis->setToolTip ("Textual feedback from the program.");
  QObject::connect(tlog->tracker (), SIGNAL(text_ready (std::string)),
                   qt_vis, SLOT(new_text (std::string)));
  boost::shared_ptr<Treelog> tlog_share (tlog);
  toplevel.add_treelog (tlog_share);
  layout->addWidget (qt_vis);

  // The bottom line
  QWidget *const bottom = new QWidget (center);
  QHBoxLayout *const bottom_layout = new QHBoxLayout (bottom);
  layout->addWidget (bottom);

  // Emergency stop.
  qt_stop = new QPushButton ("Stop");
  qt_stop->setToolTip ("Press here to stop the program.");
  qt_stop->setDisabled (true);
  bottom_layout->addWidget (qt_stop);
  bottom_layout->addStretch ();
  daisy_assert (!qt_stop.isNull ());
  // Track newest messages.
  QCheckBox *const qt_track = new QCheckBox ("Track");
  qt_track->setToolTip ("Check this box to always show new text.");
  QObject::connect(qt_track, SIGNAL(stateChanged (int)),
                   qt_vis, SLOT(track_tracking (int)));
  qt_track->setCheckState (Qt::Checked);
  bottom_layout->addWidget (qt_track /* , Qt::AlignCenter */);

  // Dismiss window.
  QPushButton *const qt_dismiss = new QPushButton ("Dismiss");
  qt_dismiss->setToolTip ("Press here to end the application.");
  QObject::connect(qt_dismiss, SIGNAL(clicked ()),
                   &qt_main, SLOT(close ()));
  bottom_layout->addStretch ();
  bottom_layout->addWidget (qt_dismiss);

  // All of this in our central widget.
  qt_main.setCentralWidget (center);

  // A progress bar in the bottom.
  qt_progress = new VisQtProgress;
  qt_progress->setToolTip ("Display progress of program.");
  QObject::connect(tlog->tracker (), SIGNAL(error_occured ()),
                   qt_progress, SLOT(found_error ()));
  qt_progress->new_state (toplevel.state ());
  qt_main.statusBar ()->addPermanentWidget (qt_progress);

  // The title.
  if (files.size () == 1)
    qt_main.set_file_name (files[0].c_str ());
  else
    qt_main.set_file_name ("");
  qt_main.set_title ();

  // Show it all.
  qt_main.show ();
}

void
UIRun::run_program ()
{
  // New thread.
  daisy_assert (qt_run.isNull ());
  qt_run = new RunQtMain (*top_level, all_logs);
  daisy_assert (!qt_run.isNull ());

  // Progress bar.
  daisy_assert (!qt_progress.isNull ());
  QObject::connect(qt_run, SIGNAL(progress_changed (double)),
		   qt_progress, SLOT(new_progress (double)));
  QObject::connect(qt_run, SIGNAL(progress_state (Toplevel::state_t)),
		   qt_progress, SLOT(new_state (Toplevel::state_t)));

  // Main window.
  QObject::connect(qt_run, SIGNAL(progress_changed (double)),
		   &qt_main, SLOT(new_progress (double)));
  QObject::connect(qt_run, SIGNAL(progress_state (Toplevel::state_t)),
		   &qt_main, SLOT(new_state (Toplevel::state_t)));
  QObject::connect(&qt_main, SIGNAL(stop_program ()),
		   this, SLOT(stop_program ()));

  // Stop button.
  daisy_assert (!qt_stop.isNull ());
  QObject::connect(qt_run, SIGNAL(is_now_running (bool)),
		   qt_stop, SLOT(setEnabled (bool)));
  QObject::connect(qt_stop, SIGNAL(clicked ()),
		   qt_run, SLOT(stop ()));

  // Start thread.
  qt_run->start (QThread::QThread::IdlePriority);
}

void
UIRun::stop_program ()
{
  if (!qt_run.isNull ())
    {
      qt_run->stop ();              // Tell program to stop.
      qt_run->wait ();              // Wait for it to happen.
      daisy_assert (qt_run->isFinished ());
      delete qt_run;
      qt_run = NULL;
    }
  if (!qt_run.isNull ())
    daisy_bug ("qt_run should be NULL after process has been stopped");
}

void
UIRun::run (Toplevel& toplevel)
{

  run_user_interface ();	// Start the UI.
  if (!qt_run.isNull ())
    daisy_bug ("qt_run should be NULL after user interface has finished");
}

void
UIRun::failure (Toplevel& toplevel)
{

  run_user_interface ();	// Start the UI.
  stop_program ();		// Stop the simulation.
}

void
UIRun::reset ()
{
  // Fetch data.
  daisy_assert (top_level);
  const Frame& frame = top_level->program_frame ();
  const std::vector<std::string> files = top_level->files_found ();

  // The program name.
  const symbol type_name = frame.type_name ();
  if (type_name != Attribute::None ())
    qt_name->setText (type_name.name ().c_str ());
  else
    qt_name->setText ("No program");

  // The file name.
  switch (files.size ())
    {
    case 0:
      qt_file->setToolTip ("No setup file has been loaded.");
      qt_file->setText ("No file");
      break;
    case 1:
      qt_file->setToolTip ("This is the name of the loaded setup file.");
      qt_file->setText (Path::nodir (files[0]).name ().c_str ());
      break;
    default:
      qt_file->setToolTip ("Multiple setup files have been loaded.");
      qt_file->setText ("Multiple files");
    }

  // The program description.
  if (frame.description () != Attribute::None ()
      && frame.description () != Toplevel::default_description)
    qt_description->setText (frame.description ().name ().c_str ());
  else
    qt_description->setText ("No setup file has been loaded.\n\
You can drag a setup file to the Daisy icon to run a simulation.");

  // The title.
  if (files.size () == 1)
    qt_main.set_file_name (Path::nodir (files[0]).name ().c_str ());
  else
    qt_main.set_file_name ("");
  qt_main.set_title ();
}

void
UIRun::open_setup ()
{
  QString fileName
    = QFileDialog::getOpenFileName (this,
				    "Open Daisy Setup", NULL,
				    "Daisy Setup Files (*.dai)");

  if (!fileName.isEmpty())
    {
      qt_main.statusBar ()->showMessage ("Loading...");
      top_level->reset ();
      top_level->parse_file (fileName.toStdString ());
      reset ();
      qt_main.statusBar ()->showMessage ("Setup loaded", 2000);
    }
}

UIRun::UIRun (const BlockModel& al)
  : UIQt (al),
    qt_main (application_name ()),
    qt_name (new QLabel),
    qt_file (new QLabel),
    qt_description (new QLabel),
    has_loaded_log_file (false),
    top_level (NULL)
{ }

UIRun::~UIRun ()
{ stop_program (); }

static struct UIRunSyntax : public DeclareModel
{
  Model* make (const BlockModel& al) const
  { return new UIRun (al); }

  UIRunSyntax ()
    : DeclareModel (UI::component, "GUI", "Run the program in a window.")
  { }
  void load_frame (Frame& frame) const
  {

  }
} UIRun_syntax;

// ui_Qt_run.C ends here.
<|endoftext|>


<commit_before>/************************************************************************/
/*                                                                      */
/*     Copyright 2011-2012 Stefan Schmidt and Ullrich Koethe            */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

/**
 * This header provides definitions of graph-related types
 * and optionally provides a gateway to popular graph libraries
 * (for now, BGL is supported).
 */

#ifndef VIGRA_GRAPH_HXX
#define VIGRA_GRAPH_HXX

#include "metaprogramming.hxx"
#include "tinyvector.hxx"

#ifdef WITH_BOOST_GRAPH

#  include <boost/tuple/tuple.hpp>
#  include <boost/graph/graph_traits.hpp>
#  include <boost/graph/properties.hpp>

#else // not WITH_BOOST_GRAPH

// emulate the BGL-style interface
namespace boost {

struct no_property {};

// tag classes were copied from boost:
// directed_category tags
struct directed_tag { };
struct undirected_tag { };
struct bidirectional_tag : public directed_tag { };

// traversal_category tags
struct incidence_graph_tag { };
struct adjacency_graph_tag { };
struct bidirectional_graph_tag : public incidence_graph_tag { };
struct vertex_list_graph_tag { };
struct edge_list_graph_tag { };
struct adjacency_matrix_tag { };

// edge_parallel_category tags
struct allow_parallel_edge_tag { };
struct disallow_parallel_edge_tag { };

// property maps:
struct readable_property_map_tag { };
struct writable_property_map_tag { };
struct read_write_property_map_tag
    : public readable_property_map_tag,
      public writable_property_map_tag {};
struct lvalue_property_map_tag
    : public read_write_property_map_tag {};

struct vertex_index_t {};

struct edge_property_tag {};

#ifndef BOOST_TUPLE_HPP

// tie() support for std::pair, similar to Boost's one:
// (necessary because std::pair doesn't define a suitable assignment operator)
template<class T1, class T2>
class tie_adapter
{
  public:
    tie_adapter(T1 &x, T2 &y)
        : x_(x), y_(y)
    {}

    template<class X, class Y>
    tie_adapter & operator=(const std::pair<X, Y> &pair)
    {
        x_ = pair.first;
        y_ = pair.second;
        return *this;
    }

  protected:
    T1 &x_;
    T2 &y_;
};

template<class T1, class T2>
inline
tie_adapter<T1, T2>
tie(T1& t1, T2& t2)
{
    return tie_adapter<T1, T2>(t1, t2);
}
#endif

// graph_traits class template
template <typename G>
struct graph_traits {
    typedef typename G::vertex_descriptor      vertex_descriptor;
    typedef typename G::edge_descriptor        edge_descriptor;
    typedef typename G::adjacency_iterator     adjacency_iterator;
    typedef typename G::out_edge_iterator      out_edge_iterator;
    typedef typename G::in_edge_iterator       in_edge_iterator;
    typedef typename G::vertex_iterator        vertex_iterator;
    typedef typename G::edge_iterator          edge_iterator;

    typedef typename G::directed_category      directed_category;
    typedef typename G::edge_parallel_category edge_parallel_category;
    typedef typename G::traversal_category     traversal_category;

    typedef typename G::vertices_size_type     vertices_size_type;
    typedef typename G::edges_size_type        edges_size_type;
    typedef typename G::degree_size_type       degree_size_type;

    static inline vertex_descriptor null_vertex()
    {
        return vertex_descriptor(-1);
    }
};

// property_traits class template
template <typename PropMap>
struct property_traits
{
    typedef typename PropMap::key_type    key_type;
    typedef typename PropMap::value_type  value_type;
    typedef typename PropMap::reference   reference;
    typedef typename PropMap::category    category;
};

} // namespace boost

#endif // WITH_BOOST_GRAPH

namespace vigra {
namespace boost_graph {

// vigra::boost_graph contains algorithms that are compatible to the Boost Graph Library
using namespace boost;

}} // namespace vigra::boost_graph

#if 0
namespace vigragraph {

// custom get_helper for read-only property maps (by-value)

template <class ValueType, class ReadablePropertyMap>
struct get_helper { };

template <class PropertyMap, class ValueType, class K>
inline ValueType
get(const get_helper<ValueType, PropertyMap>& pa, const K& k)
{
    const ValueType v = static_cast<const PropertyMap&>(pa)[k];
    return v;
}

// ! A fallback template for adjacent_vertices() called with
// a vertex_iterator
// (which may be specialized to be implemented more efficiently;
//  the reason is that the iterator may have more information than
//  the plain vertex_descriptor, e.g. it knows the neighborhood
//  already which otherwise needs to be reconstructed.)
template<class GRAPH>
inline
std::pair<typename graph_traits<GRAPH>::adjacency_iterator,
          typename graph_traits<GRAPH>::adjacency_iterator >
adjacent_vertices_at_iterator(typename graph_traits<GRAPH>::vertex_iterator const &v,
                              GRAPH const &g)
{
    // the default implementation just derefences the iterator
    // to yield a vertex_descriptor and forwards the call
    std::cout << "FB" << std::endl;
    return adjacent_vertices(*v, g);
}

} // namespace vigragraph
#endif

#ifdef WITH_LEMON
#  include <lemon/core.h>
#else // not WITH_LEMON

// emulate the lemon interface
namespace lemon {

struct Invalid {
  public:
    bool operator==(Invalid) const { return true;  }
    bool operator!=(Invalid) const { return false; }
    bool operator< (Invalid) const { return false; }

    template <class T, int N>
    operator vigra::TinyVector<T, N>() const
    {
       return vigra::TinyVector<T, N>(-1);
    }
};

static const Invalid INVALID = Invalid();

typedef vigra::VigraTrueType   True;
typedef vigra::VigraFalseType  False;

} // namespace lemon

#endif // WITH_LEMON

namespace lemon {

template <class T>
inline bool operator==(T const & t, Invalid)
{
    return t == T(Invalid());
}

template <class T>
inline bool operator==(Invalid, T const & t)
{
    return t == T(Invalid());
}

template <class T>
inline bool operator!=(T const & t, Invalid)
{
    return t != T(Invalid());
}

template <class T>
inline bool operator!=(Invalid, T const & t)
{
    return t != T(Invalid());
}

} // namespace lemon

namespace vigra {

template<class GRAPH,class ITEM>
struct GraphItemHelper;

template<class GRAPH>
struct GraphItemHelper<GRAPH,typename GRAPH::Edge>{
    typedef typename GRAPH::index_type index_type ;
    typedef typename GRAPH::Edge Item;
    typedef typename GRAPH::EdgeIt ItemIt;

    static index_type maxItemId(const GRAPH & g){
        return g.maxEdgeId();
    }
    static index_type itemNum(const GRAPH & g){
        return g.edgeNum();
    }
    static Item itemFromId(const GRAPH & g,const index_type id){
        return g.edgeFromId(id);
    }

};

template<class GRAPH>
struct GraphItemHelper<GRAPH,typename GRAPH::Node>{
    typedef typename GRAPH::index_type index_type ;
    typedef typename GRAPH::Node Item;
    typedef typename GRAPH::NodeIt ItemIt;

    static index_type maxItemId(const GRAPH & g){
        return g.maxNodeId();
    }
    static index_type itemNum(const GRAPH & g){
        return g.nodeNum();
    }
    static Item itemFromId(const GRAPH & g,const index_type id){
        return g.nodeFromId(id);
    }
};

template<class GRAPH>
struct GraphItemHelper<GRAPH,typename GRAPH::Arc>{
    typedef typename GRAPH::index_type index_type ;
    typedef typename GRAPH::Arc Item;
    typedef typename GRAPH::ArcIt ItemIt;

    static index_type maxItemId(const GRAPH & g){
        return g.maxArcId();
    }
    static index_type itemNum(const GRAPH & g){
        return g.arcNum();
    }
    static Item itemFromId(const GRAPH & g,const index_type id){
        return g.arcFromId(id);
    }
};

namespace lemon_graph {

// vigra::lemon_graph contains algorithms that are compatible to the LEMON graph library
using namespace lemon;

}} // namespace vigra::lemon_graph

#endif // VIGRA_GRAPH_HXX
<commit_msg>graphs.hxx: If boost is a dependency, include boost::tuple right away to avoid multiple definitions of boost::tie()<commit_after>/************************************************************************/
/*                                                                      */
/*     Copyright 2011-2012 Stefan Schmidt and Ullrich Koethe            */
/*                                                                      */
/*    This file is part of the VIGRA computer vision library.           */
/*    The VIGRA Website is                                              */
/*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
/*    Please direct questions, bug reports, and contributions to        */
/*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
/*        vigra@informatik.uni-hamburg.de                               */
/*                                                                      */
/*    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.                                   */
/*                                                                      */
/************************************************************************/

/**
 * This header provides definitions of graph-related types
 * and optionally provides a gateway to popular graph libraries
 * (for now, BGL is supported).
 */

#ifndef VIGRA_GRAPH_HXX
#define VIGRA_GRAPH_HXX

#include "metaprogramming.hxx"
#include "tinyvector.hxx"

#ifdef USE_BOOST_THREAD
// If boost is available, go ahead and include its tuple implementation
// to avoid naming conflicts with our own definition of tie(), below.
#include <boost/tuple/tuple.hpp>
#endif

#ifdef WITH_BOOST_GRAPH

#  include <boost/tuple/tuple.hpp>
#  include <boost/graph/graph_traits.hpp>
#  include <boost/graph/properties.hpp>

#else // not WITH_BOOST_GRAPH

// emulate the BGL-style interface
namespace boost {

struct no_property {};

// tag classes were copied from boost:
// directed_category tags
struct directed_tag { };
struct undirected_tag { };
struct bidirectional_tag : public directed_tag { };

// traversal_category tags
struct incidence_graph_tag { };
struct adjacency_graph_tag { };
struct bidirectional_graph_tag : public incidence_graph_tag { };
struct vertex_list_graph_tag { };
struct edge_list_graph_tag { };
struct adjacency_matrix_tag { };

// edge_parallel_category tags
struct allow_parallel_edge_tag { };
struct disallow_parallel_edge_tag { };

// property maps:
struct readable_property_map_tag { };
struct writable_property_map_tag { };
struct read_write_property_map_tag
    : public readable_property_map_tag,
      public writable_property_map_tag {};
struct lvalue_property_map_tag
    : public read_write_property_map_tag {};

struct vertex_index_t {};

struct edge_property_tag {};

#ifndef BOOST_TUPLE_HPP

// tie() support for std::pair, similar to Boost's one:
// (necessary because std::pair doesn't define a suitable assignment operator)
template<class T1, class T2>
class tie_adapter
{
  public:
    tie_adapter(T1 &x, T2 &y)
        : x_(x), y_(y)
    {}

    template<class X, class Y>
    tie_adapter & operator=(const std::pair<X, Y> &pair)
    {
        x_ = pair.first;
        y_ = pair.second;
        return *this;
    }

  protected:
    T1 &x_;
    T2 &y_;
};

template<class T1, class T2>
inline
tie_adapter<T1, T2>
tie(T1& t1, T2& t2)
{
    return tie_adapter<T1, T2>(t1, t2);
}
#endif

// graph_traits class template
template <typename G>
struct graph_traits {
    typedef typename G::vertex_descriptor      vertex_descriptor;
    typedef typename G::edge_descriptor        edge_descriptor;
    typedef typename G::adjacency_iterator     adjacency_iterator;
    typedef typename G::out_edge_iterator      out_edge_iterator;
    typedef typename G::in_edge_iterator       in_edge_iterator;
    typedef typename G::vertex_iterator        vertex_iterator;
    typedef typename G::edge_iterator          edge_iterator;

    typedef typename G::directed_category      directed_category;
    typedef typename G::edge_parallel_category edge_parallel_category;
    typedef typename G::traversal_category     traversal_category;

    typedef typename G::vertices_size_type     vertices_size_type;
    typedef typename G::edges_size_type        edges_size_type;
    typedef typename G::degree_size_type       degree_size_type;

    static inline vertex_descriptor null_vertex()
    {
        return vertex_descriptor(-1);
    }
};

// property_traits class template
template <typename PropMap>
struct property_traits
{
    typedef typename PropMap::key_type    key_type;
    typedef typename PropMap::value_type  value_type;
    typedef typename PropMap::reference   reference;
    typedef typename PropMap::category    category;
};

} // namespace boost

#endif // WITH_BOOST_GRAPH

namespace vigra {
namespace boost_graph {

// vigra::boost_graph contains algorithms that are compatible to the Boost Graph Library
using namespace boost;

}} // namespace vigra::boost_graph

#if 0
namespace vigragraph {

// custom get_helper for read-only property maps (by-value)

template <class ValueType, class ReadablePropertyMap>
struct get_helper { };

template <class PropertyMap, class ValueType, class K>
inline ValueType
get(const get_helper<ValueType, PropertyMap>& pa, const K& k)
{
    const ValueType v = static_cast<const PropertyMap&>(pa)[k];
    return v;
}

// ! A fallback template for adjacent_vertices() called with
// a vertex_iterator
// (which may be specialized to be implemented more efficiently;
//  the reason is that the iterator may have more information than
//  the plain vertex_descriptor, e.g. it knows the neighborhood
//  already which otherwise needs to be reconstructed.)
template<class GRAPH>
inline
std::pair<typename graph_traits<GRAPH>::adjacency_iterator,
          typename graph_traits<GRAPH>::adjacency_iterator >
adjacent_vertices_at_iterator(typename graph_traits<GRAPH>::vertex_iterator const &v,
                              GRAPH const &g)
{
    // the default implementation just derefences the iterator
    // to yield a vertex_descriptor and forwards the call
    std::cout << "FB" << std::endl;
    return adjacent_vertices(*v, g);
}

} // namespace vigragraph
#endif

#ifdef WITH_LEMON
#  include <lemon/core.h>
#else // not WITH_LEMON

// emulate the lemon interface
namespace lemon {

struct Invalid {
  public:
    bool operator==(Invalid) const { return true;  }
    bool operator!=(Invalid) const { return false; }
    bool operator< (Invalid) const { return false; }

    template <class T, int N>
    operator vigra::TinyVector<T, N>() const
    {
       return vigra::TinyVector<T, N>(-1);
    }
};

static const Invalid INVALID = Invalid();

typedef vigra::VigraTrueType   True;
typedef vigra::VigraFalseType  False;

} // namespace lemon

#endif // WITH_LEMON

namespace lemon {

template <class T>
inline bool operator==(T const & t, Invalid)
{
    return t == T(Invalid());
}

template <class T>
inline bool operator==(Invalid, T const & t)
{
    return t == T(Invalid());
}

template <class T>
inline bool operator!=(T const & t, Invalid)
{
    return t != T(Invalid());
}

template <class T>
inline bool operator!=(Invalid, T const & t)
{
    return t != T(Invalid());
}

} // namespace lemon

namespace vigra {

template<class GRAPH,class ITEM>
struct GraphItemHelper;

template<class GRAPH>
struct GraphItemHelper<GRAPH,typename GRAPH::Edge>{
    typedef typename GRAPH::index_type index_type ;
    typedef typename GRAPH::Edge Item;
    typedef typename GRAPH::EdgeIt ItemIt;

    static index_type maxItemId(const GRAPH & g){
        return g.maxEdgeId();
    }
    static index_type itemNum(const GRAPH & g){
        return g.edgeNum();
    }
    static Item itemFromId(const GRAPH & g,const index_type id){
        return g.edgeFromId(id);
    }

};

template<class GRAPH>
struct GraphItemHelper<GRAPH,typename GRAPH::Node>{
    typedef typename GRAPH::index_type index_type ;
    typedef typename GRAPH::Node Item;
    typedef typename GRAPH::NodeIt ItemIt;

    static index_type maxItemId(const GRAPH & g){
        return g.maxNodeId();
    }
    static index_type itemNum(const GRAPH & g){
        return g.nodeNum();
    }
    static Item itemFromId(const GRAPH & g,const index_type id){
        return g.nodeFromId(id);
    }
};

template<class GRAPH>
struct GraphItemHelper<GRAPH,typename GRAPH::Arc>{
    typedef typename GRAPH::index_type index_type ;
    typedef typename GRAPH::Arc Item;
    typedef typename GRAPH::ArcIt ItemIt;

    static index_type maxItemId(const GRAPH & g){
        return g.maxArcId();
    }
    static index_type itemNum(const GRAPH & g){
        return g.arcNum();
    }
    static Item itemFromId(const GRAPH & g,const index_type id){
        return g.arcFromId(id);
    }
};

namespace lemon_graph {

// vigra::lemon_graph contains algorithms that are compatible to the LEMON graph library
using namespace lemon;

}} // namespace vigra::lemon_graph

#endif // VIGRA_GRAPH_HXX
<|endoftext|>


<commit_before>#pragma once
#ifndef __VALIJSON_INTERNAL_JSON_POINTER_HPP
#define __VALIJSON_INTERNAL_JSON_POINTER_HPP

#include <cerrno>
#include <stdexcept>
#include <string>

#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>

#include <valijson/adapters/adapter.hpp>

namespace valijson {
namespace internal {
namespace json_pointer {

/**
 * @brief   Return the char value corresponding to a 2-digit hexadecimal string
 *
 * @throws  std::runtime_error for strings that are not exactly two characters
 *          in length and for strings that contain non-hexadecimal characters
 *
 * @return  decoded char value corresponding to the hexadecimal string
 */
inline char decodePercentEncodedChar(const std::string &digits)
{
    if (digits.length() != 2) {
        throw std::runtime_error("Failed to decode %-encoded character '" +
                digits + "' due to unexpected number of characters; "
                "expected two characters");
    }

    errno = 0;
    const char *begin = digits.c_str();
    char *end = NULL;
    const unsigned long value = strtoul(begin, &end, 16);
    if (end != begin && *end != '\0') {
        throw std::runtime_error("Failed to decode %-encoded character '" +
                digits + "'");
    }

    return char(value);
}

/**
 * @brief   Extract and transform the token between two iterators
 *
 * This function is responsible for extracting a JSON Reference token from
 * between two iterators, and performing any necessary transformations, before
 * returning the resulting string. Its main purpose is to replace the escaped
 * character sequences defined in the RFC-6901 (JSON Pointer), and to decode
 * %-encoded character sequences defined in RFC-3986 (URI).
 *
 * The encoding used in RFC-3986 should be familiar to many developers, but
 * the escaped character sequences used in JSON Pointers may be less so. From
 * the JSON Pointer specification (RFC 6901, April 2013):
 *
 *    Evaluation of each reference token begins by decoding any escaped
 *    character sequence.  This is performed by first transforming any
 *    occurrence of the sequence '~1' to '/', and then transforming any
 *    occurrence of the sequence '~0' to '~'.  By performing the
 *    substitutions in this order, an implementation avoids the error of
 *    turning '~01' first into '~1' and then into '/', which would be
 *    incorrect (the string '~01' correctly becomes '~1' after
 *    transformation).
 *
 * @param   begin  iterator pointing to beginning of a token
 * @param   end    iterator pointing to one character past the end of the token
 *
 * @return  string with escaped character sequences replaced
 *
 */
inline std::string extractReferenceToken(std::string::const_iterator begin,
        std::string::const_iterator end)
{
    std::string token(begin, end);

    // Replace JSON Pointer-specific escaped character sequences
    boost::replace_all(token, "~1", "/");
    boost::replace_all(token, "~0", "~");

    // Replace %-encoded character sequences with their actual characters
    for (size_t n = token.find('%'); n != std::string::npos;
            n = token.find('%', n + 1)) {

        try {
            const char c = decodePercentEncodedChar(token.substr(n + 1, 2));
            token.replace(n, 3, &c, 1);

        } catch (const std::runtime_error &e) {
            throw std::runtime_error(
                    std::string(e.what()) + "; in token: " + token);
        }
    }

    return token;
}

/**
 * @brief   Recursively locate the value referenced by a JSON Pointer
 *
 * This function takes both a string reference and an iterator to the beginning
 * of the substring that is being resolved. This iterator is expected to point
 * to the beginning of a reference token, whose length will be determined by
 * searching for the next delimiter ('/' or '\0'). A reference token must be
 * at least one character in length to be considered valid.
 *
 * Once the next reference token has been identified, it will be used either as
 * an array index or as an the name an object member. The validity of a
 * reference token depends on the type of the node currently being traversed,
 * and the applicability of the token to that node. For example, an array can
 * only be dereferenced by a non-negative integral index.
 *
 * Once the next node has been identified, the length of the remaining portion
 * of the JSON Pointer will be used to determine whether recursion should
 * terminate.
 *
 * @param   node            current node in recursive evaluation of JSON Pointer
 * @param   jsonPointer     string containing complete JSON Pointer
 * @param   jsonPointerItr  string iterator pointing the beginning of the next
 *                          reference token
 *
 * @return  an instance of AdapterType that wraps the dereferenced node
 */
template<typename AdapterType>
inline AdapterType resolveJsonPointer(
        const AdapterType &node,
        const std::string &jsonPointer,
        const std::string::const_iterator jsonPointerItr)
{
    // TODO: This function will probably need to implement support for
    // fetching documents referenced by JSON Pointers, similar to the
    // populateSchema function.

    const std::string::const_iterator jsonPointerEnd = jsonPointer.end();

    // Terminate recursion if all reference tokens have been consumed
    if (jsonPointerItr == jsonPointerEnd) {
        return node;
    }

    // Reference tokens must begin with a leading slash
    if (*jsonPointerItr != '/') {
        throw std::runtime_error("Expected reference token to begin with "
                "leading slash; remaining tokens: " +
                std::string(jsonPointerItr, jsonPointerEnd));
    }

    // Find iterator that points to next slash or newline character; this is
    // one character past the end of the current reference token
    std::string::const_iterator jsonPointerNext =
            std::find(jsonPointerItr + 1, jsonPointerEnd, '/');

    // Extract the next reference token
    const std::string referenceToken = extractReferenceToken(
            jsonPointerItr + 1, jsonPointerNext);

    // Empty reference tokens should be ignored
    if (referenceToken.empty()) {
        return resolveJsonPointer(node, jsonPointer, jsonPointerNext);

    } else if (node.isArray()) {
        if (referenceToken.compare("-") == 0) {
            throw std::runtime_error("Hyphens cannot be used as array indices "
                    "since the requested array element does not yet exist");
        }

        try {
            // Fragment must be non-negative integer
            const uint64_t index = boost::lexical_cast<uint64_t>(
                    referenceToken);
            typedef typename AdapterType::Array Array;
            typename Array::const_iterator itr = node.asArray().begin();

            if (index > node.asArray().size() - 1) {
                throw std::runtime_error("Expected reference token to identify "
                        "an element in the current array, but array index is "
                        "out of bounds; actual token: " + referenceToken);
            }

            if (index > std::numeric_limits<ptrdiff_t>::max()) {
                throw std::runtime_error("Array index out of bounds; hard "
                        "limit is " + boost::lexical_cast<std::string>(
                                std::numeric_limits<ptrdiff_t>::max()));
            }

            itr.advance(static_cast<ptrdiff_t>(index));

            // Recursively process the remaining tokens
            return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext);

        } catch (boost::bad_lexical_cast &) {
            throw std::runtime_error("Expected reference token to contain a "
                    "non-negative integer to identify an element in the "
                    "current array; actual token: " + referenceToken);
        }

    } else if (node.maybeObject()) {
        // Fragment must identify a member of the candidate object
        typedef typename AdapterType::Object Object;
        typename Object::const_iterator itr = node.asObject().find(
                referenceToken);
        if (itr == node.asObject().end()) {
            throw std::runtime_error("Expected reference token to identify an "
                    "element in the current object; "
                    "actual token: " + referenceToken);
        }

        // Recursively process the remaining tokens
        return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext);
    }

    throw std::runtime_error("Expected end of JSON Pointer, but at least "
            "one reference token has not been processed; remaining tokens: " +
            std::string(jsonPointerNext, jsonPointerEnd));
}

/**
 * @brief   Return the JSON Value referenced by a JSON Pointer
 *
 * @param   rootNode     node to use as root for JSON Pointer resolution
 * @param   jsonPointer  string containing JSON Pointer
 *
 * @return  an instance AdapterType in the specified document
 */
template<typename AdapterType>
inline AdapterType resolveJsonPointer(
        const AdapterType &rootNode,
        const std::string &jsonPointer)
{
    return resolveJsonPointer(rootNode, jsonPointer, jsonPointer.begin());
}

} // namespace json_pointer
} // namespace internal
} // namespace valijson

#endif
<commit_msg>Fix signed/unsigned comparison in json_pointer namespace<commit_after>#pragma once
#ifndef __VALIJSON_INTERNAL_JSON_POINTER_HPP
#define __VALIJSON_INTERNAL_JSON_POINTER_HPP

#include <cerrno>
#include <stdexcept>
#include <string>

#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>

#include <valijson/adapters/adapter.hpp>

namespace valijson {
namespace internal {
namespace json_pointer {

/**
 * @brief   Return the char value corresponding to a 2-digit hexadecimal string
 *
 * @throws  std::runtime_error for strings that are not exactly two characters
 *          in length and for strings that contain non-hexadecimal characters
 *
 * @return  decoded char value corresponding to the hexadecimal string
 */
inline char decodePercentEncodedChar(const std::string &digits)
{
    if (digits.length() != 2) {
        throw std::runtime_error("Failed to decode %-encoded character '" +
                digits + "' due to unexpected number of characters; "
                "expected two characters");
    }

    errno = 0;
    const char *begin = digits.c_str();
    char *end = NULL;
    const unsigned long value = strtoul(begin, &end, 16);
    if (end != begin && *end != '\0') {
        throw std::runtime_error("Failed to decode %-encoded character '" +
                digits + "'");
    }

    return char(value);
}

/**
 * @brief   Extract and transform the token between two iterators
 *
 * This function is responsible for extracting a JSON Reference token from
 * between two iterators, and performing any necessary transformations, before
 * returning the resulting string. Its main purpose is to replace the escaped
 * character sequences defined in the RFC-6901 (JSON Pointer), and to decode
 * %-encoded character sequences defined in RFC-3986 (URI).
 *
 * The encoding used in RFC-3986 should be familiar to many developers, but
 * the escaped character sequences used in JSON Pointers may be less so. From
 * the JSON Pointer specification (RFC 6901, April 2013):
 *
 *    Evaluation of each reference token begins by decoding any escaped
 *    character sequence.  This is performed by first transforming any
 *    occurrence of the sequence '~1' to '/', and then transforming any
 *    occurrence of the sequence '~0' to '~'.  By performing the
 *    substitutions in this order, an implementation avoids the error of
 *    turning '~01' first into '~1' and then into '/', which would be
 *    incorrect (the string '~01' correctly becomes '~1' after
 *    transformation).
 *
 * @param   begin  iterator pointing to beginning of a token
 * @param   end    iterator pointing to one character past the end of the token
 *
 * @return  string with escaped character sequences replaced
 *
 */
inline std::string extractReferenceToken(std::string::const_iterator begin,
        std::string::const_iterator end)
{
    std::string token(begin, end);

    // Replace JSON Pointer-specific escaped character sequences
    boost::replace_all(token, "~1", "/");
    boost::replace_all(token, "~0", "~");

    // Replace %-encoded character sequences with their actual characters
    for (size_t n = token.find('%'); n != std::string::npos;
            n = token.find('%', n + 1)) {

        try {
            const char c = decodePercentEncodedChar(token.substr(n + 1, 2));
            token.replace(n, 3, &c, 1);

        } catch (const std::runtime_error &e) {
            throw std::runtime_error(
                    std::string(e.what()) + "; in token: " + token);
        }
    }

    return token;
}

/**
 * @brief   Recursively locate the value referenced by a JSON Pointer
 *
 * This function takes both a string reference and an iterator to the beginning
 * of the substring that is being resolved. This iterator is expected to point
 * to the beginning of a reference token, whose length will be determined by
 * searching for the next delimiter ('/' or '\0'). A reference token must be
 * at least one character in length to be considered valid.
 *
 * Once the next reference token has been identified, it will be used either as
 * an array index or as an the name an object member. The validity of a
 * reference token depends on the type of the node currently being traversed,
 * and the applicability of the token to that node. For example, an array can
 * only be dereferenced by a non-negative integral index.
 *
 * Once the next node has been identified, the length of the remaining portion
 * of the JSON Pointer will be used to determine whether recursion should
 * terminate.
 *
 * @param   node            current node in recursive evaluation of JSON Pointer
 * @param   jsonPointer     string containing complete JSON Pointer
 * @param   jsonPointerItr  string iterator pointing the beginning of the next
 *                          reference token
 *
 * @return  an instance of AdapterType that wraps the dereferenced node
 */
template<typename AdapterType>
inline AdapterType resolveJsonPointer(
        const AdapterType &node,
        const std::string &jsonPointer,
        const std::string::const_iterator jsonPointerItr)
{
    // TODO: This function will probably need to implement support for
    // fetching documents referenced by JSON Pointers, similar to the
    // populateSchema function.

    const std::string::const_iterator jsonPointerEnd = jsonPointer.end();

    // Terminate recursion if all reference tokens have been consumed
    if (jsonPointerItr == jsonPointerEnd) {
        return node;
    }

    // Reference tokens must begin with a leading slash
    if (*jsonPointerItr != '/') {
        throw std::runtime_error("Expected reference token to begin with "
                "leading slash; remaining tokens: " +
                std::string(jsonPointerItr, jsonPointerEnd));
    }

    // Find iterator that points to next slash or newline character; this is
    // one character past the end of the current reference token
    std::string::const_iterator jsonPointerNext =
            std::find(jsonPointerItr + 1, jsonPointerEnd, '/');

    // Extract the next reference token
    const std::string referenceToken = extractReferenceToken(
            jsonPointerItr + 1, jsonPointerNext);

    // Empty reference tokens should be ignored
    if (referenceToken.empty()) {
        return resolveJsonPointer(node, jsonPointer, jsonPointerNext);

    } else if (node.isArray()) {
        if (referenceToken.compare("-") == 0) {
            throw std::runtime_error("Hyphens cannot be used as array indices "
                    "since the requested array element does not yet exist");
        }

        try {
            // Fragment must be non-negative integer
            const uint64_t index = boost::lexical_cast<uint64_t>(
                    referenceToken);
            typedef typename AdapterType::Array Array;
            typename Array::const_iterator itr = node.asArray().begin();

            if (index > node.asArray().size() - 1) {
                throw std::runtime_error("Expected reference token to identify "
                        "an element in the current array, but array index is "
                        "out of bounds; actual token: " + referenceToken);
            }

            if (index > static_cast<uint64_t>(std::numeric_limits<ptrdiff_t>::max())) {
                throw std::runtime_error("Array index out of bounds; hard "
                        "limit is " + boost::lexical_cast<std::string>(
                                std::numeric_limits<ptrdiff_t>::max()));
            }

            itr.advance(static_cast<ptrdiff_t>(index));

            // Recursively process the remaining tokens
            return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext);

        } catch (boost::bad_lexical_cast &) {
            throw std::runtime_error("Expected reference token to contain a "
                    "non-negative integer to identify an element in the "
                    "current array; actual token: " + referenceToken);
        }

    } else if (node.maybeObject()) {
        // Fragment must identify a member of the candidate object
        typedef typename AdapterType::Object Object;
        typename Object::const_iterator itr = node.asObject().find(
                referenceToken);
        if (itr == node.asObject().end()) {
            throw std::runtime_error("Expected reference token to identify an "
                    "element in the current object; "
                    "actual token: " + referenceToken);
        }

        // Recursively process the remaining tokens
        return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext);
    }

    throw std::runtime_error("Expected end of JSON Pointer, but at least "
            "one reference token has not been processed; remaining tokens: " +
            std::string(jsonPointerNext, jsonPointerEnd));
}

/**
 * @brief   Return the JSON Value referenced by a JSON Pointer
 *
 * @param   rootNode     node to use as root for JSON Pointer resolution
 * @param   jsonPointer  string containing JSON Pointer
 *
 * @return  an instance AdapterType in the specified document
 */
template<typename AdapterType>
inline AdapterType resolveJsonPointer(
        const AdapterType &rootNode,
        const std::string &jsonPointer)
{
    return resolveJsonPointer(rootNode, jsonPointer, jsonPointer.begin());
}

} // namespace json_pointer
} // namespace internal
} // namespace valijson

#endif
<|endoftext|>


<commit_before><commit_msg>leetcode: Regular Expression Matching<commit_after><|endoftext|>


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

#include <cassert>
#include <map>

#include "common/types.h"
#include "common/logger.h"
#include "common/value.h"
#include "common/value_factory.h"

#include "index/index_util.h"
#include "index/index.h"

namespace peloton {
namespace index {

bool IfForwardExpression(ExpressionType e) {
  if (e == EXPRESSION_TYPE_COMPARE_GREATERTHAN ||
      e == EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO) {
    return true;
  }
  return false;
}

bool IfBackwardExpression(ExpressionType e) {
  if (e == EXPRESSION_TYPE_COMPARE_LESSTHAN ||
      e == EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO) {
    return true;
  }
  return false;
}

bool ValuePairComparator(const std::pair<peloton::Value, int> &i,
                         const std::pair<peloton::Value, int> &j) {
  if (i.first.Compare(j.first) == VALUE_COMPARE_EQUAL) {
    return i.second < j.second;
  }
  return i.first.Compare(j.first) == VALUE_COMPARE_LESSTHAN;
}

void ConstructIntervals(oid_t leading_column_id,
                        const std::vector<Value> &values,
                        const std::vector<oid_t> &key_column_ids,
                        const std::vector<ExpressionType> &expr_types,
                        std::vector<std::pair<Value, Value>> &intervals) {
  // Find all contrains of leading column.
  // Equal --> > < num
  // > >= --->  > num
  // < <= ----> < num
  std::vector<std::pair<peloton::Value, int>> nums;
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    if (key_column_ids[i] != leading_column_id) {
      continue;
    }

    // If leading column
    if (IfForwardExpression(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], -1));
    } else if (IfBackwardExpression(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], 1));
    } else {
      assert(expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL);
      nums.push_back(std::pair<Value, int>(values[i], -1));
      nums.push_back(std::pair<Value, int>(values[i], 1));
    }
  }

  // Have merged all constraints in a single line, sort this line.
  std::sort(nums.begin(), nums.end(), Index::ValuePairComparator);
  assert(nums.size() > 0);

  // Build intervals.
  Value cur;
  size_t i = 0;
  if (nums[0].second < 0) {
    cur = nums[0].first;
    i++;
  } else {
    cur = Value::GetMinValue(nums[0].first.GetValueType());
  }

  while (i < nums.size()) {
    if (nums[i].second > 0) {
      if (i + 1 < nums.size() && nums[i + 1].second < 0) {
        // right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = nums[i + 1].first;
      } else if (i + 1 == nums.size()) {
        // Last value while right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = Value::GetNullValue(nums[0].first.GetValueType());
      }
    }
    i++;
  }

  if (cur.IsNull() == false) {
    intervals.push_back(std::pair<Value, Value>(
        cur, Value::GetMaxValue(nums[0].first.GetValueType())));
  }

  // Finish invtervals building.
};

void FindMaxMinInColumns(oid_t leading_column_id,
                         const std::vector<Value> &values,
                         const std::vector<oid_t> &key_column_ids,
                         const std::vector<ExpressionType> &expr_types,
                         std::map<oid_t, std::pair<Value, Value>> &non_leading_columns) {
  // find extreme nums on each column.
  LOG_TRACE("FindMinMax leading column %d\n", leading_column_id);
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    oid_t column_id = key_column_ids[i];
    if (column_id == leading_column_id) {
      continue;
    }

    if (non_leading_columns.find(column_id) == non_leading_columns.end()) {
      auto type = values[i].GetValueType();
      // std::pair<Value, Value> *range = new std::pair<Value,
      // Value>(Value::GetMaxValue(type),
      //                                            Value::GetMinValue(type));
      // std::pair<oid_t, std::pair<Value, Value>> key_value(column_id, range);
      non_leading_columns.insert(std::pair<oid_t, std::pair<Value, Value>>(
          column_id, std::pair<Value, Value>(Value::GetNullValue(type),
                                             Value::GetNullValue(type))));
      //  non_leading_columns[column_id] = *range;
      // delete range;
      LOG_TRACE("Insert a init bounds\tleft size %lu\t right description %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                non_leading_columns[column_id].second.GetInfo().c_str());
    }

    if (IfForwardExpression(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("min cur %lu compare with %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].first.Compare(values[i]) ==
              VALUE_COMPARE_GREATERTHAN) {
        LOG_TRACE("Update min\n");
        non_leading_columns[column_id].first =
            ValueFactory::Clone(values[i], nullptr);
      }
    }

    if (IfBackwardExpression(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("max cur %s compare with %s\n",
                non_leading_columns[column_id].second.GetInfo().c_str(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].second.Compare(values[i]) ==
              VALUE_COMPARE_LESSTHAN) {
        LOG_TRACE("Update max\n");
        non_leading_columns[column_id].second =
            ValueFactory::Clone(values[i], nullptr);
      }
    }
  }

  // check if min value is right bound or max value is left bound, if so, update
  for (const auto &k_v : non_leading_columns) {
    if (k_v.second.first.IsNull()) {
      non_leading_columns[k_v.first].first =
          Value::GetMinValue(k_v.second.first.GetValueType());
    }
    if (k_v.second.second.IsNull()) {
      non_leading_columns[k_v.first].second =
          Value::GetMaxValue(k_v.second.second.GetValueType());
    }
  }
};

}  // End index namespace
}  // End peloton namespace
<commit_msg>Adding helper function into index_util<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// btree_index.cpp
//
// Identification: src/index/btree_index.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <cassert>
#include <map>

#include "common/types.h"
#include "common/logger.h"
#include "common/value.h"
#include "common/value_factory.h"

#include "index/index_util.h"
#include "index/index.h"

namespace peloton {
namespace index {

/*
 * IfForwardExpression() - Returns true if the expression is > or >=
 */
bool IfForwardExpression(ExpressionType e) {
  // To reduce branch misprediction penalty
  return e == EXPRESSION_TYPE_COMPARE_GREATERTHAN ||
         e == EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO;
}

/*
 * IfBackWardExpression() - Returns true if the expression is < or <=
 */
bool IfBackwardExpression(ExpressionType e) {
  return e == EXPRESSION_TYPE_COMPARE_LESSTHAN ||
         e == EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO;
}

/*
 * ValuePairComparator() - Compares std::pair<Value, int>
 *
 * Values are compared first and if not equal return result
 * If values are equal then compare the second element which is an int
 * and return the result
 */
bool ValuePairComparator(const std::pair<peloton::Value, int> &i,
                         const std::pair<peloton::Value, int> &j) {

  // If first elements are equal then compare the second element
  if (i.first.Compare(j.first) == VALUE_COMPARE_EQUAL) {
    return i.second < j.second;
  }

  // Otherwise compare the first element for "<" or ">"
  return i.first.Compare(j.first) == VALUE_COMPARE_LESSTHAN;
}

void ConstructIntervals(oid_t leading_column_id,
                        const std::vector<Value> &values,
                        const std::vector<oid_t> &key_column_ids,
                        const std::vector<ExpressionType> &expr_types,
                        std::vector<std::pair<Value, Value>> &intervals) {
  // Find all contrains of leading column.
  // Equal --> > < num
  // > >= --->  > num
  // < <= ----> < num
  std::vector<std::pair<peloton::Value, int>> nums;
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    if (key_column_ids[i] != leading_column_id) {
      continue;
    }

    // If leading column
    if (IfForwardExpression(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], -1));
    } else if (IfBackwardExpression(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], 1));
    } else {
      assert(expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL);
      nums.push_back(std::pair<Value, int>(values[i], -1));
      nums.push_back(std::pair<Value, int>(values[i], 1));
    }
  }

  // Have merged all constraints in a single line, sort this line.
  std::sort(nums.begin(), nums.end(), ValuePairComparator);
  assert(nums.size() > 0);

  // Build intervals.
  Value cur;
  size_t i = 0;
  if (nums[0].second < 0) {
    cur = nums[0].first;
    i++;
  } else {
    cur = Value::GetMinValue(nums[0].first.GetValueType());
  }

  while (i < nums.size()) {
    if (nums[i].second > 0) {
      if (i + 1 < nums.size() && nums[i + 1].second < 0) {
        // right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = nums[i + 1].first;
      } else if (i + 1 == nums.size()) {
        // Last value while right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = Value::GetNullValue(nums[0].first.GetValueType());
      }
    }
    i++;
  }

  if (cur.IsNull() == false) {
    intervals.push_back(std::pair<Value, Value>(
        cur, Value::GetMaxValue(nums[0].first.GetValueType())));
  }

  // Finish invtervals building.
};

void FindMaxMinInColumns(oid_t leading_column_id,
                         const std::vector<Value> &values,
                         const std::vector<oid_t> &key_column_ids,
                         const std::vector<ExpressionType> &expr_types,
                         std::map<oid_t, std::pair<Value, Value>> &non_leading_columns) {
  // find extreme nums on each column.
  LOG_TRACE("FindMinMax leading column %d\n", leading_column_id);
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    oid_t column_id = key_column_ids[i];
    if (column_id == leading_column_id) {
      continue;
    }

    if (non_leading_columns.find(column_id) == non_leading_columns.end()) {
      auto type = values[i].GetValueType();
      // std::pair<Value, Value> *range = new std::pair<Value,
      // Value>(Value::GetMaxValue(type),
      //                                            Value::GetMinValue(type));
      // std::pair<oid_t, std::pair<Value, Value>> key_value(column_id, range);
      non_leading_columns.insert(std::pair<oid_t, std::pair<Value, Value>>(
          column_id, std::pair<Value, Value>(Value::GetNullValue(type),
                                             Value::GetNullValue(type))));
      //  non_leading_columns[column_id] = *range;
      // delete range;
      LOG_TRACE("Insert a init bounds\tleft size %lu\t right description %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                non_leading_columns[column_id].second.GetInfo().c_str());
    }

    if (IfForwardExpression(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("min cur %lu compare with %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].first.Compare(values[i]) ==
              VALUE_COMPARE_GREATERTHAN) {
        LOG_TRACE("Update min\n");
        non_leading_columns[column_id].first =
            ValueFactory::Clone(values[i], nullptr);
      }
    }

    if (IfBackwardExpression(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("max cur %s compare with %s\n",
                non_leading_columns[column_id].second.GetInfo().c_str(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].second.Compare(values[i]) ==
              VALUE_COMPARE_LESSTHAN) {
        LOG_TRACE("Update max\n");
        non_leading_columns[column_id].second =
            ValueFactory::Clone(values[i], nullptr);
      }
    }
  }

  // check if min value is right bound or max value is left bound, if so, update
  for (const auto &k_v : non_leading_columns) {
    if (k_v.second.first.IsNull()) {
      non_leading_columns[k_v.first].first =
          Value::GetMinValue(k_v.second.first.GetValueType());
    }
    if (k_v.second.second.IsNull()) {
      non_leading_columns[k_v.first].second =
          Value::GetMaxValue(k_v.second.second.GetValueType());
    }
  }
};

}  // End index namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>#include <thread>
#include <queue>
#include <glog/logging.h>
#include <util.h>
#include <atom/atom.h>
#include <core/core.h>
#include <index/real_index.h>

namespace {

const std::string k_default_index = "index";
const size_t k_stop_attempts = 120;
const size_t k_stop_interval_check_ms = 500;

std::string key(const Event& e) {
  return e.host() + "-" + e.service();
}

}

real_index::real_index(pub_sub & pubsub, push_event_fn_t push_event,
                       const int64_t expire_interval,
                       scheduler_interface &  sched,
                       spwan_thread_fn_t spwan_thread_fn)
:
  pubsub_(pubsub),
  push_event_fn_(push_event),
  expiring_(false),
  spwan_thread_fn_(spwan_thread_fn),
  sched_(sched)
{

  pubsub_.add_publisher(k_default_index,
                        std::bind(&real_index::all_events, this));

  sched_.add_periodic_task(std::bind(&real_index::timer_cb, this),
                            expire_interval);
}

std::vector<std::shared_ptr<Event>> real_index::all_events() {

  mutex_.lock();
  auto idx_cpy(index_map_);
  mutex_.unlock();

  std::vector<std::shared_ptr<Event>> events;

  for (const auto & kv: idx_cpy) {
    events.push_back(kv.second);
  }

  return events;
}

void real_index::add_event(const Event& e) {

  VLOG(3) << "add_event()";

  const std::string ev_key(key(e));

  auto shared_event = std::make_shared<Event>(e);

  {
    std::lock_guard<std::mutex> lock(mutex_);
    index_map_.insert({ev_key, shared_event});
  }

  pubsub_.publish(k_default_index, e);
}

void real_index::timer_cb() {

  if (expiring_.exchange(true)) {

    VLOG(1) << "previous expire_events thread hasn't finished yet";
    return;

  }

  spwan_thread_fn_(std::bind(&real_index::expire_events, this));

}

void real_index::expire_events() {

  atom_attach_thread();

  VLOG(3) << "expire_fn()++";

  VLOG(3) << "index size: " << index_map_.size();

  std::vector<std::shared_ptr<Event>> expired_events;

  int64_t now = static_cast<int64_t>(sched_.unix_time());

  {

    std::lock_guard<std::mutex> lock(mutex_);

    auto it = index_map_.begin();
    while (it != index_map_.end()) {

      const auto & event(it->second);

      auto expire = event->time() + static_cast<int64_t>(event->ttl());
      if (expire < now) {
        expired_events.push_back(event);
        index_map_.erase(it++);
      } else {
        ++it;
      }

    }

  }

  VLOG(3) << "expire process took "
          << static_cast<int64_t>(sched_.unix_time()) - now << " seconds";

  for (auto & event : expired_events) {
    event->set_state("expired");
    pubsub_.publish(k_default_index, *event);
    push_event_fn_(*event);
  }

  VLOG(3) << "expire_fn()--";

  expiring_.store(false);

  atom_detach_thread();
}

real_index::~real_index() {

  VLOG(3) << "~real_index()++";

  if (expiring_.exchange(true)) {

    VLOG(3) << "expire_events thread is running";

    for (size_t attempts = k_stop_attempts; attempts > 0; attempts--) {

      if (!expiring_.exchange(true)) {
        break;
      }

      VLOG(3) << "Waiting for expiring event to finish";

      std::this_thread::sleep_for(
          std::chrono::milliseconds(k_stop_interval_check_ms));
    }

  }

  VLOG(3) << "~real_index()--";
}
<commit_msg>Fix index issue<commit_after>#include <thread>
#include <queue>
#include <glog/logging.h>
#include <util.h>
#include <atom/atom.h>
#include <core/core.h>
#include <index/real_index.h>

namespace {

const std::string k_default_index = "index";
const size_t k_stop_attempts = 120;
const size_t k_stop_interval_check_ms = 500;

std::string key(const Event& e) {
  return e.host() + "-" + e.service();
}

}

real_index::real_index(pub_sub & pubsub, push_event_fn_t push_event,
                       const int64_t expire_interval,
                       scheduler_interface &  sched,
                       spwan_thread_fn_t spwan_thread_fn)
:
  pubsub_(pubsub),
  push_event_fn_(push_event),
  expiring_(false),
  spwan_thread_fn_(spwan_thread_fn),
  sched_(sched)
{

  pubsub_.add_publisher(k_default_index,
                        std::bind(&real_index::all_events, this));

  sched_.add_periodic_task(std::bind(&real_index::timer_cb, this),
                            expire_interval);
}

std::vector<std::shared_ptr<Event>> real_index::all_events() {

  mutex_.lock();
  auto idx_cpy(index_map_);
  mutex_.unlock();

  std::vector<std::shared_ptr<Event>> events;

  for (const auto & kv: idx_cpy) {
    events.push_back(kv.second);
  }

  return events;
}

void real_index::add_event(const Event& e) {

  VLOG(3) << "add_event()";

  const std::string ev_key(key(e));

  auto shared_event = std::make_shared<Event>(e);

  {
    std::lock_guard<std::mutex> lock(mutex_);
    index_map_[ev_key] = shared_event;
  }

  pubsub_.publish(k_default_index, e);
}

void real_index::timer_cb() {

  if (expiring_.exchange(true)) {

    VLOG(1) << "previous expire_events thread hasn't finished yet";
    return;

  }

  spwan_thread_fn_(std::bind(&real_index::expire_events, this));

}

void real_index::expire_events() {

  atom_attach_thread();

  VLOG(3) << "expire_fn()++";

  VLOG(3) << "index size: " << index_map_.size();

  std::vector<std::shared_ptr<Event>> expired_events;

  int64_t now = static_cast<int64_t>(sched_.unix_time());

  {

    std::lock_guard<std::mutex> lock(mutex_);

    auto it = index_map_.begin();
    while (it != index_map_.end()) {

      const auto & event(it->second);

      auto expire = event->time() + static_cast<int64_t>(event->ttl());
      if (expire < now) {
        expired_events.push_back(event);
        index_map_.erase(it++);
      } else {
        ++it;
      }

    }

  }

  VLOG(3) << "expire process took "
          << static_cast<int64_t>(sched_.unix_time()) - now << " seconds";

  for (auto & event : expired_events) {
    event->set_state("expired");
    pubsub_.publish(k_default_index, *event);
    push_event_fn_(*event);
  }

  VLOG(3) << "expire_fn()--";

  expiring_.store(false);

  atom_detach_thread();
}

real_index::~real_index() {

  VLOG(3) << "~real_index()++";

  if (expiring_.exchange(true)) {

    VLOG(3) << "expire_events thread is running";

    for (size_t attempts = k_stop_attempts; attempts > 0; attempts--) {

      if (!expiring_.exchange(true)) {
        break;
      }

      VLOG(3) << "Waiting for expiring event to finish";

      std::this_thread::sleep_for(
          std::chrono::milliseconds(k_stop_interval_check_ms));
    }

  }

  VLOG(3) << "~real_index()--";
}
<|endoftext|>