<commit_before>#include "callwindow.h"

#include "ui_callwindow.h"
#include "ui_about.h"

#include "statisticswindow.h"
#include "videoviewfactory.h"

#include "common.h"
#include "settingskeys.h"

#include <QCloseEvent>
#include <QTimer>
#include <QMetaType>
#include <QDebug>
#include <QDir>

CallWindow::CallWindow(QWidget *parent):
  QMainWindow(parent),
  ui_(new Ui::CallWindow),
  viewFactory_(std::shared_ptr<VideoviewFactory>(new VideoviewFactory)),
  settingsView_(this),
  statsWindow_(nullptr),
  conference_(this),
  partInt_(nullptr),
  timer_(new QTimer(this))
{
  ui_->setupUi(this);
}

CallWindow::~CallWindow()
{
  timer_->stop();
  delete timer_;
  if(statsWindow_)
  {
    statsWindow_->close();
    delete statsWindow_;
  }
  delete ui_;
}

void CallWindow::init(ParticipantInterface *partInt)
{
  partInt_ = partInt;

  ui_->Add_contact_widget->setVisible(false);

  viewFactory_->setSelfview(ui_->SelfView, ui_->SelfView);

  setWindowTitle("Kvazzup");

  contacts_.initializeList(ui_->contactList, partInt_);

  aboutWidget_ = new Ui::AboutWidget;
  aboutWidget_->setupUi(&about_);

  // I don't know why this is required.
  qRegisterMetaType<QVector<int> >("QVector<int>");

  QObject::connect(&settingsView_, &Settings::updateCallSettings,
                   this,           &CallWindow::updateCallSettings);

  QObject::connect(&settingsView_, &Settings::updateVideoSettings,
                   this,           &CallWindow::updateVideoSettings);

  QObject::connect(&settingsView_, &Settings::updateAudioSettings,
                   this,           &CallWindow::updateAudioSettings);

  QObject::connect(ui_->mic, &QPushButton::clicked,
                   this, &CallWindow::micButton);

  QObject::connect(ui_->camera, &QPushButton::clicked,
                   this, &CallWindow::cameraButton);

  QObject::connect(ui_->EndCallButton, SIGNAL(clicked()),
                   this, SIGNAL(endCall()));

  QObject::connect(ui_->actionClose, SIGNAL(triggered()),
                   this, SIGNAL(closed()));

  QObject::connect(ui_->address, &QLineEdit::textChanged,
                   this, &CallWindow::changedSIPText);

  QObject::connect(ui_->username, &QLineEdit::textChanged,
                   this, &CallWindow::changedSIPText);

  QObject::connect(ui_->screen_share, &QPushButton::clicked,
                   this, &CallWindow::screensShareButton);

  QMainWindow::show();

  QObject::connect(&conference_, &ConferenceView::acceptCall, this, &CallWindow::callAccepted);
  QObject::connect(&conference_, &ConferenceView::rejectCall, this, &CallWindow::callRejected);
  QObject::connect(&conference_, &ConferenceView::cancelCall, this, &CallWindow::callCancelled);

  conference_.init(ui_->participantLayout, ui_->participants);

  initButton(QDir::currentPath() + "/icons/add_contact.svg", QSize(60,60), QSize(35,35), ui_->addContact);
  initButton(QDir::currentPath() + "/icons/settings.svg", QSize(60,60), QSize(35,35), ui_->settings_button);
  initButton(QDir::currentPath() + "/icons/video_on.svg", QSize(60,60), QSize(35,35), ui_->camera);
  initButton(QDir::currentPath() + "/icons/mic_on.svg", QSize(60,60), QSize(35,35), ui_->mic);
  initButton(QDir::currentPath() + "/icons/end_call.svg", QSize(60,60), QSize(35,35), ui_->EndCallButton);
  initButton(QDir::currentPath() + "/icons/screen_share.svg", QSize(60,60), QSize(35,35), ui_->screen_share);

  ui_->buttonContainer->layout()->setAlignment(ui_->endcallHolder, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->settings_button, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->mic, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->camera, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->SelfView, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->screen_share, Qt::AlignBottom);

  ui_->contactListContainer->layout()->setAlignment(ui_->addContact, Qt::AlignHCenter);

  ui_->EndCallButton->hide();

  settingsView_.init();

  // set button icons to correct states
  setMicState(settingEnabled(SettingsKey::micStatus));
  setCameraState(settingEnabled(SettingsKey::cameraStatus));
  setScreenShareState(settingEnabled(SettingsKey::screenShareStatus));
}

void CallWindow::initButton(QString iconPath, QSize size, QSize iconSize,
                            QPushButton* button)
{
  QPixmap pixmap(iconPath);
  if(!pixmap.isNull())
  {
    QIcon ButtonIcon(pixmap);
    button->setIcon(ButtonIcon);
    button->setText("");

    button->setMaximumSize(size);
    button->setMinimumSize(size);
    button->setIconSize(iconSize);
  }
  else
  {
    qDebug() << "WARNING," << metaObject()->className() << ": Could not find icon:" << iconPath;
  }
}

StatisticsInterface* CallWindow::createStatsWindow()
{
  printNormal(this,"Initiating, CallWindow: Creating statistics window");
  statsWindow_ = new StatisticsWindow(this);

  // Stats GUI updates are handled solely by timer
  timer_->setInterval(200);
  timer_->setSingleShot(false);
  timer_->start();

  connect(timer_, SIGNAL(timeout()), statsWindow_, SLOT(update()));
  return statsWindow_;
}

void CallWindow::on_addContact_clicked()
{
  printNormal(this, "Clicked");
  QString serverAddress = settingString(SettingsKey::sipServerAddress);
  ui_->address->setText(serverAddress);
  ui_->username->setText("username");

  changedSIPText(serverAddress);
}

