<commit_before>/*!
 *
 * Copyright (C) 2012 Jolla Ltd.
 *
 * Contact: Mohammed Hassan <mohammed.hassan@jollamobile.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "grilodatasource.h"
#include "grilomedia.h"
#include "grilomodel.h"
#include "griloregistry.h"
#include <QDebug>

#include <QTimerEvent>

static void fill_key_id(gpointer data, gpointer user_data) {
  QVariantList *varList = static_cast<QVariantList *>(user_data);
  varList->append(GriloDataSource::MetadataKeys(GRLPOINTER_TO_KEYID(data)));
}

GriloDataSource::GriloDataSource(QObject *parent) :
  QObject(parent),
  m_opId(0),
  m_registry(0),
  m_count(0),
  m_skip(0),
  m_insertIndex(0),
  m_updateScheduled(false) {

  m_metadataKeys << Title;
  m_typeFilter << None;
}

GriloDataSource::~GriloDataSource() {
  cancelRefresh();
  m_models.clear();
}

const QList<GriloMedia *> *GriloDataSource::media() const {
  return &m_media;
}

void GriloDataSource::addModel(GriloModel *model) {
  if (m_models.indexOf(model) == -1) {
    m_models << model;
  }
}

void GriloDataSource::removeModel(GriloModel *model) {
  if (int index = m_models.indexOf(model) != -1) {
    m_models.removeAt(index);
  }
}

void GriloDataSource::prefill(GriloModel *model) {
  if (m_media.isEmpty()) {
    return;
  }

  model->beginInsertRows(QModelIndex(), 0, m_media.size() - 1);
  model->endInsertRows();

  emit model->countChanged();
}

void GriloDataSource::addMedia(GrlMedia *media) {
  GriloMedia *wrappedMedia = 0;

  if (m_insertIndex < m_media.count()) {
      wrappedMedia = m_hash.value(QString::fromUtf8(grl_media_get_id(media)), 0);
  }

  if (wrappedMedia) {
      // If the media was already queried by a previous fetch update its position and refresh
      // the data instead of creating another item.
      bool dataChanged = false;
      int index = m_media.indexOf(wrappedMedia);
      if (index == m_insertIndex) {
         dataChanged = true;
      } else if (index != -1) {
          dataChanged = true;
        foreach (GriloModel *model, m_models) {
          model->beginMoveRows(QModelIndex(), index, index, QModelIndex(), m_insertIndex);
        }
        m_media.move(index, m_insertIndex);
        foreach (GriloModel *model, m_models) {
          model->endMoveRows();
        }
      }

      if (dataChanged) {
        wrappedMedia->setMedia(media);
        foreach (GriloModel *model, m_models) {
          QModelIndex modelIndex = model->index(m_insertIndex, 0);
          model->dataChanged(modelIndex, modelIndex);
        }
        ++m_insertIndex;
        return;
      }
  }

  wrappedMedia = new GriloMedia(media);

  foreach (GriloModel *model, m_models) {
    model->beginInsertRows(QModelIndex(), m_insertIndex, m_insertIndex);
  }

  m_media.insert(m_insertIndex, wrappedMedia);
  ++m_insertIndex;

  QString id = wrappedMedia->id();
  if (!id.isEmpty()) {
    m_hash.insert(id, wrappedMedia);
  }

  foreach (GriloModel *model, m_models) {
    model->endInsertRows();
    emit model->countChanged();
  }

}

void GriloDataSource::removeMedia(GrlMedia *media) {
  QString id = QString::fromUtf8(grl_media_get_id(media));

  if (id.isEmpty() || !m_hash.contains(id)) {
    // We really cannot do much.
    return;
  }

  GriloMedia *wrapper = m_hash[id];
  int index = m_media.indexOf(wrapper);
  if (index < m_insertIndex) {
    --m_insertIndex;
  }

  // remove from models:
  foreach (GriloModel *model, m_models) {
    model->beginRemoveRows(QModelIndex(), index, index);
  }

  // remove from hash
  m_hash.take(id);

  // remove from list
  m_media.takeAt(index);

  // destroy
  wrapper->deleteLater();

  foreach (GriloModel *model, m_models) {
    model->endRemoveRows();
  }
}

void GriloDataSource::clearMedia() {
  if (m_media.isEmpty()) {
    return;
  }

  int size = m_media.size();

  foreach (GriloModel *model, m_models) {
    model->beginRemoveRows(QModelIndex(), 0, size - 1);
  }

  qDeleteAll(m_media);
  m_media.clear();
  m_hash.clear();

  foreach (GriloModel *model, m_models) {
    model->endRemoveRows();
    emit model->countChanged();
  }
}

GriloRegistry *GriloDataSource::registry() const {
  return m_registry;
}

void GriloDataSource::setRegistry(GriloRegistry *registry) {
  // Registry change is not allowed for now.

  if (!m_registry && registry != m_registry) {

    m_registry = registry;

    QObject::connect(m_registry, SIGNAL(availableSourcesChanged()),
		     this, SLOT(availableSourcesChanged()));
    QObject::connect(m_registry, SIGNAL(contentChanged(QString,GrlSourceChangeType,GPtrArray*)),
             this, SLOT(contentChanged(QString,GrlSourceChangeType,GPtrArray*)));

    emit registryChanged();
  }
}

int GriloDataSource::count() const {
  return m_count;
}

void GriloDataSource::setCount(int count) {
  if (m_count != count) {
    m_count = count;
    emit countChanged();
  }
}

int GriloDataSource::skip() const {
  return m_skip;
}

void GriloDataSource::setSkip(int skip) {
  if (m_skip != skip) {
    m_skip = skip;
    emit skipChanged();
  }
}

QVariantList GriloDataSource::metadataKeys() const {
  return m_metadataKeys;
}

void GriloDataSource::setMetadataKeys(const QVariantList& keys) {
  if (m_metadataKeys != keys) {
    m_metadataKeys = keys;
    emit metadataKeysChanged();
  }
}

QVariantList GriloDataSource::typeFilter() const {
  return m_typeFilter;
}

void GriloDataSource::setTypeFilter(const QVariantList& filter) {
  if (m_typeFilter != filter) {
    m_typeFilter = filter;
    emit typeFilterChanged();
  }
}

GrlOperationOptions *GriloDataSource::operationOptions(GrlSource *src, const OperationType& type) {
  GrlCaps *caps = NULL;

  if (src) {
    caps = grl_source_get_caps(src, (GrlSupportedOps)type);
  }

  GrlOperationOptions *options = grl_operation_options_new(caps);

  grl_operation_options_set_flags(options, GRL_RESOLVE_IDLE_RELAY); // TODO: hardcoded
  grl_operation_options_set_skip(options, m_skip);

  if (m_count != 0) {
    grl_operation_options_set_count(options, m_count);
  }

  int typeFilter = 0;
  foreach (const QVariant& var, m_typeFilter) {
    if (var.canConvert<int>()) {
      typeFilter |= var.toInt();
    }
  }

  grl_operation_options_set_type_filter(options, (GrlTypeFilter)typeFilter);

  return options;
}

GList *GriloDataSource::keysAsList() {
  // TODO: Check why using  grl_metadata_key_list_new() produces a symbol error.
  GList *keys = NULL;

  foreach (const QVariant& var, m_metadataKeys) {
    if (var.canConvert<int>()) {
      keys = g_list_append(keys, GRLKEYID_TO_POINTER(var.toInt()));
    }
  }

  return keys;
}

void GriloDataSource::cancelRefresh() {
  if (m_opId != 0) {
    grl_operation_cancel(m_opId);
    m_opId = 0;
  }

  m_insertIndex = 0;
  m_updateScheduled = false;
  m_updateTimer.stop();
}

void GriloDataSource::grilo_source_result_cb(GrlSource *source, guint op_id,
					     GrlMedia *media, guint remaining,
					     gpointer user_data, const GError *error) {

  Q_UNUSED(source);

  // We get an error if the operation has been canceled:
  if (error) {
    if (error->domain != GRL_CORE_ERROR || error->code != GRL_CORE_ERROR_OPERATION_CANCELLED) {
      // TODO: error reporting?
      qCritical() << "Operation failed" << error->message;
    }
  }

  GriloDataSource *that = static_cast<GriloDataSource *>(user_data);

  if (that->m_opId != op_id) {
    qWarning() << "Got results belonging to an unknown browse id";

    if (media) {
      g_object_unref(media);
    }

    return;
  }

  if (media) {
    that->addMedia(media);
  }

  if (remaining == 0) {
    emit that->finished();
    that->m_opId = 0;

    if (that->m_updateScheduled) {
      that->m_updateTimer.start(100, that);
    }

    // If there are items from a previous fetch still remaining remove them.
    if (that->m_insertIndex < that->m_media.count()) {
      foreach (GriloModel *model, that->m_models) {
        model->beginRemoveRows(QModelIndex(), that->m_insertIndex, that->m_media.count() - 1);
      }
      while (that->m_media.count() > that->m_insertIndex) {
          GriloMedia *media = that->m_media.takeLast();
          that->m_hash.remove(media->id());
          delete media;
      }
      foreach (GriloModel *model, that->m_models) {
        model->endRemoveRows();
        emit model->countChanged();
      }
    }
  }
}

void GriloDataSource::contentChanged(const QString &source, GrlSourceChangeType change_type,
                            GPtrArray *changed_media)
{
    Q_UNUSED(source);
    Q_UNUSED(change_type);
    Q_UNUSED(changed_media);
}

void GriloDataSource::updateContent(GrlSourceChangeType change_type, GPtrArray *changed_media)
{
    switch (change_type) {
    case GRL_CONTENT_CHANGED:
    case GRL_CONTENT_ADDED:
      if (!m_updateScheduled) {
        m_updateScheduled = true;
        if (m_opId == 0) {
          m_updateTimer.start(100, this);
        }
      }
      break;
    case GRL_CONTENT_REMOVED:
      for (uint i = 0; i < changed_media->len; ++i) {
          removeMedia((GrlMedia *)g_ptr_array_index(changed_media, i));
      }
      break;
    default:
      break;
    }
}

QVariantList GriloDataSource::listToVariantList(const GList *keys) const {
  QVariantList varList;

  g_list_foreach(const_cast<GList *>(keys), fill_key_id, &varList);

  return varList;
}

void GriloDataSource::timerEvent(QTimerEvent *event) {
  if (event->timerId() == m_updateTimer.timerId()) {
    m_updateTimer.stop();
    emit contentUpdated();
  }
}
<commit_msg>[datasource] Corrected emitting countChanged when removing rows<commit_after>/*!
 *
 * Copyright (C) 2012 Jolla Ltd.
 *
 * Contact: Mohammed Hassan <mohammed.hassan@jollamobile.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "grilodatasource.h"
#include "grilomedia.h"
#include "grilomodel.h"
#include "griloregistry.h"
#include <QDebug>

#include <QTimerEvent>

static void fill_key_id(gpointer data, gpointer user_data) {
  QVariantList *varList = static_cast<QVariantList *>(user_data);
  varList->append(GriloDataSource::MetadataKeys(GRLPOINTER_TO_KEYID(data)));
}

GriloDataSource::GriloDataSource(QObject *parent) :
  QObject(parent),
  m_opId(0),
  m_registry(0),
  m_count(0),
  m_skip(0),
  m_insertIndex(0),
  m_updateScheduled(false) {

  m_metadataKeys << Title;
  m_typeFilter << None;
}

GriloDataSource::~GriloDataSource() {
  cancelRefresh();
  m_models.clear();
}

const QList<GriloMedia *> *GriloDataSource::media() const {
  return &m_media;
}

void GriloDataSource::addModel(GriloModel *model) {
  if (m_models.indexOf(model) == -1) {
    m_models << model;
  }
}

void GriloDataSource::removeModel(GriloModel *model) {
  if (int index = m_models.indexOf(model) != -1) {
    m_models.removeAt(index);
  }
}

void GriloDataSource::prefill(GriloModel *model) {
  if (m_media.isEmpty()) {
    return;
  }

  model->beginInsertRows(QModelIndex(), 0, m_media.size() - 1);
  model->endInsertRows();

  emit model->countChanged();
}

void GriloDataSource::addMedia(GrlMedia *media) {
  GriloMedia *wrappedMedia = 0;

  if (m_insertIndex < m_media.count()) {
      wrappedMedia = m_hash.value(QString::fromUtf8(grl_media_get_id(media)), 0);
  }

  if (wrappedMedia) {
      // If the media was already queried by a previous fetch update its position and refresh
      // the data instead of creating another item.
      bool dataChanged = false;
      int index = m_media.indexOf(wrappedMedia);
      if (index == m_insertIndex) {
         dataChanged = true;
      } else if (index != -1) {
          dataChanged = true;
        foreach (GriloModel *model, m_models) {
          model->beginMoveRows(QModelIndex(), index, index, QModelIndex(), m_insertIndex);
        }
        m_media.move(index, m_insertIndex);
        foreach (GriloModel *model, m_models) {
          model->endMoveRows();
        }
      }

      if (dataChanged) {
        wrappedMedia->setMedia(media);
        foreach (GriloModel *model, m_models) {
          QModelIndex modelIndex = model->index(m_insertIndex, 0);
          model->dataChanged(modelIndex, modelIndex);
        }
        ++m_insertIndex;
        return;
      }
  }

  wrappedMedia = new GriloMedia(media);

  foreach (GriloModel *model, m_models) {
    model->beginInsertRows(QModelIndex(), m_insertIndex, m_insertIndex);
  }

  m_media.insert(m_insertIndex, wrappedMedia);
  ++m_insertIndex;

  QString id = wrappedMedia->id();
  if (!id.isEmpty()) {
    m_hash.insert(id, wrappedMedia);
  }

  foreach (GriloModel *model, m_models) {
    model->endInsertRows();
    emit model->countChanged();
  }

}

void GriloDataSource::removeMedia(GrlMedia *media) {
  QString id = QString::fromUtf8(grl_media_get_id(media));

  if (id.isEmpty() || !m_hash.contains(id)) {
    // We really cannot do much.
    return;
  }

  GriloMedia *wrapper = m_hash[id];
  int index = m_media.indexOf(wrapper);
  if (index < m_insertIndex) {
    --m_insertIndex;
  }

  // remove from models:
  foreach (GriloModel *model, m_models) {
    model->beginRemoveRows(QModelIndex(), index, index);
  }

  // remove from hash
  m_hash.take(id);

  // remove from list
  m_media.takeAt(index);

  // destroy
  wrapper->deleteLater();

  foreach (GriloModel *model, m_models) {
    model->endRemoveRows();
    emit model->countChanged();
  }
}

void GriloDataSource::clearMedia() {
  if (m_media.isEmpty()) {
    return;
  }

  int size = m_media.size();

  foreach (GriloModel *model, m_models) {
    model->beginRemoveRows(QModelIndex(), 0, size - 1);
  }

  qDeleteAll(m_media);
  m_media.clear();
  m_hash.clear();

  foreach (GriloModel *model, m_models) {
    model->endRemoveRows();
    emit model->countChanged();
  }
}

GriloRegistry *GriloDataSource::registry() const {
  return m_registry;
}

void GriloDataSource::setRegistry(GriloRegistry *registry) {
  // Registry change is not allowed for now.

  if (!m_registry && registry != m_registry) {

    m_registry = registry;

    QObject::connect(m_registry, SIGNAL(availableSourcesChanged()),
		     this, SLOT(availableSourcesChanged()));
    QObject::connect(m_registry, SIGNAL(contentChanged(QString,GrlSourceChangeType,GPtrArray*)),
             this, SLOT(contentChanged(QString,GrlSourceChangeType,GPtrArray*)));

    emit registryChanged();
  }
}

int GriloDataSource::count() const {
  return m_count;
}

void GriloDataSource::setCount(int count) {
  if (m_count != count) {
    m_count = count;
    emit countChanged();
  }
}

int GriloDataSource::skip() const {
  return m_skip;
}

void GriloDataSource::setSkip(int skip) {
  if (m_skip != skip) {
    m_skip = skip;
    emit skipChanged();
  }
}

QVariantList GriloDataSource::metadataKeys() const {
  return m_metadataKeys;
}

void GriloDataSource::setMetadataKeys(const QVariantList& keys) {
  if (m_metadataKeys != keys) {
    m_metadataKeys = keys;
    emit metadataKeysChanged();
  }
}

QVariantList GriloDataSource::typeFilter() const {
  return m_typeFilter;
}

void GriloDataSource::setTypeFilter(const QVariantList& filter) {
  if (m_typeFilter != filter) {
    m_typeFilter = filter;
    emit typeFilterChanged();
  }
}

GrlOperationOptions *GriloDataSource::operationOptions(GrlSource *src, const OperationType& type) {
  GrlCaps *caps = NULL;

  if (src) {
    caps = grl_source_get_caps(src, (GrlSupportedOps)type);
  }

  GrlOperationOptions *options = grl_operation_options_new(caps);

  grl_operation_options_set_flags(options, GRL_RESOLVE_IDLE_RELAY); // TODO: hardcoded
  grl_operation_options_set_skip(options, m_skip);

  if (m_count != 0) {
    grl_operation_options_set_count(options, m_count);
  }

  int typeFilter = 0;
  foreach (const QVariant& var, m_typeFilter) {
    if (var.canConvert<int>()) {
      typeFilter |= var.toInt();
    }
  }

  grl_operation_options_set_type_filter(options, (GrlTypeFilter)typeFilter);

  return options;
}

GList *GriloDataSource::keysAsList() {
  // TODO: Check why using  grl_metadata_key_list_new() produces a symbol error.
  GList *keys = NULL;

  foreach (const QVariant& var, m_metadataKeys) {
    if (var.canConvert<int>()) {
      keys = g_list_append(keys, GRLKEYID_TO_POINTER(var.toInt()));
    }
  }

  return keys;
}

void GriloDataSource::cancelRefresh() {
  if (m_opId != 0) {
    grl_operation_cancel(m_opId);
    m_opId = 0;
  }

  m_insertIndex = 0;
  m_updateScheduled = false;
  m_updateTimer.stop();
}

void GriloDataSource::grilo_source_result_cb(GrlSource *source, guint op_id,
					     GrlMedia *media, guint remaining,
					     gpointer user_data, const GError *error) {

  Q_UNUSED(source);

  // We get an error if the operation has been canceled:
  if (error) {
    if (error->domain != GRL_CORE_ERROR || error->code != GRL_CORE_ERROR_OPERATION_CANCELLED) {
      // TODO: error reporting?
      qCritical() << "Operation failed" << error->message;
    }
  }

  GriloDataSource *that = static_cast<GriloDataSource *>(user_data);

  if (that->m_opId != op_id) {
    qWarning() << "Got results belonging to an unknown browse id";

    if (media) {
      g_object_unref(media);
    }

    return;
  }

  if (media) {
    that->addMedia(media);
  }

  if (remaining == 0) {
    emit that->finished();
    that->m_opId = 0;

    if (that->m_updateScheduled) {
      that->m_updateTimer.start(100, that);
    }

    // If there are items from a previous fetch still remaining remove them.
    if (that->m_insertIndex < that->m_media.count()) {
      foreach (GriloModel *model, that->m_models) {
        model->beginRemoveRows(QModelIndex(), that->m_insertIndex, that->m_media.count() - 1);
      }
      while (that->m_media.count() > that->m_insertIndex) {
          GriloMedia *media = that->m_media.takeLast();
          that->m_hash.remove(media->id());
          delete media;
      }
      foreach (GriloModel *model, that->m_models) {
        model->endRemoveRows();
        emit model->countChanged();
      }
    }
  }
}

void GriloDataSource::contentChanged(const QString &source, GrlSourceChangeType change_type,
                            GPtrArray *changed_media)
{
    Q_UNUSED(source);
    Q_UNUSED(change_type);
    Q_UNUSED(changed_media);
}

void GriloDataSource::updateContent(GrlSourceChangeType change_type, GPtrArray *changed_media)
{
    switch (change_type) {
    case GRL_CONTENT_CHANGED:
    case GRL_CONTENT_ADDED:
      if (!m_updateScheduled) {
        m_updateScheduled = true;
        if (m_opId == 0) {
          m_updateTimer.start(100, this);
        }
      }
      break;
    case GRL_CONTENT_REMOVED:
      for (uint i = 0; i < changed_media->len; ++i) {
          removeMedia((GrlMedia *)g_ptr_array_index(changed_media, i));
      }
      break;
    default:
      break;
    }
}

QVariantList GriloDataSource::listToVariantList(const GList *keys) const {
  QVariantList varList;

  g_list_foreach(const_cast<GList *>(keys), fill_key_id, &varList);

  return varList;
}

void GriloDataSource::timerEvent(QTimerEvent *event) {
  if (event->timerId() == m_updateTimer.timerId()) {
    m_updateTimer.stop();
    emit contentUpdated();
  }
}
<|endoftext|>


<commit_before>#include "dynet/hsm-builder.h"

#include <fstream>
#include <iostream>
#include <sstream>

#include "dynet/param-init.h"

using namespace std;

namespace dynet {

Cluster::Cluster() {}
void Cluster::new_graph(ComputationGraph& cg) {
  for (Cluster* child : children) {
    child->new_graph(cg);
  }
  bias.pg = NULL;
  weights.pg = NULL;
}

Cluster* Cluster::add_child(unsigned sym) {
  auto it = word2ind.find(sym);
  unsigned i;
  if (it == word2ind.end()) {
    Cluster* c = new Cluster();
    c->rep_dim = rep_dim;
    c->path = path;
    c->path.push_back(sym);
    i = children.size();
    word2ind.insert(make_pair(sym, i));
    children.push_back(c);
  }
  else {
    i = it->second;
  }
  return children[i];
}

void Cluster::add_word(unsigned word) {
  word2ind[word] = terminals.size();
  terminals.push_back(word);
}

void Cluster::initialize(unsigned rep_dim, ParameterCollection& model) {
  this->rep_dim = rep_dim;
  initialize(model);
}

void Cluster::initialize(ParameterCollection& model) {
  output_size = (children.size() > 0) ? children.size() : terminals.size();

  if (output_size == 1) {
  }
  else if (output_size == 2) {
    p_weights = model.add_parameters({1, rep_dim});
    p_bias = model.add_parameters({1}, ParameterInitConst(0.f));
  }
  else {
    p_weights = model.add_parameters({output_size, rep_dim});
    p_bias = model.add_parameters({output_size}, ParameterInitConst(0.f));
  }

  for (Cluster* child : children) {
    child->initialize(model);
  }
}

unsigned Cluster::num_children() const {
  return children.size();
}

const Cluster* Cluster::get_child(unsigned i) const {
  return children[i];
}

const vector<unsigned>& Cluster::get_path() const { return path; }
unsigned Cluster::get_index(unsigned word) const { return word2ind.find(word)->second; }
unsigned Cluster::get_word(unsigned index) const { return terminals[index]; }

Expression Cluster::predict(Expression h, ComputationGraph& cg) const {
  if (output_size == 1) {
    return input(cg, 1.0f);
  }
  else {
    Expression b = get_bias(cg);
    Expression w = get_weights(cg);
    return affine_transform({b, w, h});
  }
}

Expression Cluster::neg_log_softmax(Expression h, unsigned r, ComputationGraph& cg) const {
  if (output_size == 1) {
    return input(cg, 0.0f);
  }
  else if (output_size == 2) {
    Expression p = logistic(predict(h, cg));
    if (r == 1) {
      p = 1 - p;
    }
    return -log(p);
  }
  else {
    Expression dist = predict(h, cg);
    return pickneglogsoftmax(dist, r);
  }
}

unsigned Cluster::sample(Expression h, ComputationGraph& cg) const {
  if (output_size == 1) {
    return 0;
  }
  else if (output_size == 2) {
    Expression prob0_expr = logistic(predict(h, cg));
    double prob0 = as_scalar(cg.incremental_forward(prob0_expr));
    double p = rand01();
    if (p < prob0) {
      return 0;
    }
    else {
      return 1;
    }
  }
  else {
    Expression dist_expr = softmax(predict(h, cg));
    vector<float> dist = as_vector(cg.incremental_forward(dist_expr));
    unsigned c = 0;
    double p = rand01();
    for (; c < dist.size(); ++c) {
      p -= dist[c];
      if (p < 0.0) { break; }
    }
    if (c == dist.size()) {
      --c;
    }
    return c;
  }
}

Expression Cluster::get_weights(ComputationGraph& cg) const {
  if (weights.pg != &cg) {
    weights = parameter(cg, p_weights);
  }
  return weights;
}

Expression Cluster::get_bias(ComputationGraph& cg) const {
  if (bias.pg != &cg) {
    bias = parameter(cg, p_bias);
  }
  return bias;
}

string Cluster::toString() const {
  stringstream ss;
  for (unsigned i = 0; i < path.size(); ++i) {
    if (i != 0) {
      ss << " ";
    }
    ss << path[i];
  }
  return ss.str();
}

HierarchicalSoftmaxBuilder::HierarchicalSoftmaxBuilder(unsigned rep_dim,
                             const std::string& cluster_file,
                             Dict& word_dict,
                             ParameterCollection& model) {
  local_model = model.add_subcollection("hsm-builder");
  root = read_cluster_file(cluster_file, word_dict);
  root->initialize(rep_dim, local_model);
}

HierarchicalSoftmaxBuilder::~HierarchicalSoftmaxBuilder() {
}

void HierarchicalSoftmaxBuilder::initialize(ParameterCollection& model) {
 root->initialize(model);
}

void HierarchicalSoftmaxBuilder::new_graph(ComputationGraph& cg) {
  pcg = &cg;
  root->new_graph(cg);
}

Expression HierarchicalSoftmaxBuilder::neg_log_softmax(const Expression& rep, unsigned wordidx) {
  if(pcg != NULL)
    DYNET_INVALID_ARG("In HierarchicalSoftmaxBuilder, you must call new_graph before calling neg_log_softmax!");
  Cluster* path = widx2path[wordidx];

  unsigned i = 0;
  const Cluster* node = root;
  DYNET_ASSERT(root != NULL, "Null root in HierarchicalSoftmaxBuilder");
  vector<Expression> log_probs;
  Expression lp;
  unsigned r;
  while (node->num_children() > 0) {
    r = node->get_index(path->get_path()[i]);
    lp = node->neg_log_softmax(rep, r, *pcg);
    log_probs.push_back(lp);
    node = node->get_child(r);
    DYNET_ASSERT(node != NULL, "Null node in HierarchicalSoftmaxBuilder");
    i += 1;
  }

  r = path->get_index(wordidx);
  lp = node->neg_log_softmax(rep, r, *pcg);
  log_probs.push_back(lp);

  return sum(log_probs);
}

unsigned HierarchicalSoftmaxBuilder::sample(const Expression& rep) {
  if(pcg != NULL)
    DYNET_INVALID_ARG("In HierarchicalSoftmaxBuilder, you must call new_graph before calling sample!");

  const Cluster* node = root;
  vector<float> dist;
  unsigned c;
  while (node->num_children() > 0) {
    c = node->sample(rep, *pcg);
    node = node->get_child(c);
  }

  c = node->sample(rep, *pcg);
  return node->get_word(c);
}

Expression HierarchicalSoftmaxBuilder::full_log_distribution(const Expression& rep) {
  DYNET_RUNTIME_ERR("full_distribution not implemented for HierarchicalSoftmaxBuilder");
  return dynet::Expression();
}

inline bool is_ws(char x) { return (x == ' ' || x == '\t'); }
inline bool not_ws(char x) { return (x != ' ' && x != '\t'); }

Cluster* HierarchicalSoftmaxBuilder::read_cluster_file(const std::string& cluster_file, Dict& word_dict) {
  cerr << "Reading clusters from " << cluster_file << " ...\n";
  ifstream in(cluster_file);
  if(!in)
    DYNET_INVALID_ARG("HierarchicalSoftmaxBuilder couldn't read clusters from " << cluster_file);
  int wc = 0;
  string line;
  vector<unsigned> path;
  Cluster* root = new Cluster();
  while(getline(in, line)) {
    path.clear();
    ++wc;
    const unsigned len = line.size();
    unsigned startp = 0;
    unsigned endp = 0;
    while (startp < len) {
      while (is_ws(line[startp]) && startp < len) { ++startp; }
      endp = startp;
      while (not_ws(line[endp]) && endp < len) { ++endp; }
      string symbol = line.substr(startp, endp - startp);
      path.push_back(path_symbols.convert(symbol));
      if (line[endp] == ' ') {
        startp = endp + 1;
        continue;
      }
      else {
        break;
      }
    }
    Cluster* node = root;
    for (unsigned symbol : path) {
      node = node->add_child(symbol);
    }

    unsigned startw = endp;
    while (is_ws(line[startw]) && startw < len) { ++startw; }
    unsigned endw = startw;
    while (not_ws(line[endw]) && endw < len) { ++endw; }
    if(endp <= startp || startw <= endp || endw <= startw)
      DYNET_INVALID_ARG("File formatting error in HierarchicalSoftmaxBuilder");

    string word = line.substr(startw, endw - startw);
    unsigned widx = word_dict.convert(word);
    node->add_word(widx);

    if (widx2path.size() <= widx) {
      widx2path.resize(widx + 1);
    }
    widx2path[widx] = node;
  }
  cerr << "Done reading clusters.\n";
  return root;
}

} // namespace dynet
<commit_msg>In hsm-builder.cc: (1) fix the bug on checking whether new_graph is called; (2) pass the rep_dim explicitly to the cluster children nodes<commit_after>#include "dynet/hsm-builder.h"

#include <fstream>
#include <iostream>
#include <sstream>

#include "dynet/param-init.h"

using namespace std;

namespace dynet {

Cluster::Cluster() {}
void Cluster::new_graph(ComputationGraph& cg) {
  for (Cluster* child : children) {
    child->new_graph(cg);
  }
  bias.pg = NULL;
  weights.pg = NULL;
}

Cluster* Cluster::add_child(unsigned sym) {
  auto it = word2ind.find(sym);
  unsigned i;
  if (it == word2ind.end()) {
    Cluster* c = new Cluster();
    c->rep_dim = rep_dim;
    c->path = path;
    c->path.push_back(sym);
    i = children.size();
    word2ind.insert(make_pair(sym, i));
    children.push_back(c);
  }
  else {
    i = it->second;
  }
  return children[i];
}

void Cluster::add_word(unsigned word) {
  word2ind[word] = terminals.size();
  terminals.push_back(word);
}

void Cluster::initialize(unsigned rep_dim, ParameterCollection& model) {
  this->rep_dim = rep_dim;
  initialize(model);
}

void Cluster::initialize(ParameterCollection& model) {
  output_size = (children.size() > 0) ? children.size() : terminals.size();

  if (output_size == 1) {
  }
  else if (output_size == 2) {
    p_weights = model.add_parameters({1, rep_dim});
    p_bias = model.add_parameters({1}, ParameterInitConst(0.f));
  }
  else {
    p_weights = model.add_parameters({output_size, rep_dim});
    p_bias = model.add_parameters({output_size}, ParameterInitConst(0.f));
  }

  for (Cluster* child : children) {
    child->rep_dim = this->rep_dim;
    child->initialize(model);
  }
}

unsigned Cluster::num_children() const {
  return children.size();
}

const Cluster* Cluster::get_child(unsigned i) const {
  return children[i];
}

const vector<unsigned>& Cluster::get_path() const { return path; }
unsigned Cluster::get_index(unsigned word) const { return word2ind.find(word)->second; }
unsigned Cluster::get_word(unsigned index) const { return terminals[index]; }

Expression Cluster::predict(Expression h, ComputationGraph& cg) const {
  if (output_size == 1) {
    return input(cg, 1.0f);
  } else {
    Expression b = get_bias(cg);
    Expression w = get_weights(cg);
    return affine_transform({b, w, h});
  }
}

Expression Cluster::neg_log_softmax(Expression h, unsigned r, ComputationGraph& cg) const {
  if (output_size == 1) {
    return input(cg, 0.0f);
  }
  else if (output_size == 2) {
    Expression p = logistic(predict(h, cg));
    if (r == 1) {
      p = 1 - p;
    }
    return -log(p);
  }
  else {
    Expression dist = predict(h, cg);
    return pickneglogsoftmax(dist, r);
  }
}

unsigned Cluster::sample(Expression h, ComputationGraph& cg) const {
  if (output_size == 1) {
    return 0;
  }
  else if (output_size == 2) {
    Expression prob0_expr = logistic(predict(h, cg));
    double prob0 = as_scalar(cg.incremental_forward(prob0_expr));
    double p = rand01();
    if (p < prob0) {
      return 0;
    }
    else {
      return 1;
    }
  }
  else {
    Expression dist_expr = softmax(predict(h, cg));
    vector<float> dist = as_vector(cg.incremental_forward(dist_expr));
    unsigned c = 0;
    double p = rand01();
    for (; c < dist.size(); ++c) {
      p -= dist[c];
      if (p < 0.0) { break; }
    }
    if (c == dist.size()) {
      --c;
    }
    return c;
  }
}

Expression Cluster::get_weights(ComputationGraph& cg) const {
  if (weights.pg != &cg) {
    weights = parameter(cg, p_weights);
  }
  return weights;
}

Expression Cluster::get_bias(ComputationGraph& cg) const {
  if (bias.pg != &cg) {
    bias = parameter(cg, p_bias);
  }
  return bias;
}

string Cluster::toString() const {
  stringstream ss;
  for (unsigned i = 0; i < path.size(); ++i) {
    if (i != 0) {
      ss << " ";
    }
    ss << path[i];
  }
  return ss.str();
}

HierarchicalSoftmaxBuilder::HierarchicalSoftmaxBuilder(unsigned rep_dim,
                             const std::string& cluster_file,
                             Dict& word_dict,
                             ParameterCollection& model) {
  local_model = model.add_subcollection("hsm-builder");
  root = read_cluster_file(cluster_file, word_dict);
  root->initialize(rep_dim, local_model);
}

HierarchicalSoftmaxBuilder::~HierarchicalSoftmaxBuilder() {
}

void HierarchicalSoftmaxBuilder::initialize(ParameterCollection& model) {
 root->initialize(model);
}

void HierarchicalSoftmaxBuilder::new_graph(ComputationGraph& cg) {
  pcg = &cg;
  root->new_graph(cg);
}

Expression HierarchicalSoftmaxBuilder::neg_log_softmax(const Expression& rep, unsigned wordidx) {
  if(pcg == NULL)
    DYNET_INVALID_ARG("In HierarchicalSoftmaxBuilder, you must call new_graph before calling neg_log_softmax!");
  Cluster* path = widx2path[wordidx];

  unsigned i = 0;
  const Cluster* node = root;
  DYNET_ASSERT(root != NULL, "Null root in HierarchicalSoftmaxBuilder");
  vector<Expression> log_probs;
  Expression lp;
  unsigned r;
  while (node->num_children() > 0) {
    r = node->get_index(path->get_path()[i]);
    lp = node->neg_log_softmax(rep, r, *pcg);
    log_probs.push_back(lp);
    node = node->get_child(r);
    DYNET_ASSERT(node != NULL, "Null node in HierarchicalSoftmaxBuilder");
    i += 1;
  }

  r = path->get_index(wordidx);
  lp = node->neg_log_softmax(rep, r, *pcg);
  log_probs.push_back(lp);

  return sum(log_probs);
}

unsigned HierarchicalSoftmaxBuilder::sample(const Expression& rep) {
  if(pcg == NULL)
    DYNET_INVALID_ARG("In HierarchicalSoftmaxBuilder, you must call new_graph before calling sample!");

  const Cluster* node = root;
  vector<float> dist;
  unsigned c;
  while (node->num_children() > 0) {
    c = node->sample(rep, *pcg);
    node = node->get_child(c);
  }

  c = node->sample(rep, *pcg);
  return node->get_word(c);
}

Expression HierarchicalSoftmaxBuilder::full_log_distribution(const Expression& rep) {
  DYNET_RUNTIME_ERR("full_distribution not implemented for HierarchicalSoftmaxBuilder");
  return dynet::Expression();
}

inline bool is_ws(char x) { return (x == ' ' || x == '\t'); }
inline bool not_ws(char x) { return (x != ' ' && x != '\t'); }

Cluster* HierarchicalSoftmaxBuilder::read_cluster_file(const std::string& cluster_file, Dict& word_dict) {
  cerr << "Reading clusters from " << cluster_file << " ...\n";
  ifstream in(cluster_file);
  if(!in)
    DYNET_INVALID_ARG("HierarchicalSoftmaxBuilder couldn't read clusters from " << cluster_file);
  int wc = 0;
  string line;
  vector<unsigned> path;
  Cluster* root = new Cluster();
  while(getline(in, line)) {
    path.clear();
    ++wc;
    const unsigned len = line.size();
    unsigned startp = 0;
    unsigned endp = 0;
    while (startp < len) {
      while (is_ws(line[startp]) && startp < len) { ++startp; }
      endp = startp;
      while (not_ws(line[endp]) && endp < len) { ++endp; }
      string symbol = line.substr(startp, endp - startp);
      path.push_back(path_symbols.convert(symbol));
      if (line[endp] == ' ') {
        startp = endp + 1;
        continue;
      }
      else {
        break;
      }
    }
    Cluster* node = root;
    for (unsigned symbol : path) {
      node = node->add_child(symbol);
    }

    unsigned startw = endp;
    while (is_ws(line[startw]) && startw < len) { ++startw; }
    unsigned endw = startw;
    while (not_ws(line[endw]) && endw < len) { ++endw; }
    if(endp <= startp || startw <= endp || endw <= startw)
      DYNET_INVALID_ARG("File formatting error in HierarchicalSoftmaxBuilder");

    string word = line.substr(startw, endw - startw);
    unsigned widx = word_dict.convert(word);
    node->add_word(widx);

    if (widx2path.size() <= widx) {
      widx2path.resize(widx + 1);
    }
    widx2path[widx] = node;
  }
  cerr << "Done reading clusters.\n";
  return root;
}

} // namespace dynet
<|endoftext|>


<commit_before>/* Copyright 2017 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "deepmath/guidance/vocabulary.h"

#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/env.h"

namespace deepmath {

using tensorflow::StringPiece;

static bool is_variable(const StringPiece word) {
  return !word.empty() && isupper(word[0]);
}

// Add variables, functions, and numbers from a file
void Vocabulary::Initialize(tensorflow::StringPiece path) {
  QCHECK(id_to_vocab_.empty()) << "Initialize called twice";

  // Remove flags from path
  bool one_variable = false;
  const auto slash = path.rfind('/');
  const auto colon = path.rfind(':');
  if (colon != string::npos && (slash == string::npos || slash < colon)) {
    for (const auto& flag :
         tensorflow::str_util::Split(path.substr(colon + 1), ',')) {
      if (flag == "one_variable") {
        one_variable = true;
      } else if (flag == "map_unknown") {
        map_unknown_ = true;
      } else {
        LOG(FATAL) << "Invalid vocabulary flag '" << flag << "'";
      }
    }
    path = path.substr(0, colon);
  }

  // A few symbols are used in string form by the weaver
  id_to_vocab_.resize(kStart);
  id_to_vocab_[kEqual] = "=";
  id_to_vocab_[kFalse] = "$false";
  id_to_vocab_[kTrue] = "$true";

  // Load vocabulary
  {
    string all_vocab;
    TF_CHECK_OK(tensorflow::ReadFileToString(
        tensorflow::Env::Default(), path.ToString(), &all_vocab));
    for (const auto& raw_word : tensorflow::str_util::Split(all_vocab, '\n')) {
      tensorflow::StringPiece word = raw_word;
      tensorflow::str_util::RemoveWhitespaceContext(&word);
      if (word.empty()) continue;
      for (const auto c : word) {
        QCHECK(isalnum(c) || c == '_') << "Nonalphanumeric vocab word '"
            << tensorflow::str_util::CEscape(word) << " in " << path;
      }
      if (one_variable && is_variable(word)) {
        if (variable_id_ < 0) {
          variable_id_ = id_to_vocab_.size();
          id_to_vocab_.push_back("X");
        }
      } else {
        id_to_vocab_.push_back(word.ToString());
      }
    }
  }

  // Invert id_to_vocab_
  for (int i = 0; i < id_to_vocab_.size(); i++) {
    if (!id_to_vocab_[i].empty()) {
      vocab_to_id_.emplace(id_to_vocab_[i], i);
    }
  }
}

// Lookup the id of a vocabulary word
int32 Vocabulary::Word(const string& word) const {
  if (variable_id_ >= 0 && is_variable(word)) return variable_id_;
  auto it = vocab_to_id_.find(word);
  if (it == vocab_to_id_.end() && map_unknown_) {
    if (variable_id_ >= 0)
      return variable_id_;
    else
      it = vocab_to_id_.find("X49");
  }
  QCHECK(it != vocab_to_id_.end()) << "Unknown vocabulary word: " << word;
  return it->second;
}

}  // namespace deepmath
<commit_msg>Internal changes<commit_after>/* Copyright 2017 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "deepmath/guidance/vocabulary.h"

#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/env.h"

namespace deepmath {

using tensorflow::StringPiece;

static bool is_variable(const StringPiece word) {
  return !word.empty() && isupper(word[0]);
}

// Add variables, functions, and numbers from a file
void Vocabulary::Initialize(tensorflow::StringPiece path) {
  QCHECK(id_to_vocab_.empty()) << "Initialize called twice";

  // Remove flags from path
  bool one_variable = false;
  const auto slash = path.rfind('/');
  const auto colon = path.rfind(':');
  if (colon != string::npos && (slash == string::npos || slash < colon)) {
    for (const auto& flag :
         tensorflow::str_util::Split(path.substr(colon + 1), ',')) {
      if (flag == "one_variable") {
        one_variable = true;
      } else if (flag == "map_unknown") {
        map_unknown_ = true;
      } else {
        LOG(FATAL) << "Invalid vocabulary flag '" << flag << "'";
      }
    }
    path = path.substr(0, colon);
  }

  // A few symbols are used in string form by the weaver
  id_to_vocab_.resize(kStart);
  id_to_vocab_[kEqual] = "=";
  id_to_vocab_[kFalse] = "$false";
  id_to_vocab_[kTrue] = "$true";

  // Load vocabulary
  {
    string all_vocab;
    TF_CHECK_OK(tensorflow::ReadFileToString(tensorflow::Env::Default(),
                                             std::string(path), &all_vocab));
    for (const auto& raw_word : tensorflow::str_util::Split(all_vocab, '\n')) {
      tensorflow::StringPiece word = raw_word;
      tensorflow::str_util::RemoveWhitespaceContext(&word);
      if (word.empty()) continue;
      for (const auto c : word) {
        QCHECK(isalnum(c) || c == '_') << "Nonalphanumeric vocab word '"
            << tensorflow::str_util::CEscape(word) << " in " << path;
      }
      if (one_variable && is_variable(word)) {
        if (variable_id_ < 0) {
          variable_id_ = id_to_vocab_.size();
          id_to_vocab_.push_back("X");
        }
      } else {
        id_to_vocab_.push_back(std::string(word));
      }
    }
  }

  // Invert id_to_vocab_
  for (int i = 0; i < id_to_vocab_.size(); i++) {
    if (!id_to_vocab_[i].empty()) {
      vocab_to_id_.emplace(id_to_vocab_[i], i);
    }
  }
}

// Lookup the id of a vocabulary word
int32 Vocabulary::Word(const string& word) const {
  if (variable_id_ >= 0 && is_variable(word)) return variable_id_;
  auto it = vocab_to_id_.find(word);
  if (it == vocab_to_id_.end() && map_unknown_) {
    if (variable_id_ >= 0)
      return variable_id_;
    else
      it = vocab_to_id_.find("X49");
  }
  QCHECK(it != vocab_to_id_.end()) << "Unknown vocabulary word: " << word;
  return it->second;
}

}  // namespace deepmath
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: memory.cc,v 1.58 2006/09/02 12:08:28 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#include "bochs.h"
#include "cpu/cpu.h"
#include "iodev/iodev.h"
#define LOG_THIS BX_MEM_THIS

#if BX_PROVIDE_CPU_MEMORY

//
// Memory map inside the 1st megabyte:
//
// 0x00000 - 0x7ffff    DOS area (512K)
// 0x80000 - 0x9ffff    Optional fixed memory hole (128K)
// 0xa0000 - 0xbffff    Standard PCI/ISA Video Mem / SMMRAM (128K)
// 0xc0000 - 0xdffff    Expansion Card BIOS and Buffer Area (128K)
// 0xe0000 - 0xeffff    Lower BIOS Area (64K)
// 0xf0000 - 0xfffff    Upper BIOS Area (64K)
//

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);
  struct memory_handler_struct *memory_handler = NULL;

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_write(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical write break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_write_watchpoints; i++) {
      if (write_watchpoint[i] == a20addr) {
        BX_CPU(0)->watchpoint = a20addr;
        BX_CPU(0)->break_point = BREAK_POINT_WRITE;
        break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected(a20addr, len)) {
      local_apic->write(a20addr, (Bit32u *)data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_write;
    }
  }

  memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->write_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_write:

  // all memory access feets in single 4K page
  if (a20addr < BX_MEM_THIS len) {
#if BX_SUPPORT_ICACHE
    pageWriteStampTable.decWriteStamp(a20addr);
#endif
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        WriteHostQWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit64u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 4) {
        WriteHostDWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit32u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 2) {
        WriteHostWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit16u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 1) {
        * ((Bit8u *) (&BX_MEM_THIS vector[a20addr])) = * (Bit8u *) data;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      // len == other, just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

write_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 000A0000 .. 000FFFFF
      BX_MEM_THIS vector[a20addr] = *data_ptr;
      BX_DBG_DIRTY_PAGE(a20addr >> 12);
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto write_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) {
        BX_MEM_THIS vector[a20addr] = *data_ptr;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
      }
      goto inc_one;
    }

    // adapter ROM     C0000 .. DFFFF
    // ROM BIOS memory E0000 .. FFFFF
#if BX_SUPPORT_PCI == 0
    // ignore write to ROM
#else
    // Write Based on 440fx Programming
    if (BX_MEM_THIS pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_wr_memtype(a20addr)) {
        case 0x1:   // Writes to ShadowRAM
          BX_DEBUG(("Writing to ShadowRAM: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          BX_MEM_THIS vector[a20addr] = *data_ptr;
          BX_DBG_DIRTY_PAGE(a20addr >> 12);
          goto inc_one;

        case 0x0:   // Writes to ROM, Inhibit
          BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          goto inc_one;

        default:
          BX_PANIC(("writePhysicalPage: default case"));
          goto inc_one;
      }
    }
#endif
    goto inc_one;
  }
  else {
    // access outside limits of physical memory, ignore
    BX_DEBUG(("Write outside the limits of physical memory (ignore)"));
  }
}

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);
  struct memory_handler_struct *memory_handler = NULL;

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_read(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical read break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_read_watchpoints; i++) {
      if (read_watchpoint[i] == a20addr) {
         BX_CPU(0)->watchpoint = a20addr;
         BX_CPU(0)->break_point = BREAK_POINT_READ;
         break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected (a20addr, len)) {
      local_apic->read(a20addr, data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_read;
    }
  }

  memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->read_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_read:

  if (a20addr <= BX_MEM_THIS len) {
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        ReadHostQWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit64u*) data);
        return;
      }
      if (len == 4) {
        ReadHostDWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit32u*) data);
        return;
      }
      if (len == 2) {
        ReadHostWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit16u*) data);
        return;
      }
      if (len == 1) {
        * (Bit8u *) data = * ((Bit8u *) (&BX_MEM_THIS vector[a20addr]));
        return;
      }
      // len == other case can just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

read_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 00080000 .. 000FFFFF
      *data_ptr = BX_MEM_THIS vector[a20addr];
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto read_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) *data_ptr = BX_MEM_THIS vector[a20addr];
      goto inc_one;
    }

#if BX_SUPPORT_PCI
    if (BX_MEM_THIS pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_rd_memtype(a20addr)) {
        case 0x0:  // Read from ROM
          if ((a20addr & 0xfffe0000) == 0x000e0000)
          {
            *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
          }
          else
          {
            *data_ptr = BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
          }
          goto inc_one;
        case 0x1:  // Read from ShadowRAM
          *data_ptr = BX_MEM_THIS vector[a20addr];
          goto inc_one;
        default:
          BX_PANIC(("readPhysicalPage: default case"));
      }
      goto inc_one;
    }
    else
#endif  // #if BX_SUPPORT_PCI
    {
      if ((a20addr & 0xfffc0000) != 0x000c0000) {
        *data_ptr = BX_MEM_THIS vector[a20addr];
      }
      else if ((a20addr & 0xfffe0000) == 0x000e0000)
      {
        *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
      }
      else
      {
        *data_ptr = BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
      }
      goto inc_one;
    }
  }
  else
  {  // access outside limits of physical memory

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

    for (unsigned i = 0; i < len; i++) {
      if (a20addr >= (bx_phy_address)~BIOS_MASK)
        *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
      else
        *data_ptr = 0xff;
      addr++;
      a20addr = (addr);
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
    }
  }
}

#endif // #if BX_PROVIDE_CPU_MEMORY
<commit_msg>Bochs website tracker patch shows where write outside of memory occurred<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: memory.cc,v 1.59 2006/12/29 08:02:35 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#include "bochs.h"
#include "cpu/cpu.h"
#include "iodev/iodev.h"
#define LOG_THIS BX_MEM_THIS

#if BX_PROVIDE_CPU_MEMORY

//
// Memory map inside the 1st megabyte:
//
// 0x00000 - 0x7ffff    DOS area (512K)
// 0x80000 - 0x9ffff    Optional fixed memory hole (128K)
// 0xa0000 - 0xbffff    Standard PCI/ISA Video Mem / SMMRAM (128K)
// 0xc0000 - 0xdffff    Expansion Card BIOS and Buffer Area (128K)
// 0xe0000 - 0xeffff    Lower BIOS Area (64K)
// 0xf0000 - 0xfffff    Upper BIOS Area (64K)
//

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);
  struct memory_handler_struct *memory_handler = NULL;

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_write(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical write break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_write_watchpoints; i++) {
      if (write_watchpoint[i] == a20addr) {
        BX_CPU(0)->watchpoint = a20addr;
        BX_CPU(0)->break_point = BREAK_POINT_WRITE;
        break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected(a20addr, len)) {
      local_apic->write(a20addr, (Bit32u *)data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_write;
    }
  }

  memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->write_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_write:

  // all memory access feets in single 4K page
  if (a20addr < BX_MEM_THIS len) {
#if BX_SUPPORT_ICACHE
    pageWriteStampTable.decWriteStamp(a20addr);
#endif
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        WriteHostQWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit64u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 4) {
        WriteHostDWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit32u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 2) {
        WriteHostWordToLittleEndian(&BX_MEM_THIS vector[a20addr], *(Bit16u*)data);
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      if (len == 1) {
        * ((Bit8u *) (&BX_MEM_THIS vector[a20addr])) = * (Bit8u *) data;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
        return;
      }
      // len == other, just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

write_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 000A0000 .. 000FFFFF
      BX_MEM_THIS vector[a20addr] = *data_ptr;
      BX_DBG_DIRTY_PAGE(a20addr >> 12);
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto write_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) {
        BX_MEM_THIS vector[a20addr] = *data_ptr;
        BX_DBG_DIRTY_PAGE(a20addr >> 12);
      }
      goto inc_one;
    }

    // adapter ROM     C0000 .. DFFFF
    // ROM BIOS memory E0000 .. FFFFF
#if BX_SUPPORT_PCI == 0
    // ignore write to ROM
#else
    // Write Based on 440fx Programming
    if (BX_MEM_THIS pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_wr_memtype(a20addr)) {
        case 0x1:   // Writes to ShadowRAM
          BX_DEBUG(("Writing to ShadowRAM: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          BX_MEM_THIS vector[a20addr] = *data_ptr;
          BX_DBG_DIRTY_PAGE(a20addr >> 12);
          goto inc_one;

        case 0x0:   // Writes to ROM, Inhibit
          BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
          goto inc_one;

        default:
          BX_PANIC(("writePhysicalPage: default case"));
          goto inc_one;
      }
    }
#endif
    goto inc_one;
  }
  else {
    // access outside limits of physical memory, ignore
    BX_DEBUG(("Write outside the limits of physical memory (0x%08x) (ignore)", a20addr));
  }
}

  void BX_CPP_AttrRegparmN(3)
BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  Bit8u *data_ptr;
  bx_phy_address a20addr = A20ADDR(addr);
  struct memory_handler_struct *memory_handler = NULL;

  // Note: accesses should always be contained within a single page now

  if (cpu != NULL) {
#if BX_SUPPORT_IODEBUG
    bx_iodebug_c::mem_read(cpu, a20addr, len, data);
#endif

    BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);

#if BX_DEBUGGER
    // (mch) Check for physical read break points, TODO
    // (bbd) Each breakpoint should have an associated CPU#, TODO
    for (int i = 0; i < num_read_watchpoints; i++) {
      if (read_watchpoint[i] == a20addr) {
         BX_CPU(0)->watchpoint = a20addr;
         BX_CPU(0)->break_point = BREAK_POINT_READ;
         break;
      }
    }
#endif

#if BX_SUPPORT_APIC
    bx_generic_apic_c *local_apic = &cpu->local_apic;
    if (local_apic->is_selected (a20addr, len)) {
      local_apic->read(a20addr, data, len);
      return;
    }
#endif

    if ((a20addr & 0xfffe0000) == 0x000a0000 && (BX_MEM_THIS smram_available))
    {
      // SMRAM memory space
      if (BX_MEM_THIS smram_enable || (cpu->smm_mode() && !BX_MEM_THIS smram_restricted))
        goto mem_read;
    }
  }

  memory_handler = BX_MEM_THIS memory_handlers[a20addr >> 20];
  while (memory_handler) {
    if (memory_handler->begin <= a20addr &&
          memory_handler->end >= a20addr &&
          memory_handler->read_handler(a20addr, len, data, memory_handler->param))
    {
      return;
    }
    memory_handler = memory_handler->next;
  }

mem_read:

  if (a20addr <= BX_MEM_THIS len) {
    // all of data is within limits of physical memory
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      if (len == 8) {
        ReadHostQWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit64u*) data);
        return;
      }
      if (len == 4) {
        ReadHostDWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit32u*) data);
        return;
      }
      if (len == 2) {
        ReadHostWordFromLittleEndian(&BX_MEM_THIS vector[a20addr], * (Bit16u*) data);
        return;
      }
      if (len == 1) {
        * (Bit8u *) data = * ((Bit8u *) (&BX_MEM_THIS vector[a20addr]));
        return;
      }
      // len == other case can just fall thru to special cases handling
    }

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

read_one:
    if ((a20addr & 0xfff80000) != 0x00080000 || (a20addr <= 0x0009ffff))
    {
      // addr *not* in range 00080000 .. 000FFFFF
      *data_ptr = BX_MEM_THIS vector[a20addr];
inc_one:
      if (len == 1) return;
      len--;
      a20addr++;
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
      goto read_one;
    }

    // addr must be in range 000A0000 .. 000FFFFF

    // SMMRAM
    if (a20addr <= 0x000bffff) {
      // devices are not allowed to access SMMRAM under VGA memory
      if (cpu) *data_ptr = BX_MEM_THIS vector[a20addr];
      goto inc_one;
    }

#if BX_SUPPORT_PCI
    if (BX_MEM_THIS pci_enabled && ((a20addr & 0xfffc0000) == 0x000c0000))
    {
      switch (DEV_pci_rd_memtype(a20addr)) {
        case 0x0:  // Read from ROM
          if ((a20addr & 0xfffe0000) == 0x000e0000)
          {
            *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
          }
          else
          {
            *data_ptr = BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
          }
          goto inc_one;
        case 0x1:  // Read from ShadowRAM
          *data_ptr = BX_MEM_THIS vector[a20addr];
          goto inc_one;
        default:
          BX_PANIC(("readPhysicalPage: default case"));
      }
      goto inc_one;
    }
    else
#endif  // #if BX_SUPPORT_PCI
    {
      if ((a20addr & 0xfffc0000) != 0x000c0000) {
        *data_ptr = BX_MEM_THIS vector[a20addr];
      }
      else if ((a20addr & 0xfffe0000) == 0x000e0000)
      {
        *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
      }
      else
      {
        *data_ptr = BX_MEM_THIS rom[(a20addr & EXROM_MASK) + BIOSROMSZ];
      }
      goto inc_one;
    }
  }
  else
  {  // access outside limits of physical memory

#ifdef BX_LITTLE_ENDIAN
    data_ptr = (Bit8u *) data;
#else // BX_BIG_ENDIAN
    data_ptr = (Bit8u *) data + (len - 1);
#endif

    for (unsigned i = 0; i < len; i++) {
      if (a20addr >= (bx_phy_address)~BIOS_MASK)
        *data_ptr = BX_MEM_THIS rom[a20addr & BIOS_MASK];
      else
        *data_ptr = 0xff;
      addr++;
      a20addr = (addr);
#ifdef BX_LITTLE_ENDIAN
      data_ptr++;
#else // BX_BIG_ENDIAN
      data_ptr--;
#endif
    }
  }
}

#endif // #if BX_PROVIDE_CPU_MEMORY
<|endoftext|>


<commit_before>#include <iostream>
#include <boost/variant.hpp>

using std::nullptr_t;
using std::pair;
using std::make_pair;
using std::move;

template <typename T, typename F, typename BaseInner, typename ArgsT>
struct ComposeVariantVisitor
{
  struct Inner : BaseInner
  {
    Inner(ArgsT&& a) : BaseInner(std::move(a.second)), f_(std::move(a.first)) {}

    void operator()(const T& t) const { f_(t); }

private:

    F f_;
  };

  ComposeVariantVisitor(ArgsT&& args) : m_args(move(args))
  {
  }

  template<typename Tadd, typename Fadd>
  auto on(Fadd&& f)
  {
    return ComposeVariantVisitor<Tadd, Fadd, Inner, std::pair<Fadd, ArgsT>>(
        make_pair(move(f), move(m_args)));
  }

  auto end_variant_visitor()
  {
    return Inner(move(m_args));
  }

  ArgsT m_args;
};

struct EmptyVariantVisitor
{
  struct Inner : public boost::static_visitor<>
  {
    Inner(nullptr_t)
    {
    }
  };

  template <typename Tadd, typename Fadd>
  auto on(Fadd&& f)
  {
    return ComposeVariantVisitor<Tadd, Fadd, Inner, pair<Fadd, nullptr_t>>(
        make_pair(move(f), nullptr));
  }
};

EmptyVariantVisitor begin_variant_visitor()
{
    return EmptyVariantVisitor();
}

int main(int argc, char* argv[])
{
  boost::variant<int,double,char> v;

  /////////////////////////////////////////////////////////////

  struct printer : boost::static_visitor<>
  {
    void operator()(const int i) const { std::cout << i << "\n"; }
    void operator()(const double d) const { std::cout << d << "\n"; }
    void operator()(const char c) const { std::cout << c << "\n"; }
  };

  v = 7;
  boost::apply_visitor(printer(), v);

  v = 3.14159;
  boost::apply_visitor(printer(), v);

  v = 'p';
  boost::apply_visitor(printer(), v);

  /////////////////////////////////////////////////////////////

  auto inline_printer = begin_variant_visitor()
    .on<int>([](const int i) { std::cout << i << "\n";})
    .on<double>([](const double d) { std::cout << d << "\n";})
    .on<char>([](const char c) { std::cout << c << "\n";})
    .end_variant_visitor();

  v = 7;
  boost::apply_visitor(inline_printer, v);

  v = 3.14159;
  boost::apply_visitor(inline_printer, v);

  v = 'p';
  boost::apply_visitor(inline_printer, v);
}

<commit_msg>Inline variant visitor fails for class types<commit_after>#include <iostream>
#include <boost/variant.hpp>

using std::nullptr_t;
using std::pair;
using std::make_pair;
using std::move;

template <typename T, typename F, typename BaseInner, typename ArgsT>
struct ComposeVariantVisitor
{
  struct Inner : BaseInner
  {
    Inner(ArgsT&& a) : BaseInner(std::move(a.second)), f_(std::move(a.first)) {}

    void operator()(T& t) const { f_(t); }

private:

    F f_;
  };

  ComposeVariantVisitor(ArgsT&& args) : m_args(move(args))
  {
  }

  template<typename Tadd, typename Fadd>
  auto on(Fadd&& f)
  {
    return ComposeVariantVisitor<Tadd, Fadd, Inner, std::pair<Fadd, ArgsT>>(
        make_pair(move(f), move(m_args)));
  }

  auto end_variant_visitor()
  {
    return Inner(move(m_args));
  }

  ArgsT m_args;
};

struct EmptyVariantVisitor
{
  struct Inner : public boost::static_visitor<>
  {
    Inner(nullptr_t)
    {
    }
  };

  template <typename Tadd, typename Fadd>
  auto on(Fadd&& f)
  {
    return ComposeVariantVisitor<Tadd, Fadd, Inner, pair<Fadd, nullptr_t>>(
        make_pair(move(f), nullptr));
  }
};

EmptyVariantVisitor begin_variant_visitor()
{
    return EmptyVariantVisitor();
}

class A{};
class B{};
class C{};

int main(int argc, char* argv[])
{
  boost::variant<A,B,C> v;

  /////////////////////////////////////////////////////////////

  struct printer : boost::static_visitor<>
  {
    void operator()(A&) const { std::cout << "A\n"; }
    void operator()(B&) const { std::cout << "B\n"; }
    void operator()(C&) const { std::cout << "C\n"; }
  };

  v = A();
  boost::apply_visitor(printer(), v);

  v = B();
  boost::apply_visitor(printer(), v);

  v = C();
  boost::apply_visitor(printer(), v);

  /////////////////////////////////////////////////////////////

  auto inline_printer = begin_variant_visitor()
    .on<A>([](A&) { std::cout << "A\n";})
    .on<B>([](B&) { std::cout << "B\n";})
    .on<C>([](C&) { std::cout << "C\n";})
    .end_variant_visitor();

  v = A();
  boost::apply_visitor(inline_printer, v);

  v = B();
  boost::apply_visitor(inline_printer, v);

  v = C();
  boost::apply_visitor(inline_printer, v);
}

<|endoftext|>


<commit_before>/**
@file Data/Metadata.hpp
@brief Metadata classes.

@author Timothy Howard
@copyright 2013-2014 Timothy Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_DATA_METADATA_HPP_
#define HORD_DATA_METADATA_HPP_

#include <Hord/config.hpp>
#include <Hord/aux.hpp>
#include <Hord/String.hpp>
#include <Hord/serialization.hpp>
#include <Hord/Data/Defs.hpp>
#include <Hord/IO/PropStream.hpp>

#include <duct/cc_unique_ptr.hpp>

namespace Hord {
namespace Data {

// Forward declarations
class MetaField;
class StringMetaField;
class Int32MetaField;
class Int64MetaField;
class BoolMetaField;
struct Metadata;

/**
	@addtogroup data
	@{
*/
/**
	@addtogroup metadata
	@{
*/