void CallWindow::addContact()
{
  // TODO: support dns
  QRegularExpression re_ip ("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
  QRegularExpressionMatch ip_match = re_ip.match(ui_->address->text());

  // has the user inputted correct information
  if (!ip_match.hasMatch())
  {
    ui_->addressLabel->setText("Please set an IP address!");
    ui_->addressLabel->setStyleSheet("QLabel { color : red; }");
  }
  else if (ui_->username->text() == "")
  {
    ui_->usernameLabel->setText("Please set username!");
    ui_->usernameLabel->setStyleSheet("QLabel { color : red; }");
  }
  else
  {
    contacts_.addContact(partInt_, ui_->peerName->text(), ui_->username->text(), ui_->address->text());

    // Clean the add menu after successful add
    ui_->peerName->clear();
    ui_->username->clear();
    ui_->address->clear();
    ui_->addressLabel->setText("Address");
    ui_->addressLabel->setStyleSheet("QLabel { color : black; }");

    ui_->usernameLabel->setText("Username");
    ui_->usernameLabel->setStyleSheet("QLabel { color : black; }");
    ui_->Add_contact_widget->hide();

    ui_->addContact->show();
  }
}

void CallWindow::displayOutgoingCall(uint32_t sessionID, QString name)
{
  contacts_.turnAllItemsToPlus();
  conference_.callingTo(sessionID, name); // TODO get name from contact list
}

void CallWindow::displayIncomingCall(uint32_t sessionID, QString caller)
{
  conference_.incomingCall(sessionID, caller);
}

void CallWindow::displayRinging(uint32_t sessionID)
{
  conference_.ringing(sessionID);
}

void CallWindow::openStatistics()
{
  if(statsWindow_)
  {
    statsWindow_->show();
  }
  else
  {
    qDebug() << "WARNING," << metaObject()->className()
             << ": No stats window class initiated";
  }
}

void CallWindow::closeEvent(QCloseEvent *event)
{
  emit closed();
  statsWindow_->hide();
  statsWindow_->finished(0);

  QMainWindow::closeEvent(event);
}

void CallWindow::addVideoStream(uint32_t sessionID)
{
  ui_->EndCallButton->setEnabled(true);
  ui_->EndCallButton->show();
  conference_.addVideoStream(sessionID, viewFactory_);
}

void CallWindow::setMicState(bool on)
{
  if(on)
  {
    initButton(QDir::currentPath() + "/icons/mic_on.svg", QSize(60,60), QSize(35,35), ui_->mic);
    //ui_->mic->setText("Mic off");
  }
  else
  {
    initButton(QDir::currentPath() + "/icons/mic_off.svg", QSize(60,60), QSize(35,35), ui_->mic);
    //ui_->mic->setText("Mic on");
  }
}

void CallWindow::setCameraState(bool on)
{
  if(on)
  {
    initButton(QDir::currentPath() + "/icons/video_on.svg",
               QSize(60,60), QSize(35,35), ui_->camera);
  }
  else
  {
    initButton(QDir::currentPath() + "/icons/video_off.svg",
               QSize(60,60), QSize(35,35), ui_->camera);
  }
}

void CallWindow::setScreenShareState(bool on)
{
  Q_UNUSED(on)
  // TODO: Change screen share icon
}

void CallWindow::removeParticipant(uint32_t sessionID)
{
  Q_ASSERT(sessionID != 0);

  if (sessionID == 0)
  {
    //printDebug();
    return;
  }

  if(!conference_.removeCaller(sessionID))
  {
    ui_->EndCallButton->setEnabled(false);
    ui_->EndCallButton->hide();
    contacts_.setAccessibleAll();
  }

  contacts_.setAccessible(sessionID);
  viewFactory_->clearWidgets(sessionID);
}

void CallWindow::removeWithMessage(uint32_t sessionID, QString message, bool temporaryMessage)
{
  removeParticipant(sessionID);
  conference_.attachMessageWidget(message, temporaryMessage);
}

void CallWindow::on_settings_button_clicked()
{
  settingsView_.show();
}

void CallWindow::screensShareButton()
{
  printNormal(this, "Changing state of screen share");

  // we change the state of screensharestatus setting here
  settingsView_.setScreenShareState(!settingEnabled(SettingsKey::screenShareStatus));

  emit updateVideoSettings();
}

void CallWindow::micButton(bool checked)
{
  Q_UNUSED(checked);

  bool currentState = settingEnabled(SettingsKey::micStatus);

  setMicState(!currentState);
  settingsView_.setMicState(!currentState);
  emit updateAudioSettings();
}

void CallWindow::cameraButton(bool checked)
{
  Q_UNUSED(checked);

  bool currentState = settingEnabled(SettingsKey::cameraStatus);

  setCameraState(!currentState);
  settingsView_.setCameraState(!currentState);
  emit updateVideoSettings();
}

void CallWindow::on_about_clicked()
{
  about_.show();
}

void CallWindow::changedSIPText(const QString &text)
{
  Q_UNUSED(text);
  ui_->sipAddress->setText("sip:" + ui_->username->text() + "@" + ui_->address->text());
}

void CallWindow::showICEFailedMessage()
{
  mesg_.showError("Error: ICE Failed",
                  "ICE did not succeed to find a connection. "
                  "You may try again. If the issue persists, "
                  "please report the issue to Github if you are connected to the internet "
                  "and describe your network setup.");
}

void CallWindow::showCryptoMissingMessage()
{
  mesg_.showWarning("Warning: Encryption not possible",
                    "Crypto++ has not been included in both Kvazzup and uvgRTP.");
}

void CallWindow::showZRTPFailedMessage(QString sessionID)
{
  mesg_.showError("Error: ZRTP handshake has failed for session " + sessionID,
                  "Could not exchange encryption keys.");
}
<commit_msg>fix(GUI): Close the GUI message when exiting application<commit_after>#include "callwindow.h"

#include "ui_callwindow.h"
#include "ui_about.h"

#include "statisticswindow.h"
#include "videoviewfactory.h"

#include "common.h"
#include "settingskeys.h"

#include <QCloseEvent>
#include <QTimer>
#include <QMetaType>
#include <QDebug>
#include <QDir>

CallWindow::CallWindow(QWidget *parent):
  QMainWindow(parent),
  ui_(new Ui::CallWindow),
  viewFactory_(std::shared_ptr<VideoviewFactory>(new VideoviewFactory)),
  settingsView_(this),
  statsWindow_(nullptr),
  conference_(this),
  partInt_(nullptr),
  timer_(new QTimer(this))
{
  ui_->setupUi(this);
}

CallWindow::~CallWindow()
{
  timer_->stop();
  delete timer_;
  if(statsWindow_)
  {
    statsWindow_->close();
    delete statsWindow_;
  }
  delete ui_;
}

void CallWindow::init(ParticipantInterface *partInt)
{
  partInt_ = partInt;

  ui_->Add_contact_widget->setVisible(false);

  viewFactory_->setSelfview(ui_->SelfView, ui_->SelfView);

  setWindowTitle("Kvazzup");

  contacts_.initializeList(ui_->contactList, partInt_);

  aboutWidget_ = new Ui::AboutWidget;
  aboutWidget_->setupUi(&about_);

  // I don't know why this is required.
  qRegisterMetaType<QVector<int> >("QVector<int>");

  QObject::connect(&settingsView_, &Settings::updateCallSettings,
                   this,           &CallWindow::updateCallSettings);

  QObject::connect(&settingsView_, &Settings::updateVideoSettings,
                   this,           &CallWindow::updateVideoSettings);

  QObject::connect(&settingsView_, &Settings::updateAudioSettings,
                   this,           &CallWindow::updateAudioSettings);

  QObject::connect(ui_->mic, &QPushButton::clicked,
                   this, &CallWindow::micButton);

  QObject::connect(ui_->camera, &QPushButton::clicked,
                   this, &CallWindow::cameraButton);

  QObject::connect(ui_->EndCallButton, SIGNAL(clicked()),
                   this, SIGNAL(endCall()));

  QObject::connect(ui_->actionClose, SIGNAL(triggered()),
                   this, SIGNAL(closed()));

  QObject::connect(ui_->address, &QLineEdit::textChanged,
                   this, &CallWindow::changedSIPText);

  QObject::connect(ui_->username, &QLineEdit::textChanged,
                   this, &CallWindow::changedSIPText);

  QObject::connect(ui_->screen_share, &QPushButton::clicked,
                   this, &CallWindow::screensShareButton);

  QMainWindow::show();

  QObject::connect(&conference_, &ConferenceView::acceptCall, this, &CallWindow::callAccepted);
  QObject::connect(&conference_, &ConferenceView::rejectCall, this, &CallWindow::callRejected);
  QObject::connect(&conference_, &ConferenceView::cancelCall, this, &CallWindow::callCancelled);

  conference_.init(ui_->participantLayout, ui_->participants);

  initButton(QDir::currentPath() + "/icons/add_contact.svg", QSize(60,60), QSize(35,35), ui_->addContact);
  initButton(QDir::currentPath() + "/icons/settings.svg", QSize(60,60), QSize(35,35), ui_->settings_button);
  initButton(QDir::currentPath() + "/icons/video_on.svg", QSize(60,60), QSize(35,35), ui_->camera);
  initButton(QDir::currentPath() + "/icons/mic_on.svg", QSize(60,60), QSize(35,35), ui_->mic);
  initButton(QDir::currentPath() + "/icons/end_call.svg", QSize(60,60), QSize(35,35), ui_->EndCallButton);
  initButton(QDir::currentPath() + "/icons/screen_share.svg", QSize(60,60), QSize(35,35), ui_->screen_share);

  ui_->buttonContainer->layout()->setAlignment(ui_->endcallHolder, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->settings_button, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->mic, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->camera, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->SelfView, Qt::AlignBottom);
  ui_->buttonContainer->layout()->setAlignment(ui_->screen_share, Qt::AlignBottom);

  ui_->contactListContainer->layout()->setAlignment(ui_->addContact, Qt::AlignHCenter);

  ui_->EndCallButton->hide();

  settingsView_.init();

  // set button icons to correct states
  setMicState(settingEnabled(SettingsKey::micStatus));
  setCameraState(settingEnabled(SettingsKey::cameraStatus));
  setScreenShareState(settingEnabled(SettingsKey::screenShareStatus));
}

void CallWindow::initButton(QString iconPath, QSize size, QSize iconSize,
                            QPushButton* button)
{
  QPixmap pixmap(iconPath);
  if(!pixmap.isNull())
  {
    QIcon ButtonIcon(pixmap);
    button->setIcon(ButtonIcon);
    button->setText("");

    button->setMaximumSize(size);
    button->setMinimumSize(size);
    button->setIconSize(iconSize);
  }
  else
  {
    qDebug() << "WARNING," << metaObject()->className() << ": Could not find icon:" << iconPath;
  }
}

StatisticsInterface* CallWindow::createStatsWindow()
{
  printNormal(this,"Initiating, CallWindow: Creating statistics window");
  statsWindow_ = new StatisticsWindow(this);

  // Stats GUI updates are handled solely by timer
  timer_->setInterval(200);
  timer_->setSingleShot(false);
  timer_->start();

  connect(timer_, SIGNAL(timeout()), statsWindow_, SLOT(update()));
  return statsWindow_;
}

void CallWindow::on_addContact_clicked()
{
  printNormal(this, "Clicked");
  QString serverAddress = settingString(SettingsKey::sipServerAddress);
  ui_->address->setText(serverAddress);
  ui_->username->setText("username");

  changedSIPText(serverAddress);
}

void CallWindow::addContact()
{
  // TODO: support dns
  QRegularExpression re_ip ("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
  QRegularExpressionMatch ip_match = re_ip.match(ui_->address->text());

  // has the user inputted correct information
  if (!ip_match.hasMatch())
  {
    ui_->addressLabel->setText("Please set an IP address!");
    ui_->addressLabel->setStyleSheet("QLabel { color : red; }");
  }
  else if (ui_->username->text() == "")
  {
    ui_->usernameLabel->setText("Please set username!");
    ui_->usernameLabel->setStyleSheet("QLabel { color : red; }");
  }
  else
  {
    contacts_.addContact(partInt_, ui_->peerName->text(), ui_->username->text(), ui_->address->text());

    // Clean the add menu after successful add
    ui_->peerName->clear();
    ui_->username->clear();
    ui_->address->clear();
    ui_->addressLabel->setText("Address");
    ui_->addressLabel->setStyleSheet("QLabel { color : black; }");

    ui_->usernameLabel->setText("Username");
    ui_->usernameLabel->setStyleSheet("QLabel { color : black; }");
    ui_->Add_contact_widget->hide();

    ui_->addContact->show();
  }
}

void CallWindow::displayOutgoingCall(uint32_t sessionID, QString name)
{
  contacts_.turnAllItemsToPlus();
  conference_.callingTo(sessionID, name); // TODO get name from contact list
}

void CallWindow::displayIncomingCall(uint32_t sessionID, QString caller)
{
  conference_.incomingCall(sessionID, caller);
}

void CallWindow::displayRinging(uint32_t sessionID)
{
  conference_.ringing(sessionID);
}

void CallWindow::openStatistics()
{
  if(statsWindow_)
  {
    statsWindow_->show();
  }
  else
  {
    qDebug() << "WARNING," << metaObject()->className()
             << ": No stats window class initiated";
  }
}

void CallWindow::closeEvent(QCloseEvent *event)
{
  emit closed();
  statsWindow_->hide();
  mesg_.hide();

  QMainWindow::closeEvent(event);
}

void CallWindow::addVideoStream(uint32_t sessionID)
{
  ui_->EndCallButton->setEnabled(true);
  ui_->EndCallButton->show();
  conference_.addVideoStream(sessionID, viewFactory_);
}

void CallWindow::setMicState(bool on)
{
  if(on)
  {
    initButton(QDir::currentPath() + "/icons/mic_on.svg", QSize(60,60), QSize(35,35), ui_->mic);
    //ui_->mic->setText("Mic off");
  }
  else
  {
    initButton(QDir::currentPath() + "/icons/mic_off.svg", QSize(60,60), QSize(35,35), ui_->mic);
    //ui_->mic->setText("Mic on");
  }
}

void CallWindow::setCameraState(bool on)
{
  if(on)
  {
    initButton(QDir::currentPath() + "/icons/video_on.svg",
               QSize(60,60), QSize(35,35), ui_->camera);
  }
  else
  {
    initButton(QDir::currentPath() + "/icons/video_off.svg",
               QSize(60,60), QSize(35,35), ui_->camera);
  }
}

void CallWindow::setScreenShareState(bool on)
{
  Q_UNUSED(on)
  // TODO: Change screen share icon
}

void CallWindow::removeParticipant(uint32_t sessionID)
{
  Q_ASSERT(sessionID != 0);

  if (sessionID == 0)
  {
    //printDebug();
    return;
  }

  if(!conference_.removeCaller(sessionID))
  {
    ui_->EndCallButton->setEnabled(false);
    ui_->EndCallButton->hide();
    contacts_.setAccessibleAll();
  }

  contacts_.setAccessible(sessionID);
  viewFactory_->clearWidgets(sessionID);
}

void CallWindow::removeWithMessage(uint32_t sessionID, QString message, bool temporaryMessage)
{
  removeParticipant(sessionID);
  conference_.attachMessageWidget(message, temporaryMessage);
}

void CallWindow::on_settings_button_clicked()
{
  settingsView_.show();
}

void CallWindow::screensShareButton()
{
  printNormal(this, "Changing state of screen share");

  // we change the state of screensharestatus setting here
  settingsView_.setScreenShareState(!settingEnabled(SettingsKey::screenShareStatus));

  emit updateVideoSettings();
}

void CallWindow::micButton(bool checked)
{
  Q_UNUSED(checked);

  bool currentState = settingEnabled(SettingsKey::micStatus);

  setMicState(!currentState);
  settingsView_.setMicState(!currentState);
  emit updateAudioSettings();
}

void CallWindow::cameraButton(bool checked)
{
  Q_UNUSED(checked);

  bool currentState = settingEnabled(SettingsKey::cameraStatus);

  setCameraState(!currentState);
  settingsView_.setCameraState(!currentState);
  emit updateVideoSettings();
}

void CallWindow::on_about_clicked()
{
  about_.show();
}

void CallWindow::changedSIPText(const QString &text)
{
  Q_UNUSED(text);
  ui_->sipAddress->setText("sip:" + ui_->username->text() + "@" + ui_->address->text());
}

void CallWindow::showICEFailedMessage()
{
  mesg_.showError("Error: ICE Failed",
                  "ICE did not succeed to find a connection. "
                  "You may try again. If the issue persists, "
                  "please report the issue to Github if you are connected to the internet "
                  "and describe your network setup.");
}

void CallWindow::showCryptoMissingMessage()
{
  mesg_.showWarning("Warning: Encryption not possible",
                    "Crypto++ has not been included in both Kvazzup and uvgRTP.");
}

void CallWindow::showZRTPFailedMessage(QString sessionID)
{
  mesg_.showError("Error: ZRTP handshake has failed for session " + sessionID,
                  "Could not exchange encryption keys.");
}
<|endoftext|>


<commit_before>#include <Asynchrony.h>

#ifndef NULL
	#define NULL 0
#endif

namespace Asynchrony {

	void Asynchrony::loop() {
		bool destructFlag = false;
		ForwardList<ListenerItem>::Iterator itPrev = listeners.beforeBegin(),
											itNext = itPrev;
		++itNext;

		while(true) {
			if(itNext == NULL) {
				break;
			} else {
				if((*itNext).listener->check(&destructFlag))
					(*itNext).callback();

				if(destructFlag) {
					delete (*itNext).listener;
					itPrev.eraseAfter();
					destructFlag = false;

					itNext = itPrev;
				} else {
					itPrev = itNext;
				}
				++itNext;
			}
		}
	}

	identificator Asynchrony::add(Listener* listener, void (*callback)(), int priority) {
		ListenerItem item;
		item.listener = listener;
		item.callback = callback;
		item.priority = priority;
		item.id = getIdentificator();

		ForwardList<ListenerItem>::Iterator itPrev = listeners.beforeBegin(),
											itNext = itPrev;
		++itNext;

		while(true) {
			if(itNext == NULL || priority > (*itNext).priority) {
				itPrev.insertAfter(item);
				break;
			} else {
				itPrev = itNext;
				++itNext;
			}
		}

		return item.id;
	}

	void Asynchrony::remove(identificator id, bool deleteListener) {
		ForwardList<ListenerItem>::Iterator itPrev = listeners.beforeBegin(),
											itNext = itPrev;
		++itNext;

		while(true) {
			if(itNext == NULL) {
				break;
			} else if(id == (*itNext).id) {
				if(deleteListener)
					delete (*itNext).listener;
				itPrev.eraseAfter();
				break;
			} {
				itPrev = itNext;
				++itNext;
			}
		}
	}

	identificator Asynchrony::getIdentificator() {
		return ++lastIdentificator;
	}

	#if defined(ARDUINO)

		identificator Asynchrony::click(void (*callback)(), int pin, bool eventState, char mode, unsigned long bounce) {
			return add(new Click(pin, eventState, mode, bounce), callback);
		}

		identificator Asynchrony::interval(void (*callback)(), unsigned long time, char timeUnit) {
			return add(new Interval(time, timeUnit), callback);
		}

		identificator Asynchrony::timeout(void (*callback)(), unsigned long time, char timeUnit) {
			return add(new Timeout(time, timeUnit), callback);
		}

	#endif
}

Asynchrony::Asynchrony Asyn;<commit_msg>Awfull bug fix<commit_after>#include <Asynchrony.h>

#ifndef NULL
	#define NULL 0
#endif

namespace Asynchrony {

	void Asynchrony::loop() {
		bool destructFlag = false;
		ForwardList<ListenerItem>::Iterator itPrev = listeners.beforeBegin(),
											itNext = itPrev;
		++itNext;

		while(true) {
			if(itNext == NULL) {
				break;
			} else {
				if((*itNext).listener->check(&destructFlag))
					(*itNext).callback();

				if(destructFlag) {
					delete (*itNext).listener;
					itPrev.eraseAfter();
					destructFlag = false;

					itNext = itPrev;
				} else {
					itPrev = itNext;
				}
				++itNext;
			}
		}
	}

	identificator Asynchrony::add(Listener* listener, void (*callback)(), int priority) {
		ListenerItem item;
		item.listener = listener;
		item.callback = callback;
		item.priority = priority;
		item.id = getIdentificator();

		ForwardList<ListenerItem>::Iterator itPrev = listeners.beforeBegin(),
											itNext = itPrev;
		++itNext;

		while(true) {
			if(itNext == NULL || priority > (*itNext).priority) {
				itPrev.insertAfter(item);
				break;
			} else {
				itPrev = itNext;
				++itNext;
			}
		}

		return item.id;
	}

	void Asynchrony::remove(identificator id, bool deleteListener) {
		ForwardList<ListenerItem>::Iterator itPrev = listeners.beforeBegin(),
											itNext = itPrev;
		++itNext;

		while(true) {
			if(itNext == NULL) {
				break;
			} else if(id == (*itNext).id) {
				if(deleteListener)
					delete (*itNext).listener;
				itPrev.eraseAfter();
				break;
			} else {
				itPrev = itNext;
				++itNext;
			}
		}
	}

	identificator Asynchrony::getIdentificator() {
		return ++lastIdentificator;
	}

	#if defined(ARDUINO)

		identificator Asynchrony::click(void (*callback)(), int pin, bool eventState, char mode, unsigned long bounce) {
			return add(new Click(pin, eventState, mode, bounce), callback);
		}

		identificator Asynchrony::interval(void (*callback)(), unsigned long time, char timeUnit) {
			return add(new Interval(time, timeUnit), callback);
		}

		identificator Asynchrony::timeout(void (*callback)(), unsigned long time, char timeUnit) {
			return add(new Timeout(time, timeUnit), callback);
		}

	#endif
}

Asynchrony::Asynchrony Asyn;<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 midnightBITS
 *
 * 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.
 */

#include "pch.h"

#include <assert.h>
#include <cctype>

#include <languages.hpp>
#include <streams.hpp>
#include <strings.hpp>

namespace locale {

	std::string warp(const std::string& s)
	{
		auto w = utf::widen(s);
		for (auto& c : w) {
			switch (c) {
			case L'a': c = 0x0227; break; // 'ȧ'
			case L'b': c = 0x018b; break; // 'Ƌ'
			case L'c': c = 0x00e7; break; // 'ç'
			case L'd': c = 0x0111; break; // 'đ'
			case L'e': c = 0x00ea; break; // 'ê'
			case L'f': c = 0x0192; break; // 'ƒ'
			case L'g': c = 0x011f; break; // 'ğ'
			case L'h': c = 0x0125; break; // 'ĥ'
			case L'i': c = 0x00ef; break; // 'ï'
			case L'j': c = 0x0135; break; // 'ĵ'
			case L'k': c = 0x0137; break; // 'ķ'
			case L'l': c = 0x013a; break; // 'ĺ'
			case L'n': c = 0x00f1; break; // 'ñ'
			case L'o': c = 0x00f4; break; // 'ô'
			case L'r': c = 0x0213; break; // 'ȓ'
			case L's': c = 0x015f; break; // 'ş'
			case L't': c = 0x0167; break; // 'ŧ'
			case L'u': c = 0x0169; break; // 'ũ'
			case L'w': c = 0x0175; break; // 'ŵ'
			case L'y': c = 0x00ff; break; // 'ÿ'
			case L'z': c = 0x0225; break; // 'ȥ'
			case L'A': c = 0x00c4; break; // 'Ä'
			case L'B': c = 0x00df; break; // 'ß'
			case L'C': c = 0x00c7; break; // 'Ç'
			case L'D': c = 0x00d0; break; // 'Ð'
			case L'E': c = 0x0204; break; // 'Ȅ'
			case L'F': c = 0x0191; break; // 'Ƒ'
			case L'G': c = 0x0120; break; // 'Ġ'
			case L'H': c = 0x0126; break; // 'Ħ'
			case L'I': c = 0x00cd; break; // 'Í'
			case L'J': c = 0x0134; break; // 'Ĵ'
			case L'K': c = 0x0136; break; // 'Ķ'
			case L'L': c = 0x023d; break; // 'Ƚ'
			case L'N': c = 0x00d1; break; // 'Ñ'
			case L'O': c = 0x00d6; break; // 'Ö'
			case L'R': c = 0x0154; break; // 'Ŕ'
			case L'S': c = 0x015e; break; // 'Ş'
			case L'T': c = 0x023e; break; // 'Ⱦ'
			case L'U': c = 0x00d9; break; // 'Ù'
			case L'W': c = 0x0174; break; // 'Ŵ'
			case L'Y': c = 0x00dd; break; // 'Ý'
			case L'Z': c = 0x0224; break; // 'Ȥ'
			case L'"': c = L'?';   break; // '?'
			};
		}
		return utf::narrowed(w);
	}

	std::vector<string> translations(const std::map<std::string, std::string>& gtt, const std::vector<locale::String>& strings, bool warp_missing, bool verbose)
	{
		std::vector<string> out;
		out.reserve(gtt.empty() ? 0 : gtt.size() - 1);

		for (auto& str : strings) {
			auto it = gtt.find(str.key);
			if (it == gtt.end()) {
				if (verbose)
					printf("warning: translation for `%s' missing.\n", str.key.c_str());
				if (warp_missing)
					out.emplace_back(str.id, warp(str.value));
				continue;
			}
			out.emplace_back(str.id, it->second);
		}

		return std::move(out);
	}

	std::map<std::string, std::string> attrGTT(const std::string& attrs)
	{
		std::map<std::string, std::string> out;

		auto c = std::begin(attrs);
		auto e = std::end(attrs);
		while (c != e) {
			while (c != e && std::isspace((uint8_t)*c)) ++c;

			auto s_name = c;
			while (c != e && !std::isspace((uint8_t)*c)) {
				if (*c == ':')
					break;
				++c;
			}
			auto name = std::string{ s_name, c };

			while (c != e && std::isspace((uint8_t)*c)) ++c;
			if (c == e || *c != ':')
				continue;
			++c;

			while (c != e && std::isspace((uint8_t)*c) && *c != '\n') ++c;

			auto s_value = c;
			while (c != e && *c != '\n') ++c;
			if (c != e) ++c;
			auto e_value = c;

			while (s_value != e_value && std::isspace((uint8_t)e_value[-1])) --e_value;
			out[name] = { s_value, e_value };
		}

		return out;
	}

	std::vector<string> attributes(const std::map<std::string, std::string>& gtt)
	{
		std::vector<string> props;
		auto it = gtt.find("");
		auto attrs = attrGTT(it == gtt.end() ? std::string{ } : it->second);

		props.push_back({ ATTR_CULTURE, attrs["Language"] });
		auto attr = attrs.find("Plural-Forms");
		if (attr != attrs.end())
			props.push_back({ ATTR_PLURALS, attr->second });
		// TODO: ATTR_LANGUAGE

		return std::move(props);
	}

	char nextc(locale::instream& is)
	{
		char c;
		is.read(&c, 1);
		return c;
	}

	bool ll_code(locale::instream& is, std::string& code, std::string& name, const std::string& fname, bool ret)
	{
		code.clear();
		name.clear();

		while (!is.eof() && std::isspace((uint8_t)is.peek()))
			nextc(is);

		if (is.eof())
			return false;

		while (!is.eof() && !std::isspace((uint8_t)is.peek()))
			code.push_back(nextc(is));

		while (!is.eof() && std::isspace((uint8_t)is.peek())) {
			auto c = nextc(is);
			if (c == '\n') {
				fprintf(stderr, "error: `%s' does not contain name in %s\n", code.c_str(), fname.c_str());
				ret = false;
				return false;
			}
		}

		while (!is.eof() && is.peek() != '\n')
			name.push_back(nextc(is));

		if (!is.eof())
			nextc(is);

		auto len = name.length();
		while (len > 0 && std::isspace((uint8_t)name[len - 1]))
			--len;
		if (len != name.length())
			name = name.substr(0, len);

		return true;
	}

	bool ll_CC(const fs::path& in, std::map<std::string, std::string>& langs)
	{
		auto inname = in;
		inname.make_preferred();

		std::unique_ptr<FILE, decltype(&fclose)> inf{ fs::fopen(in, "rb"), fclose };
		if (!inf) {
			fprintf(stderr, "could not open `%s'", inname.string().c_str());
			return false;
		}

		locale::finstream is{ inf.get() };
		std::string code, name;
		bool ret = true;
		while (ll_code(is, code, name, inname.string(), ret) && ret)
			langs[code] = name;

		return ret;
	}

#define WRITE(os, I) if (!os.write(I)) return -1;
#define WRITESTR(os, S) if (os.write(S) != (S).length()) return -1;
#define CARRY(ex) do { auto ret = (ex); if (ret) return ret; } while (0)

	namespace {
		int header(locale::outstream& os, uint32_t& next_offset, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			WRITE(os, (uint32_t)block.size());
			WRITE(os, next_offset);
			next_offset += (uint32_t)(sizeof(string_key) * block.size());
			return 0;
		}

		void update_offsets(uint32_t& next_offset, std::vector<string>& block)
		{
			for (auto& str : block) {
				str.key.offset = next_offset;
				next_offset += str.key.length;
				++next_offset;
			}
		}

		int list(locale::outstream& os, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			for (auto& str : block)
				WRITE(os, str.key);

			return 0;
		}

		int data(locale::outstream& os, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			for (auto& str : block) {
				WRITESTR(os, str.value);
				WRITE(os, '\0');
			}

			return 0;
		}

		int section(locale::outstream& os, uint32_t section_id, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			uint32_t key_size = sizeof(string_key) / sizeof(uint32_t);
			key_size *= (uint32_t)block.size();

			string_header hdr;
			hdr.id = section_id;
			hdr.string_offset = key_size + sizeof(string_header) / sizeof(uint32_t);
			hdr.ints = hdr.string_offset - sizeof(section_header) / sizeof(uint32_t);
			hdr.string_count = (uint32_t)block.size();

			uint32_t offset = 0;
			update_offsets(offset, block);
			uint32_t padding = (((offset + 3) >> 2) << 2) - offset;
			offset += padding;
			offset /= sizeof(uint32_t);
			hdr.ints += offset;

			WRITE(os, hdr);

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4127)
#endif

			CARRY(list(os, block));
			CARRY(data(os, block));

#ifdef _MSC_VER
#pragma warning(pop)
#endif

			while (padding--) {
				WRITE(os, '\0');
			}

			return 0;
		}
	}

	int file::write(locale::outstream& os)
	{
		constexpr uint32_t header_size = 3 * sizeof(uint32_t);

		file_header hdr;
		hdr.id = hdrtext_tag;
		hdr.ints = (sizeof(file_header) - sizeof(section_header)) / sizeof(uint32_t);
		hdr.version = v1_0::version;
		hdr.serial = serial;

		WRITE(os, langtext_tag);
		WRITE(os, hdr);

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4127)
#endif

		CARRY(section(os, attrtext_tag, attrs));
		CARRY(section(os, strstext_tag, strings));
		CARRY(section(os, keystext_tag, keys));

#ifdef _MSC_VER
#pragma warning(pop)
#endif

		WRITE(os, lasttext_tag);
		WRITE(os, (size_t)0);

		return 0;
	}

#undef WRITE
#undef WRITESTR
#undef CARRY
}
<commit_msg>Switching fomr GNU ll_CC to ISO ll-CC<commit_after>/*
 * Copyright (C) 2015 midnightBITS
 *
 * 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.
 */

#include "pch.h"

#include <assert.h>
#include <cctype>

#include <languages.hpp>
#include <streams.hpp>
#include <strings.hpp>

namespace locale {

	std::string warp(const std::string& s)
	{
		auto w = utf::widen(s);
		for (auto& c : w) {
			switch (c) {
			case L'a': c = 0x0227; break; // 'ȧ'
			case L'b': c = 0x018b; break; // 'Ƌ'
			case L'c': c = 0x00e7; break; // 'ç'
			case L'd': c = 0x0111; break; // 'đ'
			case L'e': c = 0x00ea; break; // 'ê'
			case L'f': c = 0x0192; break; // 'ƒ'
			case L'g': c = 0x011f; break; // 'ğ'
			case L'h': c = 0x0125; break; // 'ĥ'
			case L'i': c = 0x00ef; break; // 'ï'
			case L'j': c = 0x0135; break; // 'ĵ'
			case L'k': c = 0x0137; break; // 'ķ'
			case L'l': c = 0x013a; break; // 'ĺ'
			case L'n': c = 0x00f1; break; // 'ñ'
			case L'o': c = 0x00f4; break; // 'ô'
			case L'r': c = 0x0213; break; // 'ȓ'
			case L's': c = 0x015f; break; // 'ş'
			case L't': c = 0x0167; break; // 'ŧ'
			case L'u': c = 0x0169; break; // 'ũ'
			case L'w': c = 0x0175; break; // 'ŵ'
			case L'y': c = 0x00ff; break; // 'ÿ'
			case L'z': c = 0x0225; break; // 'ȥ'
			case L'A': c = 0x00c4; break; // 'Ä'
			case L'B': c = 0x00df; break; // 'ß'
			case L'C': c = 0x00c7; break; // 'Ç'
			case L'D': c = 0x00d0; break; // 'Ð'
			case L'E': c = 0x0204; break; // 'Ȅ'
			case L'F': c = 0x0191; break; // 'Ƒ'
			case L'G': c = 0x0120; break; // 'Ġ'
			case L'H': c = 0x0126; break; // 'Ħ'
			case L'I': c = 0x00cd; break; // 'Í'
			case L'J': c = 0x0134; break; // 'Ĵ'
			case L'K': c = 0x0136; break; // 'Ķ'
			case L'L': c = 0x023d; break; // 'Ƚ'
			case L'N': c = 0x00d1; break; // 'Ñ'
			case L'O': c = 0x00d6; break; // 'Ö'
			case L'R': c = 0x0154; break; // 'Ŕ'
			case L'S': c = 0x015e; break; // 'Ş'
			case L'T': c = 0x023e; break; // 'Ⱦ'
			case L'U': c = 0x00d9; break; // 'Ù'
			case L'W': c = 0x0174; break; // 'Ŵ'
			case L'Y': c = 0x00dd; break; // 'Ý'
			case L'Z': c = 0x0224; break; // 'Ȥ'
			case L'"': c = L'?';   break; // '?'
			};
		}
		return utf::narrowed(w);
	}