/**
	Base Metadata field.

	@note read() and write() will serialize base properties;
	implementations shall serialize only their own properties.
*/
class MetaField {
public:
	/**
		Type info.
	*/
	struct type_info final {
		/** Type. */
		MetaFieldType const type;

		/**
			Default-construct field of this type.

			@returns Pointer to field, or @c nullptr if allocation
			failed.
		*/
		MetaField*
		(&construct)() noexcept;
	};

/** @name Properties */ /// @{
	/**
		Name.

		@warning This field will be truncated to 255 code units
		when serializing.
	*/
	String name{};
/// @}

private:
	MetaField(MetaField const&) = delete;
	MetaField& operator=(MetaField const&) = delete;

protected:
/** @name Implementation */ /// @{
	/**
		get_type_info() implementation.
	*/
	virtual type_info const&
	get_type_info_impl() const noexcept = 0;

	/**
		read() implementation.

		@throws SerializerError{..}
	*/
	virtual ser_result_type
	read_impl(
		InputSerializer& ser
	) = 0;

	/**
		write() implementation.

		@throws SerializerError{..}
	*/
	virtual ser_result_type
	write_impl(
		OutputSerializer& ser
	) const = 0;
/// @}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	virtual
	~MetaField() noexcept = 0;

	/** Default constructor. */
	MetaField() = default;
	/** Move constructor. */
	MetaField(MetaField&&) = default;
	/** Move assignment operator. */
	MetaField& operator=(MetaField&&) = default;