	std::vector<string> translations(const std::map<std::string, std::string>& gtt, const std::vector<locale::String>& strings, bool warp_missing, bool verbose)
	{
		std::vector<string> out;
		out.reserve(gtt.empty() ? 0 : gtt.size() - 1);

		for (auto& str : strings) {
			auto it = gtt.find(str.key);
			if (it == gtt.end()) {
				if (verbose)
					printf("warning: translation for `%s' missing.\n", str.key.c_str());
				if (warp_missing)
					out.emplace_back(str.id, warp(str.value));
				continue;
			}
			out.emplace_back(str.id, it->second);
		}

		return std::move(out);
	}

	std::map<std::string, std::string> attrGTT(const std::string& attrs)
	{
		std::map<std::string, std::string> out;

		auto c = std::begin(attrs);
		auto e = std::end(attrs);
		while (c != e) {
			while (c != e && std::isspace((uint8_t)*c)) ++c;

			auto s_name = c;
			while (c != e && !std::isspace((uint8_t)*c)) {
				if (*c == ':')
					break;
				++c;
			}
			auto name = std::string{ s_name, c };

			while (c != e && std::isspace((uint8_t)*c)) ++c;
			if (c == e || *c != ':')
				continue;
			++c;

			while (c != e && std::isspace((uint8_t)*c) && *c != '\n') ++c;

			auto s_value = c;
			while (c != e && *c != '\n') ++c;
			if (c != e) ++c;
			auto e_value = c;

			while (s_value != e_value && std::isspace((uint8_t)e_value[-1])) --e_value;
			out[name] = { s_value, e_value };
		}

		return out;
	}

	static std::string gnu2iso(std::string s)
	{
		size_t i = 0;
		for (auto& c : s) {
			if (c == '_') {
				c = '.';
			} else if (c == '.') { // ll_CC.code?
				s = s.substr(0, i);
				break;
			}

			++i;
		}

		return s;
	}

	std::vector<string> attributes(const std::map<std::string, std::string>& gtt)
	{
		std::vector<string> props;
		auto it = gtt.find("");
		auto attrs = attrGTT(it == gtt.end() ? std::string{ } : it->second);

		props.push_back({ ATTR_CULTURE, gnu2iso(attrs["Language"]) });
		auto attr = attrs.find("Plural-Forms");
		if (attr != attrs.end())
			props.push_back({ ATTR_PLURALS, attr->second });
		// TODO: ATTR_LANGUAGE

		return std::move(props);
	}

	char nextc(locale::instream& is)
	{
		char c;
		is.read(&c, 1);
		return c;
	}

	bool ll_code(locale::instream& is, std::string& code, std::string& name, const std::string& fname, bool ret)
	{
		code.clear();
		name.clear();

		while (!is.eof() && std::isspace((uint8_t)is.peek()))
			nextc(is);

		if (is.eof())
			return false;

		while (!is.eof() && !std::isspace((uint8_t)is.peek()))
			code.push_back(nextc(is));

		while (!is.eof() && std::isspace((uint8_t)is.peek())) {
			auto c = nextc(is);
			if (c == '\n') {
				fprintf(stderr, "error: `%s' does not contain name in %s\n", code.c_str(), fname.c_str());
				ret = false;
				return false;
			}
		}

		while (!is.eof() && is.peek() != '\n')
			name.push_back(nextc(is));

		if (!is.eof())
			nextc(is);

		auto len = name.length();
		while (len > 0 && std::isspace((uint8_t)name[len - 1]))
			--len;
		if (len != name.length())
			name = name.substr(0, len);

		return true;
	}

	bool ll_CC(const fs::path& in, std::map<std::string, std::string>& langs)
	{
		auto inname = in;
		inname.make_preferred();

		std::unique_ptr<FILE, decltype(&fclose)> inf{ fs::fopen(in, "rb"), fclose };
		if (!inf) {
			fprintf(stderr, "could not open `%s'", inname.string().c_str());
			return false;
		}

		locale::finstream is{ inf.get() };
		std::string code, name;
		bool ret = true;
		while (ll_code(is, code, name, inname.string(), ret) && ret)
			langs[code] = name;

		return ret;
	}

#define WRITE(os, I) if (!os.write(I)) return -1;
#define WRITESTR(os, S) if (os.write(S) != (S).length()) return -1;
#define CARRY(ex) do { auto ret = (ex); if (ret) return ret; } while (0)

	namespace {
		int header(locale::outstream& os, uint32_t& next_offset, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			WRITE(os, (uint32_t)block.size());
			WRITE(os, next_offset);
			next_offset += (uint32_t)(sizeof(string_key) * block.size());
			return 0;
		}

		void update_offsets(uint32_t& next_offset, std::vector<string>& block)
		{
			for (auto& str : block) {
				str.key.offset = next_offset;
				next_offset += str.key.length;
				++next_offset;
			}
		}

		int list(locale::outstream& os, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			for (auto& str : block)
				WRITE(os, str.key);

			return 0;
		}

		int data(locale::outstream& os, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			for (auto& str : block) {
				WRITESTR(os, str.value);
				WRITE(os, '\0');
			}

			return 0;
		}

		int section(locale::outstream& os, uint32_t section_id, std::vector<string>& block)
		{
			if (block.empty())
				return 0;

			uint32_t key_size = sizeof(string_key) / sizeof(uint32_t);
			key_size *= (uint32_t)block.size();

			string_header hdr;
			hdr.id = section_id;
			hdr.string_offset = key_size + sizeof(string_header) / sizeof(uint32_t);
			hdr.ints = hdr.string_offset - sizeof(section_header) / sizeof(uint32_t);
			hdr.string_count = (uint32_t)block.size();

			uint32_t offset = 0;
			update_offsets(offset, block);
			uint32_t padding = (((offset + 3) >> 2) << 2) - offset;
			offset += padding;
			offset /= sizeof(uint32_t);
			hdr.ints += offset;

			WRITE(os, hdr);

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4127)
#endif

			CARRY(list(os, block));
			CARRY(data(os, block));

#ifdef _MSC_VER
#pragma warning(pop)
#endif

			while (padding--) {
				WRITE(os, '\0');
			}

			return 0;
		}
	}

	int file::write(locale::outstream& os)
	{
		constexpr uint32_t header_size = 3 * sizeof(uint32_t);

		file_header hdr;
		hdr.id = hdrtext_tag;
		hdr.ints = (sizeof(file_header) - sizeof(section_header)) / sizeof(uint32_t);
		hdr.version = v1_0::version;
		hdr.serial = serial;

		WRITE(os, langtext_tag);
		WRITE(os, hdr);

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4127)
#endif

		CARRY(section(os, attrtext_tag, attrs));
		CARRY(section(os, strstext_tag, strings));
		CARRY(section(os, keystext_tag, keys));

#ifdef _MSC_VER
#pragma warning(pop)
#endif

		WRITE(os, lasttext_tag);
		WRITE(os, (size_t)0);

		return 0;
	}

#undef WRITE
#undef WRITESTR
#undef CARRY
}
<|endoftext|>


<commit_before>/** \file
 *
 * Unit tests for the Features API, which lets us attach metadata to Alignments and MultipathAlignments.
 */

#include <iostream>
#include <sstream>
#include "../features.hpp"

#include "catch.hpp"

namespace vg {
namespace unittest {

using namespace std;

TEST_CASE("Tag features work", "[features][alignment]") {

    Alignment aln;

    SECTION("Feature starts not present") {
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
    }

    SECTION("Feature is present after addition") {
        add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG);

        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        SECTION("Feature can be removed again") {
            remove_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG);

            REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
        }
    }

    SECTION("Feature can be added with a bool value") {
        SECTION("False does not set it") {
            add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, false);
            REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
        }

        SECTION("True sets it") {
            add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, true);
            REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
        }
    }

    SECTION("Feature can be set") {
        add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        set_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, true);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        set_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, false);
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        set_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, true);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
    }
}

TEST_CASE("Single-value features work", "[features][alignment]") {

    Alignment aln;

    SECTION("Features start not present") {
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
    }

    SECTION("Feature is present after addition") {
        add_feature(aln, FeatureType::HAPLOTYPE_LOGPROB, 1.0);

        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
        REQUIRE(get_feature(aln, FeatureType::HAPLOTYPE_LOGPROB) == 1.0);
    }
}

}
}

<commit_msg>Test the multi-valued features too<commit_after>/** \file
 *
 * Unit tests for the Features API, which lets us attach metadata to Alignments and MultipathAlignments.
 */

#include <iostream>
#include <sstream>
#include "../features.hpp"

#include "catch.hpp"

namespace vg {
namespace unittest {

using namespace std;

TEST_CASE("Tag features work", "[features][alignment]") {

    Alignment aln;

    SECTION("Feature starts not present") {
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
    }

    SECTION("Feature is present after addition") {
        add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG);

        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        SECTION("Feature can be removed again") {
            remove_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG);

            REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
        }
    }

    SECTION("Feature can be added with a bool value") {
        SECTION("False does not set it") {
            add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, false);
            REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
        }

        SECTION("True sets it") {
            add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, true);
            REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
        }
    }

    SECTION("Feature can be set") {
        add_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        set_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, true);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        set_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, false);
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));

        set_feature(&aln, FeatureType::HAPLOTYPE_SCORED_TAG, true);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_SCORED_TAG));
    }
}

TEST_CASE("Single-value features work", "[features][alignment]") {

    Alignment aln;

    SECTION("Features start not present") {
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
    }

    SECTION("Feature is present after addition") {
        add_feature(&aln, FeatureType::HAPLOTYPE_LOGPROB, 1.0);

        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
        REQUIRE(get_feature(aln, FeatureType::HAPLOTYPE_LOGPROB) == 1.0);

        SECTION("Feature can be removed") {
            remove_feature(&aln, FeatureType::HAPLOTYPE_LOGPROB);
            REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
        }
    }

    SECTION("Feature can be set") {
        set_feature(&aln, FeatureType::HAPLOTYPE_LOGPROB, 1.0);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
        REQUIRE(get_feature(aln, FeatureType::HAPLOTYPE_LOGPROB) == 1.0);

        set_feature(&aln, FeatureType::HAPLOTYPE_LOGPROB, 15);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
        REQUIRE(get_feature(aln, FeatureType::HAPLOTYPE_LOGPROB) == (double)15);

        set_feature(&aln, FeatureType::HAPLOTYPE_LOGPROB, 2.0);
        REQUIRE(has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
        REQUIRE(get_feature(aln, FeatureType::HAPLOTYPE_LOGPROB) == 2.0);

        remove_feature(&aln, FeatureType::HAPLOTYPE_LOGPROB);
        REQUIRE(!has_feature(aln, FeatureType::HAPLOTYPE_LOGPROB));
    }
}

TEST_CASE("Multi-value features work", "[features][alignment]") {
    Alignment aln;

    SECTION("Features start not present") {
        REQUIRE(!has_feature(aln, FeatureType::SECONDARY_SCORES));
    }

    SECTION("Feature is present after addition") {
        add_feature(&aln, FeatureType::SECONDARY_SCORES, 1.0);

        REQUIRE(has_feature(aln, FeatureType::SECONDARY_SCORES));
        REQUIRE(get_feature(aln, FeatureType::SECONDARY_SCORES) == 1.0);
        auto vals = get_features(aln, FeatureType::SECONDARY_SCORES);
        REQUIRE(vals.size() == 1);
        REQUIRE(vals[0] == 1.0);

        SECTION("Feature can be removed") {
            remove_feature(&aln, FeatureType::SECONDARY_SCORES);
            REQUIRE(!has_feature(aln, FeatureType::SECONDARY_SCORES));

            auto vals = get_features(aln, FeatureType::SECONDARY_SCORES);
            REQUIRE(vals.size() == 0);
        }

        SECTION("More values can be added") {
            add_feature(&aln, FeatureType::SECONDARY_SCORES, 2.0);
            add_feature(&aln, FeatureType::SECONDARY_SCORES, 3.0);

            REQUIRE(get_feature(aln, FeatureType::SECONDARY_SCORES) == 1.0);
            auto vals = get_features(aln, FeatureType::SECONDARY_SCORES);
            REQUIRE(vals.size() == 3);
            REQUIRE(vals[0] == 1.0);
            REQUIRE(vals[1] == 2.0);
            REQUIRE(vals[2] == 3.0);

            SECTION("All values can be removed") {
                remove_feature(&aln, FeatureType::SECONDARY_SCORES);
                REQUIRE(!has_feature(aln, FeatureType::SECONDARY_SCORES));

                auto vals = get_features(aln, FeatureType::SECONDARY_SCORES);
                REQUIRE(vals.size() == 0);
            }
        }
    }
}

}
}

<|endoftext|>


<commit_before>// Copyright 2014 BitPay Inc.
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <stdint.h>
#include <ctype.h>
#include <sstream>
#include "univalue.h"

using namespace std;

static const UniValue nullValue;

void UniValue::clear()
{
    typ = VNULL;
    val.clear();
    keys.clear();
    values.clear();
}

bool UniValue::setNull()
{
    clear();
    return true;
}

bool UniValue::setBool(bool val_)
{
    clear();
    typ = VBOOL;
    if (val_)
        val = "1";
    return true;
}

static bool validNumStr(const string& s)
{
    string tokenVal;
    unsigned int consumed;
    enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str());
    return (tt == JTOK_NUMBER);
}

bool UniValue::setNumStr(const string& val_)
{
    if (!validNumStr(val))
        return false;

    clear();
    typ = VNUM;
    val = val_;
    return true;
}

bool UniValue::setInt(uint64_t val)
{
    string s;
    ostringstream oss;

    oss << val;

    return setNumStr(oss.str());
}

bool UniValue::setInt(int64_t val)
{
    string s;
    ostringstream oss;

    oss << val;

    return setNumStr(oss.str());
}

bool UniValue::setFloat(double val)
{
    string s;
    ostringstream oss;

    oss << val;

    return setNumStr(oss.str());
}

bool UniValue::setStr(const string& val_)
{
    clear();
    typ = VSTR;
    val = val_;
    return true;
}

bool UniValue::setArray()
{
    clear();
    typ = VARR;
    return true;
}

bool UniValue::setObject()
{
    clear();
    typ = VOBJ;
    return true;
}

bool UniValue::push_back(const UniValue& val)
{
    if (typ != VARR)
        return false;

    values.push_back(val);
    return true;
}

bool UniValue::push_backV(const std::vector<UniValue>& vec)
{
    if (typ != VARR)
        return false;

    values.insert(values.end(), vec.begin(), vec.end());

    return true;
}

bool UniValue::pushKV(const std::string& key, const UniValue& val)
{
    if (typ != VOBJ)
        return false;

    keys.push_back(key);
    values.push_back(val);
    return true;
}

bool UniValue::pushKVs(const UniValue& obj)
{
    if (typ != VOBJ || obj.typ != VOBJ)
        return false;

    for (unsigned int i = 0; i < obj.keys.size(); i++) {
        keys.push_back(obj.keys[i]);
        values.push_back(obj.values[i]);
    }

    return true;
}

int UniValue::findKey(const std::string& key) const
{
    for (unsigned int i = 0; i < keys.size(); i++) {
        if (keys[i] == key)
            return (int) i;
    }

    return -1;
}

bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
{
    for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
         it != t.end(); it++) {
        int idx = findKey(it->first);
        if (idx < 0)
            return false;

        if (values[idx].getType() != it->second)
            return false;
    }

    return true;
}

const UniValue& UniValue::operator[](const std::string& key) const
{
    if (typ != VOBJ)
        return nullValue;

    int index = findKey(key);
    if (index < 0)
        return nullValue;

    return values[index];
}

const UniValue& UniValue::operator[](unsigned int index) const
{
    if (typ != VOBJ && typ != VARR)
        return nullValue;
    if (index >= values.size())
        return nullValue;

    return values[index];
}

const char *uvTypeName(UniValue::VType t)
{
    switch (t) {
    case UniValue::VNULL: return "null";
    case UniValue::VBOOL: return "bool";
    case UniValue::VOBJ: return "object";
    case UniValue::VARR: return "array";
    case UniValue::VSTR: return "string";
    case UniValue::VNUM: return "number";
    }

    // not reached
    return NULL;
}

<commit_msg>UniValue: use correct setNumStr() input val, when setting number values<commit_after>// Copyright 2014 BitPay Inc.
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <stdint.h>
#include <ctype.h>
#include <sstream>
#include "univalue.h"

using namespace std;

static const UniValue nullValue;

void UniValue::clear()
{
    typ = VNULL;
    val.clear();
    keys.clear();
    values.clear();
}

bool UniValue::setNull()
{
    clear();
    return true;
}

bool UniValue::setBool(bool val_)
{
    clear();
    typ = VBOOL;
    if (val_)
        val = "1";
    return true;
}

static bool validNumStr(const string& s)
{
    string tokenVal;
    unsigned int consumed;
    enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str());
    return (tt == JTOK_NUMBER);
}

bool UniValue::setNumStr(const string& val_)
{
    if (!validNumStr(val_))
        return false;

    clear();
    typ = VNUM;
    val = val_;
    return true;
}

bool UniValue::setInt(uint64_t val)
{
    string s;
    ostringstream oss;

    oss << val;

    return setNumStr(oss.str());
}

bool UniValue::setInt(int64_t val)
{
    string s;
    ostringstream oss;

    oss << val;

    return setNumStr(oss.str());
}

bool UniValue::setFloat(double val)
{
    string s;
    ostringstream oss;

    oss << val;

    return setNumStr(oss.str());
}

bool UniValue::setStr(const string& val_)
{
    clear();
    typ = VSTR;
    val = val_;
    return true;
}

bool UniValue::setArray()
{
    clear();
    typ = VARR;
    return true;
}

bool UniValue::setObject()
{
    clear();
    typ = VOBJ;
    return true;
}

bool UniValue::push_back(const UniValue& val)
{
    if (typ != VARR)
        return false;

    values.push_back(val);
    return true;
}