	/**
		Constructor with name.
	*/
	explicit
	MetaField(
		String name
	) noexcept
		: name(std::move(name))
	{}
/// @}

public:
/** @name Properties */ /// @{
	/**
		Get type info.
	*/
	type_info const&
	get_type_info() const noexcept {
		return get_type_info_impl();
	}

	/**
		Set name.
	*/
	void
	set_name(
		String new_name
	) noexcept {
		this->name.assign(std::move(new_name));
		if (0xFF < this->name.size()) {
			this->name.resize(0xFF);
			// TODO: Truncate invalid unit sequence (if any) after resize
		}
	}
/// @}

/** @name Serialization */ /// @{
	/**
		Read from input serializer.

		@throws SerializerError{..}
		If a serialization operation failed.
	*/
	ser_result_type
	read(
		ser_tag_read,
		InputSerializer& ser
	) {
		ser(Cacophony::make_string_cfg<std::uint8_t>(this->name));
		read_impl(ser);
	}

	/**
		Write to output serializer.

		@throws SerializerError{..}
		If a serialization operation failed.
	*/
	ser_result_type
	write(
		ser_tag_write,
		OutputSerializer& ser
	) const {
		ser(Cacophony::make_string_cfg<std::uint8_t>(this->name));
		write_impl(ser);
	}
/// @}
};
inline MetaField::~MetaField() noexcept = default;