bool UniValue::push_backV(const std::vector<UniValue>& vec)
{
    if (typ != VARR)
        return false;

    values.insert(values.end(), vec.begin(), vec.end());

    return true;
}

bool UniValue::pushKV(const std::string& key, const UniValue& val)
{
    if (typ != VOBJ)
        return false;

    keys.push_back(key);
    values.push_back(val);
    return true;
}

bool UniValue::pushKVs(const UniValue& obj)
{
    if (typ != VOBJ || obj.typ != VOBJ)
        return false;

    for (unsigned int i = 0; i < obj.keys.size(); i++) {
        keys.push_back(obj.keys[i]);
        values.push_back(obj.values[i]);
    }

    return true;
}

int UniValue::findKey(const std::string& key) const
{
    for (unsigned int i = 0; i < keys.size(); i++) {
        if (keys[i] == key)
            return (int) i;
    }

    return -1;
}

bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
{
    for (std::map<std::string,UniValue::VType>::const_iterator it = t.begin();
         it != t.end(); it++) {
        int idx = findKey(it->first);
        if (idx < 0)
            return false;

        if (values[idx].getType() != it->second)
            return false;
    }

    return true;
}

const UniValue& UniValue::operator[](const std::string& key) const
{
    if (typ != VOBJ)
        return nullValue;

    int index = findKey(key);
    if (index < 0)
        return nullValue;

    return values[index];
}

const UniValue& UniValue::operator[](unsigned int index) const
{
    if (typ != VOBJ && typ != VARR)
        return nullValue;
    if (index >= values.size())
        return nullValue;

    return values[index];
}

const char *uvTypeName(UniValue::VType t)
{
    switch (t) {
    case UniValue::VNULL: return "null";
    case UniValue::VBOOL: return "bool";
    case UniValue::VOBJ: return "object";
    case UniValue::VARR: return "array";
    case UniValue::VSTR: return "string";
    case UniValue::VNUM: return "number";
    }

    // not reached
    return NULL;
}

<|endoftext|>


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

#ifndef _BufferQueue_hxx_
#define _BufferQueue_hxx_

#include <cstdint>
#include <cstdlib>

#include <os/OS.hxx>

class BufferPool;

/** main buffer pool instance */
extern BufferPool *mainBufferPool;

/** Buffer structure that contains both metadata and user data */
class Buffer
{
public:
    /** Free this buffer to the BufferPool from whence it came.
     */
    inline void free();

    /** Advance the position of the buffer.
     * @param bytes number of bytes to advance.
     * @return pointer to the new position (next available byte)
     */
    void *advance(size_t bytes);

    /** reset the buffer position back to beginning.
     * @return pointer to the new position (next available byte)
     */
    void *zero()
    {
        left = _size;
        return data;
    }

    /** Get a pointer to the first position (byte) of the buffer.
     * @return pointer to the first position (byte)
     */
    const void *start() const
    {
        return data;
    }

    /** Get a pointer to the first position (byte) of the buffer.
     * @return pointer to the first position (byte)
     */
    void *start()
    {
        return data;
    }

    /** Get a pointer to the current position of the buffer.
     * @return pointer to the current position (next available byte)
     */
    void *position()
    {
        return &data[_size - left];
    }

    /** Get the size of the buffer in bytes.
     * @return size of the buffer in bytes
     */
    size_t size() const
    {
        return _size;
    }

    /** Get the number of unused bytes in the buffer.
     * @return number of unused bytes
     */
    size_t available() const
    {
        return left;
    }

    /** Get the number of used bytes in the buffer.
     * @return number of used bytes
     */
    size_t used() const
    {
        return _size - left;
    }

    /** Expand the buffer size.
     * @param size size buffer after expansion.
     * @return newly expanded buffer with old buffer data moved
     */
    Buffer *expand(size_t size);

    /** Set the unique identifier for the buffer.
     * @param identifier 32-bit unique identifier
     */
    void id(uint32_t identifier)
    {
        _id = identifier;
    }

    /** Get the unique identifier for the buffer.
     * @return 32-bit unique identifier
     */
    uint32_t id()
    {
        return _id;
    }

    /** Add another reference to the buffer.
     * @return total number of references to this point
     */
    unsigned int reference();

private:
    /** Like a constructor, but in this case, we allocate extra space for the
     * user data.
     * @param pool BufferPool instance from which this buffer will come
     * @param size size of user data in bytes
     * @param items number of items to allocate
     * @return newly allocated buffer or addres of first item in an array of
     *         allocated buffers, HASSERT() on failure
     */
    static Buffer *alloc(BufferPool *pool, size_t size, size_t items = 1)
    {
        HASSERT(pool != NULL && items != 0);
        size_t align_size = sizeof_buffer(size);
        Buffer *buffer = (Buffer*)malloc(align_size * items);
        HASSERT(buffer != NULL);
        Buffer *result = buffer;
        for (size_t i = 0; i < items; ++i)
        {
            buffer->next = NULL;
            buffer->bufferPool = pool;
            buffer->_size = size;
            buffer->left = size;
            buffer->count = 1;
            buffer = (Buffer*)((char*)buffer + align_size);
        }
        return result;
    }

    /** Like a constructor, but in this case, we re-purpose an existing buffer
     * with no new memory allocation.
     * @param buffer instance of buffer to reinitialize
     * @param size size of user data in bytes
     * @return newly reinitialized buffer, HASSERT() on failure
     */
    static Buffer *init(Buffer *buffer, size_t size)
    {
        HASSERT(buffer->bufferPool != NULL);
        HASSERT(buffer->_size == size);
        buffer->next = NULL;
        buffer->left = size;
        buffer->count = 1;
        return buffer;
    }

    /** Macro to position to beginning of structure from data member position*/
    #define BUFFER(_buffer) (Buffer*)((char *)(_buffer) - sizeof(Buffer));

    /* pointer to BufferPool instance that this buffer belongs to */
    BufferPool *bufferPool;

    /** next buffer in list */
    Buffer *next;

    /** size of data in bytes */
    size_t _size;

    /** amount for free space left in the buffer */
    size_t left;

    /** message ID for uniquely identifying this buffer in a queue */
    uint32_t _id;

    /** number of references in use */
    unsigned int count;

    /** user data */
    char data[];

    /** This class is a helper of BufferPool, so we know where to free to */
    friend class BufferPool;

    /** This class is a helper of BufferQueue */
    friend class BufferQueue;

    /** The total size of an array element of a Buffer for given payload.
     * @param size payload size
     */
    static size_t sizeof_buffer(size_t size)
    {
        return sizeof(Buffer) + (((size/sizeof(long)) + (size % sizeof(long) ? 1 : 0)) * sizeof(long));
    }

    /** Default constructor */
    Buffer();

    /** Default destructor */
    ~Buffer();

    DISALLOW_COPY_AND_ASSIGN(Buffer);
};

/** Pool of previously allocated, but currently unused, buffers. */
class BufferPool
{
public:
    /* Default Constructor */
    BufferPool()
        : totalSize(0),
          mutex(),
          pool {NULL, NULL, NULL, NULL},
          itemSize(0),
          items(0)
    {
    }

    /* Constructor for a fixed size pool.
     * @param item_size size of each item in the pool
     * @param items number of items in the pool
     */
    BufferPool(size_t item_size, size_t items)
        : totalSize(0),
          mutex(),
          pool {Buffer::alloc(this, item_size, items), NULL, NULL, NULL},
          itemSize(item_size),
          items(items)
    {
        Buffer *current = first;
        for (size_t i = 0; i < items; ++i)
        {
            current->next = pool[1];
            pool[1] = current;
            current = (Buffer*)((char*)current + Buffer::sizeof_buffer(item_size));
        }
        /* save the index just after last buffer in the bool */
        pool[2] = current;
    }

    /* default destructor */
    ~BufferPool()
    {
        HASSERT(0);
    }

    /** Used in static pools to tell if this buffer is a member of the pool.
     * @param buffer buffer to test validity on
     * @return true if the buffer is in the pool, or this is not a fixed pool,
     *         else return false;
     */
    bool valid(Buffer *buffer)
    {
        if (itemSize != 0)
        {
            if (buffer >= first && buffer <= pool[2])
            {
                return true;
            }
            return false;
        }
        return true;
    }

    /** Get a free buffer out of the pool.  A buffer may be
     * obtained without context (object reference) from the mainBufferPool
     * with the ::buffer_free method.
     *
     * @param size minimum size in bytes the buffer must hold
     * @return pointer to the newly allocated buffer
     */
    Buffer *buffer_alloc(size_t size);

    /** Release a buffer back to the free buffer pool.  A buffer may be
     * released without context (object reference) to the mainBufferPool
     * with the ::buffer_free method.
     *
     * @param buffer pointer to buffer to release
     */
    void buffer_free(Buffer *buffer);

private:
    /** keep track of total allocated size of memory */
    size_t totalSize;

    /** Mutual exclusion for buffer pool */
    OSMutex mutex;

    /** this union save overlapping memory */
    union
    {
        /** Free buffer pool */
        Buffer *pool[4];

        /** First buffer in a pre-allocated array pool */
        Buffer *first;
    };

    /** item Size for fixed pools */
    size_t itemSize;

    /** number of items for fixed pools */
    size_t items;

    /** This class is a helper of BufferQueue */
    friend class BufferQueue;

    /** This class is a helper of Buffer */
    friend class Buffer;

    DISALLOW_COPY_AND_ASSIGN(BufferPool);
};

/** This class implements a linked list "queue" of buffers.  It may be
 * instantiated to use the mainBufferPool for its memory pool, or optionally
 * another BufferPool instance may be specified for its memory pool.
 */
class BufferQueue
{
public:
    /** Default Constructor, use mainBufferPool for buffer allocation. */
    BufferQueue()
        : head(NULL),
          tail(NULL),
          count(0),
          mutex()
    {
    }

    /** Default destructor.
     */
    ~BufferQueue()
    {
    }

    /** Release a buffer back to the free buffer pool.
     * @param buffer pointer to buffer to release
     */
    void buffer_free(Buffer *buffer)
    {
        buffer->free();
    }

    /** Add a buffer to the back of the queue.
     * @param buffer buffer to add to queue
     */
    void insert(Buffer *buffer);

    /** Get a buffer from the front of the queue.
     * @return buffer buffer retrieved from queue
     */
    Buffer *next();

    /** Get the number of pending items in the queue.
     * @return number of pending items in the queue
     */
    size_t pending()
    {
        return count;
    }

    /** Test if the queue is empty.
     * @return true if empty, else false
     */
    bool empty()
    {
        return (head == NULL);
    }

protected:

private:
    /** head buffer in queue */
    Buffer *head;

    /** tail buffer in queue */
    Buffer *tail;

    /** number of buffers in queue */
    size_t count;

    /** @todo (Stuart Baker) For free RTOS, we may want to consider a different
     * (smaller) locking mechanism
     */
    /** Mutual exclusion for Queue */
    OSMutex mutex;

    DISALLOW_COPY_AND_ASSIGN(BufferQueue);
};

/** A BufferQueue that adds the ability to wait on the next buffer.
 * Yes this uses multiple inheritance.  Yes multiple inheritance is bad.  It
 * is okay in this case, so get over it.
 */
class BufferQueueWait : public BufferQueue, public OSSem
{
public:
    /** Default Constructor, use mainBufferPool for buffer allocation. */
    BufferQueueWait()
        : BufferQueue(),
          sem(0)
    {
    }

    /** Default destructor.
     */
    ~BufferQueueWait()
    {
    }

    /** Add a buffer to the back of the queue.
     * @param buffer buffer to add to queue
     */
    void insert(Buffer *buffer)
    {
        BufferQueue::insert(buffer);
        post();
    }

    /** Get a buffer from the front of the queue.
     * @return buffer buffer retrieved from queue
     */
    Buffer *next()
    {
        Buffer *result = BufferQueue::next();
        if (result != NULL)
        {
            /* decrement semaphore */
            OSSem::wait();
        }
        return result;
    }

    /** Wait for a buffer from the front of the queue.
     * @return buffer buffer retrieved from queue
     */
    Buffer *wait()
    {
        OSSem::wait();
        Buffer *result = BufferQueue::next();
        HASSERT(result != NULL);
        return result;
    }

    /** Wait for a buffer from the front of the queue.
     * @param timeout time to wait in nanoseconds
     * @return buffer buffer retrieved from queue, NULL on timeout or error
     */
    Buffer *timedwait(long long timeout)
    {
        if (OSSem::timedwait(timeout) != 0)
        {
            return NULL;
        }

        Buffer *result = BufferQueue::next();
        HASSERT(result != NULL);
        return result;
    }

private:
    /** Semaphore that we will wait on */
    OSSem sem;

    DISALLOW_COPY_AND_ASSIGN(BufferQueueWait);
};

/** Get a free buffer out of the mainBufferPool pool.
 * @param size minimum size in bytes the buffer must hold
 * @return pointer to the newly allocated buffer
 */
inline Buffer *buffer_alloc(size_t size)
{
    return mainBufferPool->buffer_alloc(size);
}

/** Release a buffer back to the mainBufferPool free buffer pool.
 * @param buffer pointer to buffer to release
 */
inline void buffer_free(Buffer *buffer)
{
    mainBufferPool->buffer_free(buffer);
}

/** Free this buffer to the BufferPool from whence it came.
 */
inline void Buffer::free()
{
    HASSERT(bufferPool != NULL);
    bufferPool->buffer_free(this);
}

/** Advance the position of the buffer.
 * @param bytes number of bytes to advance.
 * @return pointer to the new position (next available byte)
 */
inline void *Buffer::advance(size_t bytes)
{
    /** @todo (Stuart Baker) do we really need a mutex lock here? */
    bufferPool->mutex.lock();
    left -= bytes;
    bufferPool->mutex.unlock();
    return &data[_size - left];
}

/** Add another reference to the buffer.
 * @return total number of references to this point
 */
inline unsigned int Buffer::reference()
{
    bufferPool->mutex.lock();
    ++count;
    bufferPool->mutex.unlock();
    return count;
}

#endif /* _BufferQueue_hxx_ */
<commit_msg>comments out destructor crash.<commit_after>/** \copyright
 * Copyright (c) 2013, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file BufferQueue.hxx
 * This file provides an implementation buffered queues.
 *
 * @author Stuart W. Baker
 * @date 3 August 2013
 */

#ifndef _BufferQueue_hxx_
#define _BufferQueue_hxx_

#include <cstdint>
#include <cstdlib>

#include <os/OS.hxx>

class BufferPool;

/** main buffer pool instance */
extern BufferPool *mainBufferPool;

/** Buffer structure that contains both metadata and user data */
class Buffer
{
public:
    /** Free this buffer to the BufferPool from whence it came.
     */
    inline void free();

    /** Advance the position of the buffer.
     * @param bytes number of bytes to advance.
     * @return pointer to the new position (next available byte)
     */
    void *advance(size_t bytes);

    /** reset the buffer position back to beginning.
     * @return pointer to the new position (next available byte)
     */
    void *zero()
    {
        left = _size;
        return data;
    }

    /** Get a pointer to the first position (byte) of the buffer.
     * @return pointer to the first position (byte)
     */
    const void *start() const
    {
        return data;
    }

    /** Get a pointer to the first position (byte) of the buffer.
     * @return pointer to the first position (byte)
     */
    void *start()
    {
        return data;
    }

    /** Get a pointer to the current position of the buffer.
     * @return pointer to the current position (next available byte)
     */
    void *position()
    {
        return &data[_size - left];
    }

    /** Get the size of the buffer in bytes.
     * @return size of the buffer in bytes
     */
    size_t size() const
    {
        return _size;
    }

    /** Get the number of unused bytes in the buffer.
     * @return number of unused bytes
     */
    size_t available() const
    {
        return left;
    }

    /** Get the number of used bytes in the buffer.
     * @return number of used bytes
     */
    size_t used() const
    {
        return _size - left;
    }

    /** Expand the buffer size.
     * @param size size buffer after expansion.
     * @return newly expanded buffer with old buffer data moved
     */
    Buffer *expand(size_t size);

    /** Set the unique identifier for the buffer.
     * @param identifier 32-bit unique identifier
     */
    void id(uint32_t identifier)
    {
        _id = identifier;
    }

    /** Get the unique identifier for the buffer.
     * @return 32-bit unique identifier
     */
    uint32_t id()
    {
        return _id;
    }

    /** Add another reference to the buffer.
     * @return total number of references to this point
     */
    unsigned int reference();

private:
    /** Like a constructor, but in this case, we allocate extra space for the
     * user data.
     * @param pool BufferPool instance from which this buffer will come
     * @param size size of user data in bytes
     * @param items number of items to allocate
     * @return newly allocated buffer or addres of first item in an array of
     *         allocated buffers, HASSERT() on failure
     */
    static Buffer *alloc(BufferPool *pool, size_t size, size_t items = 1)
    {
        HASSERT(pool != NULL && items != 0);
        size_t align_size = sizeof_buffer(size);
        Buffer *buffer = (Buffer*)malloc(align_size * items);
        HASSERT(buffer != NULL);
        Buffer *result = buffer;
        for (size_t i = 0; i < items; ++i)
        {
            buffer->next = NULL;
            buffer->bufferPool = pool;
            buffer->_size = size;
            buffer->left = size;
            buffer->count = 1;
            buffer = (Buffer*)((char*)buffer + align_size);
        }
        return result;
    }

    /** Like a constructor, but in this case, we re-purpose an existing buffer
     * with no new memory allocation.
     * @param buffer instance of buffer to reinitialize
     * @param size size of user data in bytes
     * @return newly reinitialized buffer, HASSERT() on failure
     */
    static Buffer *init(Buffer *buffer, size_t size)
    {
        HASSERT(buffer->bufferPool != NULL);
        HASSERT(buffer->_size == size);
        buffer->next = NULL;
        buffer->left = size;
        buffer->count = 1;
        return buffer;
    }

    /** Macro to position to beginning of structure from data member position*/
    #define BUFFER(_buffer) (Buffer*)((char *)(_buffer) - sizeof(Buffer));

    /* pointer to BufferPool instance that this buffer belongs to */
    BufferPool *bufferPool;

    /** next buffer in list */
    Buffer *next;

    /** size of data in bytes */
    size_t _size;

    /** amount for free space left in the buffer */
    size_t left;

    /** message ID for uniquely identifying this buffer in a queue */
    uint32_t _id;

    /** number of references in use */
    unsigned int count;

    /** user data */
    char data[];

    /** This class is a helper of BufferPool, so we know where to free to */
    friend class BufferPool;

    /** This class is a helper of BufferQueue */
    friend class BufferQueue;

    /** The total size of an array element of a Buffer for given payload.
     * @param size payload size
     */
    static size_t sizeof_buffer(size_t size)
    {
        return sizeof(Buffer) + (((size/sizeof(long)) + (size % sizeof(long) ? 1 : 0)) * sizeof(long));
    }

    /** Default constructor */
    Buffer();

    /** Default destructor */
    ~Buffer();

    DISALLOW_COPY_AND_ASSIGN(Buffer);
};

/** Pool of previously allocated, but currently unused, buffers. */
class BufferPool
{
public:
    /* Default Constructor */
    BufferPool()
        : totalSize(0),
          mutex(),
          pool {NULL, NULL, NULL, NULL},
          itemSize(0),
          items(0)
    {
    }

    /* Constructor for a fixed size pool.
     * @param item_size size of each item in the pool
     * @param items number of items in the pool
     */
    BufferPool(size_t item_size, size_t items)
        : totalSize(0),
          mutex(),
          pool {Buffer::alloc(this, item_size, items), NULL, NULL, NULL},
          itemSize(item_size),
          items(items)
    {
        Buffer *current = first;
        for (size_t i = 0; i < items; ++i)
        {
            current->next = pool[1];
            pool[1] = current;
            current = (Buffer*)((char*)current + Buffer::sizeof_buffer(item_size));
        }
        /* save the index just after last buffer in the bool */
        pool[2] = current;
    }

    /* default destructor */
    ~BufferPool()
    {
      /** @todo(stbaker): what is the required condition for a buffer pool to
       be deallocated?
       HASSERT(0);
      */
    }

    /** Used in static pools to tell if this buffer is a member of the pool.
     * @param buffer buffer to test validity on
     * @return true if the buffer is in the pool, or this is not a fixed pool,
     *         else return false;
     */
    bool valid(Buffer *buffer)
    {
        if (itemSize != 0)
        {
            if (buffer >= first && buffer <= pool[2])
            {
                return true;
            }
            return false;
        }
        return true;
    }

    /** Get a free buffer out of the pool.  A buffer may be
     * obtained without context (object reference) from the mainBufferPool
     * with the ::buffer_free method.
     *
     * @param size minimum size in bytes the buffer must hold
     * @return pointer to the newly allocated buffer
     */
    Buffer *buffer_alloc(size_t size);

    /** Release a buffer back to the free buffer pool.  A buffer may be
     * released without context (object reference) to the mainBufferPool
     * with the ::buffer_free method.
     *
     * @param buffer pointer to buffer to release
     */
    void buffer_free(Buffer *buffer);

private:
    /** keep track of total allocated size of memory */
    size_t totalSize;

    /** Mutual exclusion for buffer pool */
    OSMutex mutex;

    /** this union save overlapping memory */
    union
    {
        /** Free buffer pool */
        Buffer *pool[4];

        /** First buffer in a pre-allocated array pool */
        Buffer *first;
    };

    /** item Size for fixed pools */
    size_t itemSize;

    /** number of items for fixed pools */
    size_t items;

    /** This class is a helper of BufferQueue */
    friend class BufferQueue;

    /** This class is a helper of Buffer */
    friend class Buffer;

    DISALLOW_COPY_AND_ASSIGN(BufferPool);
};

/** This class implements a linked list "queue" of buffers.  It may be
 * instantiated to use the mainBufferPool for its memory pool, or optionally
 * another BufferPool instance may be specified for its memory pool.
 */
class BufferQueue
{
public:
    /** Default Constructor, use mainBufferPool for buffer allocation. */
    BufferQueue()
        : head(NULL),
          tail(NULL),
          count(0),
          mutex()
    {
    }

    /** Default destructor.
     */
    ~BufferQueue()
    {
    }

    /** Release a buffer back to the free buffer pool.
     * @param buffer pointer to buffer to release
     */
    void buffer_free(Buffer *buffer)
    {
        buffer->free();
    }

    /** Add a buffer to the back of the queue.
     * @param buffer buffer to add to queue
     */
    void insert(Buffer *buffer);

    /** Get a buffer from the front of the queue.
     * @return buffer buffer retrieved from queue
     */
    Buffer *next();

    /** Get the number of pending items in the queue.
     * @return number of pending items in the queue
     */
    size_t pending()
    {
        return count;
    }

    /** Test if the queue is empty.
     * @return true if empty, else false
     */
    bool empty()
    {
        return (head == NULL);
    }

protected:

private:
    /** head buffer in queue */
    Buffer *head;

    /** tail buffer in queue */
    Buffer *tail;

    /** number of buffers in queue */
    size_t count;

    /** @todo (Stuart Baker) For free RTOS, we may want to consider a different
     * (smaller) locking mechanism
     */
    /** Mutual exclusion for Queue */
    OSMutex mutex;

    DISALLOW_COPY_AND_ASSIGN(BufferQueue);
};