/**
	String MetaField.
*/
class StringMetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	String value{};
/// @}

private:
	StringMetaField(StringMetaField const&) = delete;
	StringMetaField& operator=(StringMetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		ser(this->value);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(this->value);
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~StringMetaField() noexcept override = default;

	/** Default constructor. */
	StringMetaField() = default;
	/** Move constructor. */
	StringMetaField(StringMetaField&&) = default;
	/** Move assignment operator. */
	StringMetaField& operator=(StringMetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	StringMetaField(
		String name,
		String value
	) noexcept
		: MetaField(std::move(name))
		, value(std::move(value))
	{}
/// @}
};

/**
	Int32 MetaField.
*/
class Int32MetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	std::int32_t value{0};
/// @}

private:
	Int32MetaField(Int32MetaField const&) = delete;
	Int32MetaField& operator=(Int32MetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		ser(this->value);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(this->value);
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~Int32MetaField() noexcept override = default;

	/** Default constructor. */
	Int32MetaField() = default;
	/** Move constructor. */
	Int32MetaField(Int32MetaField&&) = default;
	/** Move assignment operator. */
	Int32MetaField& operator=(Int32MetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	Int32MetaField(
		String name,
		std::int32_t value
	) noexcept
		: MetaField(std::move(name))
		, value(value)
	{}
/// @}
};

/**
	Int64 MetaField.
*/
class Int64MetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	std::int64_t value{0};
/// @}

private:
	Int64MetaField(Int64MetaField const&) = delete;
	Int64MetaField& operator=(Int64MetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		ser(this->value);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(this->value);
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~Int64MetaField() noexcept override = default;

	/** Default constructor. */
	Int64MetaField() = default;
	/** Move constructor. */
	Int64MetaField(Int64MetaField&&) = default;
	/** Move assignment operator. */
	Int64MetaField& operator=(Int64MetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	Int64MetaField(
		String name,
		std::int64_t value
	) noexcept
		: MetaField(std::move(name))
		, value(value)
	{}
/// @}
};

/**
	Bool MetaField.
*/
class BoolMetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	bool value{false};
/// @}

private:
	BoolMetaField(BoolMetaField const&) = delete;
	BoolMetaField& operator=(BoolMetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		std::uint8_t boolu8 = 0;
		ser(boolu8);
		this->value = static_cast<bool>(boolu8);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(static_cast<std::uint8_t>(this->value));
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~BoolMetaField() noexcept override = default;

	/** Default constructor. */
	BoolMetaField() = default;
	/** Move constructor. */
	BoolMetaField(BoolMetaField&&) = default;
	/** Move assignment operator. */
	BoolMetaField& operator=(BoolMetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	BoolMetaField(
		String name,
		bool value
	) noexcept
		: MetaField(std::move(name))
		, value(value)
	{}
/// @}
};

/**
	Metadata.

	@sa IO::PropType::metadata
*/
struct Metadata final {
public:
	/** MetaField vector. */
	using field_vector_type
	= aux::vector<
		duct::cc_unique_ptr<MetaField>
	>;

/** @name Properties */ /// @{
	/** Fields. */
	field_vector_type fields{};
/// @}

private:
	Metadata(Metadata const&) = delete;
	Metadata& operator=(Metadata const&) = delete;

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~Metadata() noexcept = default;

	/** Default constructor. */
	Metadata() = default;
	/** Move constructor. */
	Metadata(Metadata&&) = default;
	/** Move assignment operator. */
	Metadata& operator=(Metadata&&) = default;
/// @}

/** @name Serialization */ /// @{
	/**
		Deserialize from prop stream.

		@note State will be retained if an exception is thrown.

		@pre @code
			IO::PropType::metadata == prop_stream.get_type()
		@endcode

		@throws Error{ErrorCode::serialization_io_failed}
		If an input operation failed.

		@throws Error{ErrorCode::serialization_data_malformed}
		If an invalid field type is encountered in the prop stream.

		@param prop_stream %Prop stream.
	*/
	void
	deserialize(
		IO::InputPropStream& prop_stream
	);

	/**
		Serialize to prop stream.

		@note State will be retained if an exception is thrown.

		@pre @code
			IO::PropType::metadata == prop_stream.get_type()
		@endcode

		@throws Error{ErrorCode::serialization_io_failed}
		If an output operation failed.

		@param prop_stream %Prop stream.
	*/
	void
	serialize(
		IO::OutputPropStream& prop_stream
	) const;
/// @}
};

/** @} */ // end of doc-group metadata
/** @} */ // end of doc-group data

} // namespace Data
} // namespace Hord

#endif // HORD_DATA_METADATA_HPP_
<commit_msg>:Data::MetaField: constified non-moved values in ctors.<commit_after>/**
@file Data/Metadata.hpp
@brief Metadata classes.

@author Timothy Howard
@copyright 2013-2014 Timothy Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_DATA_METADATA_HPP_
#define HORD_DATA_METADATA_HPP_

#include <Hord/config.hpp>
#include <Hord/aux.hpp>
#include <Hord/String.hpp>
#include <Hord/serialization.hpp>
#include <Hord/Data/Defs.hpp>
#include <Hord/IO/PropStream.hpp>

#include <duct/cc_unique_ptr.hpp>

namespace Hord {
namespace Data {

// Forward declarations
class MetaField;
class StringMetaField;
class Int32MetaField;
class Int64MetaField;
class BoolMetaField;
struct Metadata;

/**
	@addtogroup data
	@{
*/
/**
	@addtogroup metadata
	@{
*/

/**
	Base Metadata field.

	@note read() and write() will serialize base properties;
	implementations shall serialize only their own properties.
*/
class MetaField {
public:
	/**
		Type info.
	*/
	struct type_info final {
		/** Type. */
		MetaFieldType const type;

		/**
			Default-construct field of this type.

			@returns Pointer to field, or @c nullptr if allocation
			failed.
		*/
		MetaField*
		(&construct)() noexcept;
	};

/** @name Properties */ /// @{
	/**
		Name.

		@warning This field will be truncated to 255 code units
		when serializing.
	*/
	String name{};
/// @}

private:
	MetaField(MetaField const&) = delete;
	MetaField& operator=(MetaField const&) = delete;

protected:
/** @name Implementation */ /// @{
	/**
		get_type_info() implementation.
	*/
	virtual type_info const&
	get_type_info_impl() const noexcept = 0;

	/**
		read() implementation.

		@throws SerializerError{..}
	*/
	virtual ser_result_type
	read_impl(
		InputSerializer& ser
	) = 0;

	/**
		write() implementation.

		@throws SerializerError{..}
	*/
	virtual ser_result_type
	write_impl(
		OutputSerializer& ser
	) const = 0;
/// @}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	virtual
	~MetaField() noexcept = 0;

	/** Default constructor. */
	MetaField() = default;
	/** Move constructor. */
	MetaField(MetaField&&) = default;
	/** Move assignment operator. */
	MetaField& operator=(MetaField&&) = default;

	/**
		Constructor with name.
	*/
	explicit
	MetaField(
		String name
	) noexcept
		: name(std::move(name))
	{}
/// @}

public:
/** @name Properties */ /// @{
	/**
		Get type info.
	*/
	type_info const&
	get_type_info() const noexcept {
		return get_type_info_impl();
	}

	/**
		Set name.
	*/
	void
	set_name(
		String new_name
	) noexcept {
		this->name.assign(std::move(new_name));
		if (0xFF < this->name.size()) {
			this->name.resize(0xFF);
			// TODO: Truncate invalid unit sequence (if any) after resize
		}
	}
/// @}

/** @name Serialization */ /// @{
	/**
		Read from input serializer.

		@throws SerializerError{..}
		If a serialization operation failed.
	*/
	ser_result_type
	read(
		ser_tag_read,
		InputSerializer& ser
	) {
		ser(Cacophony::make_string_cfg<std::uint8_t>(this->name));
		read_impl(ser);
	}

	/**
		Write to output serializer.

		@throws SerializerError{..}
		If a serialization operation failed.
	*/
	ser_result_type
	write(
		ser_tag_write,
		OutputSerializer& ser
	) const {
		ser(Cacophony::make_string_cfg<std::uint8_t>(this->name));
		write_impl(ser);
	}
/// @}
};
inline MetaField::~MetaField() noexcept = default;

/**
	String MetaField.
*/
class StringMetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	String value{};
/// @}

private:
	StringMetaField(StringMetaField const&) = delete;
	StringMetaField& operator=(StringMetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		ser(this->value);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(this->value);
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~StringMetaField() noexcept override = default;

	/** Default constructor. */
	StringMetaField() = default;
	/** Move constructor. */
	StringMetaField(StringMetaField&&) = default;
	/** Move assignment operator. */
	StringMetaField& operator=(StringMetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	StringMetaField(
		String name,
		String value
	) noexcept
		: MetaField(std::move(name))
		, value(std::move(value))
	{}
/// @}
};

/**
	Int32 MetaField.
*/
class Int32MetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	std::int32_t value{0};
/// @}

private:
	Int32MetaField(Int32MetaField const&) = delete;
	Int32MetaField& operator=(Int32MetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		ser(this->value);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(this->value);
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~Int32MetaField() noexcept override = default;

	/** Default constructor. */
	Int32MetaField() = default;
	/** Move constructor. */
	Int32MetaField(Int32MetaField&&) = default;
	/** Move assignment operator. */
	Int32MetaField& operator=(Int32MetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	Int32MetaField(
		String name,
		std::int32_t const value
	) noexcept
		: MetaField(std::move(name))
		, value(value)
	{}
/// @}
};

/**
	Int64 MetaField.
*/
class Int64MetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	std::int64_t value{0};
/// @}

private:
	Int64MetaField(Int64MetaField const&) = delete;
	Int64MetaField& operator=(Int64MetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		ser(this->value);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(this->value);
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~Int64MetaField() noexcept override = default;

	/** Default constructor. */
	Int64MetaField() = default;
	/** Move constructor. */
	Int64MetaField(Int64MetaField&&) = default;
	/** Move assignment operator. */
	Int64MetaField& operator=(Int64MetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	Int64MetaField(
		String name,
		std::int64_t const value
	) noexcept
		: MetaField(std::move(name))
		, value(value)
	{}
/// @}
};

/**
	Bool MetaField.
*/
class BoolMetaField final
	: public MetaField
{
public:
/** @name Properties */ /// @{
	/** Value. */
	bool value{false};
/// @}

private:
	BoolMetaField(BoolMetaField const&) = delete;
	BoolMetaField& operator=(BoolMetaField const&) = delete;

	MetaField::type_info const&
	get_type_info_impl() const noexcept override;

	ser_result_type
	read_impl(
		InputSerializer& ser
	) override {
		std::uint8_t boolu8 = 0;
		ser(boolu8);
		this->value = static_cast<bool>(boolu8);
	}

	ser_result_type
	write_impl(
		OutputSerializer& ser
	) const override {
		ser(static_cast<std::uint8_t>(this->value));
	}

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~BoolMetaField() noexcept override = default;

	/** Default constructor. */
	BoolMetaField() = default;
	/** Move constructor. */
	BoolMetaField(BoolMetaField&&) = default;
	/** Move assignment operator. */
	BoolMetaField& operator=(BoolMetaField&&) = default;

	/**
		Constructor with name and value.
	*/
	BoolMetaField(
		String name,
		bool const value
	) noexcept
		: MetaField(std::move(name))
		, value(value)
	{}
/// @}
};

/**
	Metadata.

	@sa IO::PropType::metadata
*/
struct Metadata final {
public:
	/** MetaField vector. */
	using field_vector_type
	= aux::vector<
		duct::cc_unique_ptr<MetaField>
	>;

/** @name Properties */ /// @{
	/** Fields. */
	field_vector_type fields{};
/// @}

private:
	Metadata(Metadata const&) = delete;
	Metadata& operator=(Metadata const&) = delete;

public:
/** @name Special member functions */ /// @{
	/** Destructor. */
	~Metadata() noexcept = default;

	/** Default constructor. */
	Metadata() = default;
	/** Move constructor. */
	Metadata(Metadata&&) = default;
	/** Move assignment operator. */
	Metadata& operator=(Metadata&&) = default;
/// @}

/** @name Serialization */ /// @{
	/**
		Deserialize from prop stream.

		@note State will be retained if an exception is thrown.

		@pre @code
			IO::PropType::metadata == prop_stream.get_type()
		@endcode

		@throws Error{ErrorCode::serialization_io_failed}
		If an input operation failed.

		@throws Error{ErrorCode::serialization_data_malformed}
		If an invalid field type is encountered in the prop stream.

		@param prop_stream %Prop stream.
	*/
	void
	deserialize(
		IO::InputPropStream& prop_stream
	);

	/**
		Serialize to prop stream.

		@note State will be retained if an exception is thrown.

		@pre @code
			IO::PropType::metadata == prop_stream.get_type()
		@endcode

		@throws Error{ErrorCode::serialization_io_failed}
		If an output operation failed.

		@param prop_stream %Prop stream.
	*/
	void
	serialize(
		IO::OutputPropStream& prop_stream
	) const;
/// @}
};

/** @} */ // end of doc-group metadata
/** @} */ // end of doc-group data

} // namespace Data
} // namespace Hord

#endif // HORD_DATA_METADATA_HPP_
<|endoftext|>


<commit_before>/**
@file serialization.hpp
@brief Serialization definitions.

@author Timothy Howard
@copyright 2013-2014 Timothy Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_SERIALIZATION_HPP_
#define HORD_SERIALIZATION_HPP_

#include <Hord/config.hpp>

#include <Cacophony/types.hpp>
#include <Cacophony/traits.hpp>
#include <Cacophony/utility.hpp>
#include <Cacophony/ErrorCode.hpp>
#include <Cacophony/Error.hpp>
#include <Cacophony/BinarySerializer.hpp>
#include <Cacophony/support/binary_blob.hpp>
#include <Cacophony/support/sequence.hpp>
#include <Cacophony/support/string_cfg.hpp>
#include <Cacophony/support/vector_cfg.hpp>
#include <Cacophony/support/std_string.hpp>
#include <Cacophony/support/std_vector.hpp>

#include <duct/EndianUtils.hpp>

namespace Hord {

// Forward declarations

/**
	@addtogroup serialization
	@{
*/

using Cacophony::const_safe;

/**
	Serializer error code type.
*/
using SerializerErrorCode = Cacophony::ErrorCode;

/**
	Serializer error type.
*/
using SerializerError = Cacophony::Error;

/**
	Data input serializer.
*/
using InputSerializer = Cacophony::BinaryInputSerializer;

/**
	Data output serializer.
*/
using OutputSerializer = Cacophony::BinaryOutputSerializer;

/**
	Serialization function result type.
*/
using ser_result_type = Cacophony::ser_result_type;

/**
	Serialization function tags for Cacophony.

	These should come first in the serialization function parameter
	list.
	@{
*/
using ser_tag_serialize = Cacophony::tag_serialize;
using ser_tag_read = Cacophony::tag_read;
using ser_tag_write = Cacophony::tag_write;
/** @} */

/**
	Get the name of a serializer error.

	@returns C-string containing the name of @a error_code or
	"INVALID" if somehow @a error_code is not actually a
	SerializerErrorCode.
*/
inline char const*
get_ser_error_name(
	SerializerErrorCode const error_code
) noexcept {
	return Cacophony::get_error_name(error_code);
}

/**
	Make input serializer.
*/
inline InputSerializer
make_input_serializer(
	std::istream& stream
) noexcept {
	return InputSerializer{stream, HORD_DATA_ENDIAN};
}

/**
	Make output serializer.
*/
inline OutputSerializer
make_output_serializer(
	std::ostream& stream
) noexcept {
	return OutputSerializer{stream, HORD_DATA_ENDIAN};
}

/** @cond INTERNAL */
#define HORD_SER_ERR_MSG_IO_GENERIC(skind_)			\
	"failed to " skind_ ":"							\
	" serialization error: \n  {%s} %s"

#define HORD_SER_ERR_MSG_IO_PROP(skind_)			\
	"failed to " skind_ " prop %08x -> %s:"			\
	" serialization error: \n  {%s} %s"

#define HORD_THROW_SER_FMT(efmt_, serr_)			\
	HORD_THROW_FMT(									\
		ErrorCode::serialization_io_failed,			\
		efmt_,										\
		get_ser_error_name(serr_.get_code()),		\
		serr_.get_message()							\
	)
//

#define HORD_THROW_SER_PROP(efmt_, serr_, objid_, pkind_)	\
	HORD_THROW_FMT(											\
		Hord::ErrorCode::serialization_io_failed,			\
		efmt_,												\
		objid_,												\
		pkind_,												\
		Hord::get_ser_error_name(serr_.get_code()),			\
		serr_.get_message()									\
	)
//
/** @endcond */ // INTERNAL

/** @} */ // end of doc-group serialization

} // namespace Hord

#endif // HORD_SERIALIZATION_HPP_
<commit_msg>serialization: included Cacophony::enum_cfg.<commit_after>/**
@file serialization.hpp
@brief Serialization definitions.

@author Timothy Howard
@copyright 2013-2014 Timothy Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_SERIALIZATION_HPP_
#define HORD_SERIALIZATION_HPP_

#include <Hord/config.hpp>

#include <Cacophony/types.hpp>
#include <Cacophony/traits.hpp>
#include <Cacophony/utility.hpp>
#include <Cacophony/ErrorCode.hpp>
#include <Cacophony/Error.hpp>
#include <Cacophony/BinarySerializer.hpp>
#include <Cacophony/support/binary_blob.hpp>
#include <Cacophony/support/sequence.hpp>
#include <Cacophony/support/enum_cfg.hpp>
#include <Cacophony/support/string_cfg.hpp>
#include <Cacophony/support/vector_cfg.hpp>
#include <Cacophony/support/std_string.hpp>
#include <Cacophony/support/std_vector.hpp>

#include <duct/EndianUtils.hpp>

namespace Hord {

// Forward declarations

/**
	@addtogroup serialization
	@{
*/

using Cacophony::const_safe;

/**
	Serializer error code type.
*/
using SerializerErrorCode = Cacophony::ErrorCode;

/**
	Serializer error type.
*/
using SerializerError = Cacophony::Error;

/**
	Data input serializer.
*/
using InputSerializer = Cacophony::BinaryInputSerializer;

/**
	Data output serializer.
*/
using OutputSerializer = Cacophony::BinaryOutputSerializer;

/**
	Serialization function result type.
*/
using ser_result_type = Cacophony::ser_result_type;

/**
	Serialization function tags for Cacophony.

	These should come first in the serialization function parameter
	list.
	@{
*/
using ser_tag_serialize = Cacophony::tag_serialize;
using ser_tag_read = Cacophony::tag_read;
using ser_tag_write = Cacophony::tag_write;
/** @} */

/**
	Get the name of a serializer error.

	@returns C-string containing the name of @a error_code or
	"INVALID" if somehow @a error_code is not actually a
	SerializerErrorCode.
*/
inline char const*
get_ser_error_name(
	SerializerErrorCode const error_code
) noexcept {
	return Cacophony::get_error_name(error_code);
}

/**
	Make input serializer.
*/
inline InputSerializer
make_input_serializer(
	std::istream& stream
) noexcept {
	return InputSerializer{stream, HORD_DATA_ENDIAN};
}

/**
	Make output serializer.
*/
inline OutputSerializer
make_output_serializer(
	std::ostream& stream
) noexcept {
	return OutputSerializer{stream, HORD_DATA_ENDIAN};
}

/** @cond INTERNAL */
#define HORD_SER_ERR_MSG_IO_GENERIC(skind_)			\
	"failed to " skind_ ":"							\
	" serialization error: \n  {%s} %s"

#define HORD_SER_ERR_MSG_IO_PROP(skind_)			\
	"failed to " skind_ " prop %08x -> %s:"			\
	" serialization error: \n  {%s} %s"

#define HORD_THROW_SER_FMT(efmt_, serr_)			\
	HORD_THROW_FMT(									\
		ErrorCode::serialization_io_failed,			\
		efmt_,										\
		get_ser_error_name(serr_.get_code()),		\
		serr_.get_message()							\
	)
//

#define HORD_THROW_SER_PROP(efmt_, serr_, objid_, pkind_)	\
	HORD_THROW_FMT(											\
		Hord::ErrorCode::serialization_io_failed,			\
		efmt_,												\
		objid_,												\
		pkind_,												\
		Hord::get_ser_error_name(serr_.get_code()),			\
		serr_.get_message()									\
	)
//
/** @endcond */ // INTERNAL

/** @} */ // end of doc-group serialization

} // namespace Hord

#endif // HORD_SERIALIZATION_HPP_
<|endoftext|>