/** A BufferQueue that adds the ability to wait on the next buffer.
 * Yes this uses multiple inheritance.  Yes multiple inheritance is bad.  It
 * is okay in this case, so get over it.
 */
class BufferQueueWait : public BufferQueue, public OSSem
{
public:
    /** Default Constructor, use mainBufferPool for buffer allocation. */
    BufferQueueWait()
        : BufferQueue(),
          sem(0)
    {
    }

    /** Default destructor.
     */
    ~BufferQueueWait()
    {
    }

    /** Add a buffer to the back of the queue.
     * @param buffer buffer to add to queue
     */
    void insert(Buffer *buffer)
    {
        BufferQueue::insert(buffer);
        post();
    }

    /** Get a buffer from the front of the queue.
     * @return buffer buffer retrieved from queue
     */
    Buffer *next()
    {
        Buffer *result = BufferQueue::next();
        if (result != NULL)
        {
            /* decrement semaphore */
            OSSem::wait();
        }
        return result;
    }

    /** Wait for a buffer from the front of the queue.
     * @return buffer buffer retrieved from queue
     */
    Buffer *wait()
    {
        OSSem::wait();
        Buffer *result = BufferQueue::next();
        HASSERT(result != NULL);
        return result;
    }

    /** Wait for a buffer from the front of the queue.
     * @param timeout time to wait in nanoseconds
     * @return buffer buffer retrieved from queue, NULL on timeout or error
     */
    Buffer *timedwait(long long timeout)
    {
        if (OSSem::timedwait(timeout) != 0)
        {
            return NULL;
        }

        Buffer *result = BufferQueue::next();
        HASSERT(result != NULL);
        return result;
    }

private:
    /** Semaphore that we will wait on */
    OSSem sem;

    DISALLOW_COPY_AND_ASSIGN(BufferQueueWait);
};

/** Get a free buffer out of the mainBufferPool pool.
 * @param size minimum size in bytes the buffer must hold
 * @return pointer to the newly allocated buffer
 */
inline Buffer *buffer_alloc(size_t size)
{
    return mainBufferPool->buffer_alloc(size);
}

/** Release a buffer back to the mainBufferPool free buffer pool.
 * @param buffer pointer to buffer to release
 */
inline void buffer_free(Buffer *buffer)
{
    mainBufferPool->buffer_free(buffer);
}

/** Free this buffer to the BufferPool from whence it came.
 */
inline void Buffer::free()
{
    HASSERT(bufferPool != NULL);
    bufferPool->buffer_free(this);
}

/** Advance the position of the buffer.
 * @param bytes number of bytes to advance.
 * @return pointer to the new position (next available byte)
 */
inline void *Buffer::advance(size_t bytes)
{
    /** @todo (Stuart Baker) do we really need a mutex lock here? */
    bufferPool->mutex.lock();
    left -= bytes;
    bufferPool->mutex.unlock();
    return &data[_size - left];
}

/** Add another reference to the buffer.
 * @return total number of references to this point
 */
inline unsigned int Buffer::reference()
{
    bufferPool->mutex.lock();
    ++count;
    bufferPool->mutex.unlock();
    return count;
}

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


<commit_before>#include"all_defines.hpp"

#include"aio.hpp"
#include"heaps.hpp"
#include"types.hpp"
#include"objects.hpp"
#include"processes.hpp"
#include"workers.hpp"
#include"bytecodes.hpp"
#include"symbols.hpp"

/*Generic code for AIO*/
/*This contains code that is shared across AIO implementations*/

/*internal function for sending a message to a process*/
/*
preconditions:
	stack.top() = message to send
postconditions:
	stack.top() has been popped
*/
static inline void send_message_to(Process* P, ProcessStack& stack) {
	/*prepare message*/
	ValueHolderRef m;
	ValueHolder::copy_object(m, stack.top());
	stack.pop();

	bool is_waiting = 0;
	/*keep sending until we definitely go through any locks or whatnot*/
	while(!P->receive_message(m, is_waiting)) /*do nothing*/;
	if(is_waiting) {
		workers->workqueue_push(P);
	}
}

ProcessInvoker::ProcessInvoker(Process* nP) : P(nP) {
	/*TODO: notify workers of one more process-gc root*/
}
ProcessInvoker::~ProcessInvoker() {
	/*TODO: notify workers of loss of root*/
}

void ProcessInvoker::io_respond(
		Process& host,
		boost::shared_ptr<IOPort> port,
		boost::shared_ptr<std::vector<unsigned char> >& dat) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = port;
	stack.push(Object::to_ref<Generic*>(io));
	/*any data?*/
	if(!dat || dat->size() == 0) {
		stack.push(Object::nil());
	} else {
		BinObj* e = BinObj::create(hp, dat);
		stack.push(Object::to_ref<Generic*>(e));
	}
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::nil_respond(
		Process& host,
		boost::shared_ptr<IOPort> port) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = port;
	stack.push(Object::to_ref<Generic*>(io));
	stack.push(Object::nil());
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::accept_respond(
		Process& host,
		boost::shared_ptr<IOPort> socket,
		boost::shared_ptr<IOPort> new_socket){
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = socket;
	stack.push(Object::to_ref<Generic*>(io));
	io = hp.create<HlIOPort>();
	io->p = new_socket;
	stack.push(Object::to_ref<Generic*>(io));
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::connect_respond(
		Process& host,
		boost::shared_ptr<Event> event,
		boost::shared_ptr<IOPort> new_socket) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlEvent* ev = hp.create<HlEvent>();
	ev->p = event;
	stack.push(Object::to_ref<Generic*>(ev));
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = new_socket;
	stack.push(Object::to_ref<Generic*>(io));
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::sleep_respond(
		Process& host,
		boost::shared_ptr<Event> event,
		size_t time) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlEvent* ev = hp.create<HlEvent>();
	ev->p = event;
	stack.push(Object::to_ref<Generic*>(ev));
	stack.push(Object::to_ref<int>(time));
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::io_error_respond(
		Process& host,
		boost::shared_ptr<IOPort> port,
		std::string const& msg) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = port;
	stack.push(Object::to_ref<Generic*>(io));
	/*slow lookup is OK, we don't expect error handling
	to be fast.
	*/
	stack.push(Object::to_ref(symbols->lookup("<hl>i/o")));
	/*assume ASCII string for now*/
	for(size_t i = 0; i < msg.size(); ++i) {
		stack.push(Object::to_ref(UnicodeChar(msg[i])));
	}
	HlString::stack_create(hp, stack, msg.size());

	bytecode_tag(host, stack);
	bytecode_cons(host, stack);

	send_message_to(P, stack);
}

void ProcessInvoker::other_error_respond(
		Process& host,
		boost::shared_ptr<Event> event,
		std::string const& msg) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlEvent* ev = hp.create<HlEvent>();
	ev->p = event;
	stack.push(Object::to_ref<Generic*>(ev));
	/*slow lookup is OK, we don't expect error handling
	to be fast.
	*/
	stack.push(Object::to_ref(symbols->lookup("<hl>i/o")));
	/*assume ASCII string for now*/
	for(size_t i = 0; i < msg.size(); ++i) {
		stack.push(Object::to_ref(UnicodeChar(msg[i])));
	}
	HlString::stack_create(hp, stack, msg.size());

	bytecode_tag(host, stack);
	bytecode_cons(host, stack);

	send_message_to(P, stack);
}

<commit_msg>src/aio.cpp: Removed unnecessary comments.<commit_after>#include"all_defines.hpp"

#include"aio.hpp"
#include"heaps.hpp"
#include"types.hpp"
#include"objects.hpp"
#include"processes.hpp"
#include"workers.hpp"
#include"bytecodes.hpp"
#include"symbols.hpp"

/*Generic code for AIO*/
/*This contains code that is shared across AIO implementations*/

/*internal function for sending a message to a process*/
/*
preconditions:
	stack.top() = message to send
postconditions:
	stack.top() has been popped
*/
static inline void send_message_to(Process* P, ProcessStack& stack) {
	/*prepare message*/
	ValueHolderRef m;
	ValueHolder::copy_object(m, stack.top());
	stack.pop();

	bool is_waiting = 0;
	/*keep sending until we definitely go through any locks or whatnot*/
	while(!P->receive_message(m, is_waiting)) /*do nothing*/;
	if(is_waiting) {
		workers->workqueue_push(P);
	}
}

ProcessInvoker::ProcessInvoker(Process* nP) : P(nP) {
}
ProcessInvoker::~ProcessInvoker() {
}

void ProcessInvoker::io_respond(
		Process& host,
		boost::shared_ptr<IOPort> port,
		boost::shared_ptr<std::vector<unsigned char> >& dat) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = port;
	stack.push(Object::to_ref<Generic*>(io));
	/*any data?*/
	if(!dat || dat->size() == 0) {
		stack.push(Object::nil());
	} else {
		BinObj* e = BinObj::create(hp, dat);
		stack.push(Object::to_ref<Generic*>(e));
	}
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::nil_respond(
		Process& host,
		boost::shared_ptr<IOPort> port) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = port;
	stack.push(Object::to_ref<Generic*>(io));
	stack.push(Object::nil());
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::accept_respond(
		Process& host,
		boost::shared_ptr<IOPort> socket,
		boost::shared_ptr<IOPort> new_socket){
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = socket;
	stack.push(Object::to_ref<Generic*>(io));
	io = hp.create<HlIOPort>();
	io->p = new_socket;
	stack.push(Object::to_ref<Generic*>(io));
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::connect_respond(
		Process& host,
		boost::shared_ptr<Event> event,
		boost::shared_ptr<IOPort> new_socket) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlEvent* ev = hp.create<HlEvent>();
	ev->p = event;
	stack.push(Object::to_ref<Generic*>(ev));
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = new_socket;
	stack.push(Object::to_ref<Generic*>(io));
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::sleep_respond(
		Process& host,
		boost::shared_ptr<Event> event,
		size_t time) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlEvent* ev = hp.create<HlEvent>();
	ev->p = event;
	stack.push(Object::to_ref<Generic*>(ev));
	stack.push(Object::to_ref<int>(time));
	bytecode_cons(host, stack);

	send_message_to(P, stack);

}

void ProcessInvoker::io_error_respond(
		Process& host,
		boost::shared_ptr<IOPort> port,
		std::string const& msg) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlIOPort* io = hp.create<HlIOPort>();
	io->p = port;
	stack.push(Object::to_ref<Generic*>(io));
	/*slow lookup is OK, we don't expect error handling
	to be fast.
	*/
	stack.push(Object::to_ref(symbols->lookup("<hl>i/o")));
	/*assume ASCII string for now*/
	for(size_t i = 0; i < msg.size(); ++i) {
		stack.push(Object::to_ref(UnicodeChar(msg[i])));
	}
	HlString::stack_create(hp, stack, msg.size());

	bytecode_tag(host, stack);
	bytecode_cons(host, stack);

	send_message_to(P, stack);
}

void ProcessInvoker::other_error_respond(
		Process& host,
		boost::shared_ptr<Event> event,
		std::string const& msg) {
	Heap& hp = host; ProcessStack& stack = host.stack;
	/*build objects*/
	HlEvent* ev = hp.create<HlEvent>();
	ev->p = event;
	stack.push(Object::to_ref<Generic*>(ev));
	/*slow lookup is OK, we don't expect error handling
	to be fast.
	*/
	stack.push(Object::to_ref(symbols->lookup("<hl>i/o")));
	/*assume ASCII string for now*/
	for(size_t i = 0; i < msg.size(); ++i) {
		stack.push(Object::to_ref(UnicodeChar(msg[i])));
	}
	HlString::stack_create(hp, stack, msg.size());

	bytecode_tag(host, stack);
	bytecode_cons(host, stack);

	send_message_to(P, stack);
}

<|endoftext|>