<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/util/util.hpp>

#include <nix/hdf5/DataArrayHDF5.hpp>
#include <nix/hdf5/DataSet.hpp>
#include <nix/hdf5/DimensionHDF5.hpp>

using namespace std;

namespace nix {
namespace hdf5 {

DataArrayHDF5::DataArrayHDF5(const DataArrayHDF5 &data_array)
    : EntityWithSourcesHDF5(data_array.file(), data_array.block(), data_array.group(), data_array.id(), data_array.type(), data_array.name()),
      dimension_group(data_array.dimension_group)
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name)
    : DataArrayHDF5(file, block, group, id, type, name, util::getTime())
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name, time_t time)
    : EntityWithSourcesHDF5(file, block, group, id, type, name, time)
{
    dimension_group = this->group().openGroup("dimensions", true);
}

//--------------------------------------------------
// Element getters and setters
//--------------------------------------------------

boost::optional<std::string> DataArrayHDF5::label() const {
    boost::optional<std::string> ret;
    string value;
    group().getAttr("label", value);
    ret = value;
    return ret;
}

void DataArrayHDF5::label(const string &label) {
    if(label.empty()) {
        throw EmptyString("label");
    }
    else {
        group().setAttr("label", label);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::label(const none_t t) {
    if(group().hasAttr("label")) {
        group().removeAttr("label");
    }
    forceUpdatedAt();
}

boost::optional<std::string> DataArrayHDF5::unit() const {
    boost::optional<std::string> ret;
    string value;
    group().getAttr("unit", value);
    ret = value;
    return ret;
}

void DataArrayHDF5::unit(const string &unit) {
    if(unit.empty()) {
        throw EmptyString("unit");
    }
    else {
        group().setAttr("unit", unit);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::unit(const none_t t) {
    if(group().hasAttr("unit")) {
        group().removeAttr("unit");
    }
    forceUpdatedAt();
}

// TODO use defaults
boost::optional<double> DataArrayHDF5::expansionOrigin() const {
    boost::optional<double> ret;
    double expansion_origin;
    group().getAttr("expansion_origin", expansion_origin);
    ret = expansion_origin;
    return ret;
}

void DataArrayHDF5::expansionOrigin(double expansion_origin) {
    group().setAttr("expansion_origin", expansion_origin);
    forceUpdatedAt();
}

void DataArrayHDF5::expansionOrigin(const none_t t) {
    if(group().hasAttr("expansionOrigin")) {
        group().removeAttr("expansionOrigin");
    }
    forceUpdatedAt();
}

// TODO use defaults
vector<double> DataArrayHDF5::polynomCoefficients()const{
    vector<double> polynom_coefficients;

    if (group().hasData("polynom_coefficients")) {
        DataSet ds = group().openData("polynom_coefficients");
        ds.read(polynom_coefficients, true);
    }

    return polynom_coefficients;
}

void DataArrayHDF5::polynomCoefficients(vector<double> &coefficients) {
    DataSet ds;
    if (group().hasData("polynom_coefficients")) {
        ds = group().openData("polynom_coefficients");
        ds.setExtent({coefficients.size()});
    } else {
        ds = DataSet::create(group().h5Group(), "polynom_coefficients", coefficients);
    }
    ds.write(coefficients);
    forceUpdatedAt();
}

void DataArrayHDF5::polynomCoefficients(const none_t t) {
    if(group().hasAttr("polynom_coefficients")) {
        group().removeAttr("polynom_coefficients");
    }
    forceUpdatedAt();
}

//--------------------------------------------------
// Methods concerning dimensions
//--------------------------------------------------

size_t DataArrayHDF5::dimensionCount() const {
    return dimension_group.objectCount();
}

Dimension DataArrayHDF5::getDimension(size_t id) const {
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        Group dim_group = dimension_group.openGroup(str_id, false);
        string dim_type_name;
        dim_group.getAttr("dimension_type", dim_type_name);
        DimensionType dim_type = dimensionTypeFromStr(dim_type_name);

        Dimension dim;

        if (dim_type == DimensionType::Set ) {
            auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
            dim = SetDimension(tmp);
        } else if (dim_type == DimensionType::Range) {
            std::vector<double> ticks;
            dim_group.getData("ticks", ticks);
            auto tmp = make_shared<RangeDimensionHDF5>(dim_group, id, ticks);
            dim = RangeDimension(tmp);
        } else if (dim_type == DimensionType::Sample) {
            double samplingInterval;
            dim_group.getAttr("sampling_interval", samplingInterval);
            auto tmp = make_shared<SampledDimensionHDF5>(dim_group, id, samplingInterval);
            dim = SampledDimension(tmp);
        } else {
            throw runtime_error("Invalid dimension type");
        }

        return dim;
    } else {
        return Dimension();
    }
}

template<DimensionType dtype, typename T>
Dimension DataArrayHDF5::_createDimension(size_t id, T var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    if (dtype == DimensionType::Range || dtype == DimensionType::Sample) {
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimensionHDF5,
                                          SampledDimensionHDF5>::type
                                          dimTypeHDF5;
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimension,
                                          SampledDimension>::type
                                          dimType;
        auto tmp = make_shared<dimTypeHDF5>(dim_group, id, var);
        dim = dimType(tmp);
    } else {
        throw runtime_error("Invalid dimension type");
    }

    return dim;
}

template<>
Dimension DataArrayHDF5::_createDimension<DimensionType::Set, none_t>(size_t id, none_t var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    // no dim-type check needed since method only called if type=DimensionType::Set
    auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
    dim = SetDimension(tmp);

    return dim;
}

Dimension DataArrayHDF5::createSetDimension(size_t id) {
    return _createDimension<DimensionType::Set>(id);
}

Dimension DataArrayHDF5::createRangeDimension(size_t id, std::vector<double> ticks) {
    return _createDimension<DimensionType::Range>(id, ticks);
}

Dimension DataArrayHDF5::createSampledDimension(size_t id, double samplingInterval) {
    return _createDimension<DimensionType::Sample>(id, samplingInterval);
}

bool DataArrayHDF5::deleteDimension(size_t id) {
    bool deleted = false;
    size_t dim_count = dimensionCount();
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
        deleted = true;
    }

    if (deleted && id < dim_count) {
        for (size_t old_id = id + 1; old_id <= dim_count; old_id++) {
            string str_old_id = util::numToStr(old_id);
            string str_new_id = util::numToStr(old_id - 1);
            dimension_group.renameGroup(str_old_id, str_new_id);
        }
    }

    return deleted;
}

//--------------------------------------------------
// Other methods and functions
//--------------------------------------------------

void DataArrayHDF5::swap(DataArrayHDF5 &other) {
    using std::swap;

    EntityWithSourcesHDF5::swap(other);
    swap(dimension_group, other.dimension_group);
}

DataArrayHDF5& DataArrayHDF5::operator=(const DataArrayHDF5 &other) {
    if (*this != other) {
        DataArrayHDF5 tmp(other);
        swap(tmp);
    }

    return *this;
}

DataArrayHDF5::~DataArrayHDF5() {}

void DataArrayHDF5::createData(DataType dtype, const NDSize &size)
{
    if (group().hasData("data")) {
        throw new std::runtime_error("DataArray alread exists"); //TODO: FIXME, better exception
    }

    DataSet::create(group().h5Group(), "data", dtype, size);
    DataSet ds = group().openData("data");
}

bool DataArrayHDF5::hasData() const
{
    return group().hasData("data");
}

void DataArrayHDF5::write(DataType dtype, const void *data, const NDSize &count, const NDSize &offset)
{
    DataSet ds;

    if (!group().hasData("data")) {
        ds = DataSet::create(group().h5Group(), "data", dtype, count);
    } else {
        ds = group().openData("data");
    }

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.write(dtype, data, fileSel, memSel);
    } else {
        ds.write(dtype, count, data);
    }
}

void DataArrayHDF5::read(DataType dtype, void *data, const NDSize &count, const NDSize &offset) const
{
    if (!group().hasData("data")) {
        return;
    }

    DataSet ds = group().openData("data");

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.read(dtype, data, fileSel, memSel);
    } else {
        ds.read(dtype, count, data);
    }

}

NDSize DataArrayHDF5::dataExtent(void) const
{
    if (!group().hasData("data")) {
        return NDSize{};
    }

    DataSet ds = group().openData("data");
    return ds.size();
}

void DataArrayHDF5::dataExtent(const NDSize &extent)
{
    if (!group().hasData("data")) {
        throw runtime_error("Data field not found in DataArray!");
    }

    DataSet ds = group().openData("data");
    ds.setExtent(extent);
}

DataType DataArrayHDF5::dataType(void) const
{
    if (!group().hasData("data")) {
        //we could also throw an exception but I think returning
        //Nothing here is better (ck) - agreed (bm)
        return DataType::Nothing;
    }

    DataSet ds = group().openData("data");
    return ds.dataType();
}

} // namespace hdf5
} // namespace nix
<commit_msg>[h5] DataArray: fix label getter to correctly return none<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/util/util.hpp>

#include <nix/hdf5/DataArrayHDF5.hpp>
#include <nix/hdf5/DataSet.hpp>
#include <nix/hdf5/DimensionHDF5.hpp>

using namespace std;

namespace nix {
namespace hdf5 {

DataArrayHDF5::DataArrayHDF5(const DataArrayHDF5 &data_array)
    : EntityWithSourcesHDF5(data_array.file(), data_array.block(), data_array.group(), data_array.id(), data_array.type(), data_array.name()),
      dimension_group(data_array.dimension_group)
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name)
    : DataArrayHDF5(file, block, group, id, type, name, util::getTime())
{
}

DataArrayHDF5::DataArrayHDF5(const File &file, const Block &block, const Group &group,
                             const string &id, const string &type, const string &name, time_t time)
    : EntityWithSourcesHDF5(file, block, group, id, type, name, time)
{
    dimension_group = this->group().openGroup("dimensions", true);
}

//--------------------------------------------------
// Element getters and setters
//--------------------------------------------------

boost::optional<std::string> DataArrayHDF5::label() const {
    boost::optional<std::string> ret;
    string value;
    bool have_attr = group().getAttr("label", value);

    if (have_attr) {
        ret = value;
    }

    return ret;
}

void DataArrayHDF5::label(const string &label) {
    if(label.empty()) {
        throw EmptyString("label");
    }
    else {
        group().setAttr("label", label);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::label(const none_t t) {
    if(group().hasAttr("label")) {
        group().removeAttr("label");
    }
    forceUpdatedAt();
}

boost::optional<std::string> DataArrayHDF5::unit() const {
    boost::optional<std::string> ret;
    string value;
    group().getAttr("unit", value);
    ret = value;
    return ret;
}

void DataArrayHDF5::unit(const string &unit) {
    if(unit.empty()) {
        throw EmptyString("unit");
    }
    else {
        group().setAttr("unit", unit);
        forceUpdatedAt();
    }
}

void DataArrayHDF5::unit(const none_t t) {
    if(group().hasAttr("unit")) {
        group().removeAttr("unit");
    }
    forceUpdatedAt();
}

// TODO use defaults
boost::optional<double> DataArrayHDF5::expansionOrigin() const {
    boost::optional<double> ret;
    double expansion_origin;
    group().getAttr("expansion_origin", expansion_origin);
    ret = expansion_origin;
    return ret;
}

void DataArrayHDF5::expansionOrigin(double expansion_origin) {
    group().setAttr("expansion_origin", expansion_origin);
    forceUpdatedAt();
}

void DataArrayHDF5::expansionOrigin(const none_t t) {
    if(group().hasAttr("expansionOrigin")) {
        group().removeAttr("expansionOrigin");
    }
    forceUpdatedAt();
}

// TODO use defaults
vector<double> DataArrayHDF5::polynomCoefficients()const{
    vector<double> polynom_coefficients;

    if (group().hasData("polynom_coefficients")) {
        DataSet ds = group().openData("polynom_coefficients");
        ds.read(polynom_coefficients, true);
    }

    return polynom_coefficients;
}

void DataArrayHDF5::polynomCoefficients(vector<double> &coefficients) {
    DataSet ds;
    if (group().hasData("polynom_coefficients")) {
        ds = group().openData("polynom_coefficients");
        ds.setExtent({coefficients.size()});
    } else {
        ds = DataSet::create(group().h5Group(), "polynom_coefficients", coefficients);
    }
    ds.write(coefficients);
    forceUpdatedAt();
}

void DataArrayHDF5::polynomCoefficients(const none_t t) {
    if(group().hasAttr("polynom_coefficients")) {
        group().removeAttr("polynom_coefficients");
    }
    forceUpdatedAt();
}

//--------------------------------------------------
// Methods concerning dimensions
//--------------------------------------------------

size_t DataArrayHDF5::dimensionCount() const {
    return dimension_group.objectCount();
}

Dimension DataArrayHDF5::getDimension(size_t id) const {
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        Group dim_group = dimension_group.openGroup(str_id, false);
        string dim_type_name;
        dim_group.getAttr("dimension_type", dim_type_name);
        DimensionType dim_type = dimensionTypeFromStr(dim_type_name);

        Dimension dim;

        if (dim_type == DimensionType::Set ) {
            auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
            dim = SetDimension(tmp);
        } else if (dim_type == DimensionType::Range) {
            std::vector<double> ticks;
            dim_group.getData("ticks", ticks);
            auto tmp = make_shared<RangeDimensionHDF5>(dim_group, id, ticks);
            dim = RangeDimension(tmp);
        } else if (dim_type == DimensionType::Sample) {
            double samplingInterval;
            dim_group.getAttr("sampling_interval", samplingInterval);
            auto tmp = make_shared<SampledDimensionHDF5>(dim_group, id, samplingInterval);
            dim = SampledDimension(tmp);
        } else {
            throw runtime_error("Invalid dimension type");
        }

        return dim;
    } else {
        return Dimension();
    }
}

template<DimensionType dtype, typename T>
Dimension DataArrayHDF5::_createDimension(size_t id, T var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    if (dtype == DimensionType::Range || dtype == DimensionType::Sample) {
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimensionHDF5,
                                          SampledDimensionHDF5>::type
                                          dimTypeHDF5;
        typedef typename std::conditional<dtype == DimensionType::Range,
                                          RangeDimension,
                                          SampledDimension>::type
                                          dimType;
        auto tmp = make_shared<dimTypeHDF5>(dim_group, id, var);
        dim = dimType(tmp);
    } else {
        throw runtime_error("Invalid dimension type");
    }

    return dim;
}

template<>
Dimension DataArrayHDF5::_createDimension<DimensionType::Set, none_t>(size_t id, none_t var) {
    size_t dim_count = dimensionCount();

    if (id > (dim_count + 1) || id <= 0) { // dim_count+1 since index starts at 1
        runtime_error("Invalid dimension id: has to be 0 < id <= #(dimensions)+1");
    }

    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
    }

    Group dim_group = dimension_group.openGroup(str_id, true);
    Dimension dim;

    // no dim-type check needed since method only called if type=DimensionType::Set
    auto tmp = make_shared<SetDimensionHDF5>(dim_group, id);
    dim = SetDimension(tmp);

    return dim;
}

Dimension DataArrayHDF5::createSetDimension(size_t id) {
    return _createDimension<DimensionType::Set>(id);
}

Dimension DataArrayHDF5::createRangeDimension(size_t id, std::vector<double> ticks) {
    return _createDimension<DimensionType::Range>(id, ticks);
}

Dimension DataArrayHDF5::createSampledDimension(size_t id, double samplingInterval) {
    return _createDimension<DimensionType::Sample>(id, samplingInterval);
}

bool DataArrayHDF5::deleteDimension(size_t id) {
    bool deleted = false;
    size_t dim_count = dimensionCount();
    string str_id = util::numToStr(id);

    if (dimension_group.hasGroup(str_id)) {
        dimension_group.removeGroup(str_id);
        deleted = true;
    }

    if (deleted && id < dim_count) {
        for (size_t old_id = id + 1; old_id <= dim_count; old_id++) {
            string str_old_id = util::numToStr(old_id);
            string str_new_id = util::numToStr(old_id - 1);
            dimension_group.renameGroup(str_old_id, str_new_id);
        }
    }

    return deleted;
}

//--------------------------------------------------
// Other methods and functions
//--------------------------------------------------

void DataArrayHDF5::swap(DataArrayHDF5 &other) {
    using std::swap;

    EntityWithSourcesHDF5::swap(other);
    swap(dimension_group, other.dimension_group);
}

DataArrayHDF5& DataArrayHDF5::operator=(const DataArrayHDF5 &other) {
    if (*this != other) {
        DataArrayHDF5 tmp(other);
        swap(tmp);
    }

    return *this;
}

DataArrayHDF5::~DataArrayHDF5() {}

void DataArrayHDF5::createData(DataType dtype, const NDSize &size)
{
    if (group().hasData("data")) {
        throw new std::runtime_error("DataArray alread exists"); //TODO: FIXME, better exception
    }

    DataSet::create(group().h5Group(), "data", dtype, size);
    DataSet ds = group().openData("data");
}

bool DataArrayHDF5::hasData() const
{
    return group().hasData("data");
}

void DataArrayHDF5::write(DataType dtype, const void *data, const NDSize &count, const NDSize &offset)
{
    DataSet ds;

    if (!group().hasData("data")) {
        ds = DataSet::create(group().h5Group(), "data", dtype, count);
    } else {
        ds = group().openData("data");
    }

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.write(dtype, data, fileSel, memSel);
    } else {
        ds.write(dtype, count, data);
    }
}

void DataArrayHDF5::read(DataType dtype, void *data, const NDSize &count, const NDSize &offset) const
{
    if (!group().hasData("data")) {
        return;
    }

    DataSet ds = group().openData("data");

    if (offset.size()) {
        Selection fileSel = ds.createSelection();
        fileSel.select(count, offset);
        Selection memSel(DataSpace::create(count, false));

        ds.read(dtype, data, fileSel, memSel);
    } else {
        ds.read(dtype, count, data);
    }

}

NDSize DataArrayHDF5::dataExtent(void) const
{
    if (!group().hasData("data")) {
        return NDSize{};
    }

    DataSet ds = group().openData("data");
    return ds.size();
}

void DataArrayHDF5::dataExtent(const NDSize &extent)
{
    if (!group().hasData("data")) {
        throw runtime_error("Data field not found in DataArray!");
    }

    DataSet ds = group().openData("data");
    ds.setExtent(extent);
}

DataType DataArrayHDF5::dataType(void) const
{
    if (!group().hasData("data")) {
        //we could also throw an exception but I think returning
        //Nothing here is better (ck) - agreed (bm)
        return DataType::Nothing;
    }

    DataSet ds = group().openData("data");
    return ds.dataType();
}

} // namespace hdf5
} // namespace nix
<|endoftext|>


<commit_before>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file rao_blackwell_coordinate_particle_filter.hpp
 * \date 05/25/2014
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 */

#ifndef FAST_FILTERING_FILTERS_STOCHASTIC_RAO_BLACKWELL_COORDINATE_PARTICLE_FILTER_HPP
#define FAST_FILTERING_FILTERS_STOCHASTIC_RAO_BLACKWELL_COORDINATE_PARTICLE_FILTER_HPP

#include <vector>
#include <limits>
#include <string>
#include <algorithm>
#include <cmath>
#include <memory>

#include <Eigen/Core>

#include <fl/util/math.hpp>
#include <fl/util/traits.hpp>
#include <fl/util/profiling.hpp>
#include <fl/util/assertions.hpp>
#include <fl/util/discrete_distribution.hpp>

#include <fl/distribution/sum_of_deltas.hpp>
#include <fl/distribution/standard_gaussian.hpp>
#include <fl/distribution/interface/standard_gaussian_mapping.hpp>
#include <fl/model/process/process_model_interface.hpp>

#include <ff/models/observation_models/interfaces/rao_blackwell_observation_model.hpp>

namespace fl
{

// Forward declarations
template <
    typename ProcessModel,
    typename ObservationModel
> class RaoBlackwellCoordinateParticleFilter;

/**
 * RaoBlackwellCoordinateParticleFilter Traits
 */
template <
    typename ProcessModel,
    typename ObservationModel
>
struct Traits<
           RaoBlackwellCoordinateParticleFilter<ProcessModel, ObservationModel>
       >
{
    typedef RaoBlackwellCoordinateParticleFilter<
                ProcessModel,
                ObservationModel
            > Filter;

    /*
     * Required concept (interface) types
     *
     * - Ptr
     * - State
     * - Input
     * - Observation
     * - StateDistribution
     */
    typedef std::shared_ptr<Filter> Ptr;
    typedef typename Traits<ProcessModel>::State State;
    typedef typename Traits<ProcessModel>::Input Input;
    typedef typename Traits<ProcessModel>::Noise Noise;
    typedef typename ObservationModel::Observation Observation; //!< \todo traits missing

    /**
     * Represents the underlying distribution of the estimated state.
     */
    typedef SumOfDeltas<State> StateDistribution;

    /** \cond INTERNAL */
    typedef typename StateDistribution::Scalar Scalar;
    /** \endcond */
};

/**
 *
 *
 * \todo MISSING DOC. MISSING UTESTS
 */
template<typename ProcessModel, typename ObservationModel>
class RaoBlackwellCoordinateParticleFilter
{
protected:
    /** \cond INTERNAL */
    typedef RaoBlackwellCoordinateParticleFilter<
                ProcessModel,
                ObservationModel
            > This;
    /** \endcond */

public:
    /* public concept interface types */
    typedef typename Traits<This>::Scalar            Scalar;
    typedef typename Traits<This>::State             State;
    typedef typename Traits<This>::Input             Input;
    typedef typename Traits<This>::Noise             Noise;
    typedef typename Traits<This>::Observation       Observation;
    typedef typename Traits<This>::StateDistribution StateDistribution;

public:
    /**
     * Creates a RaoBlackwellCoordinateParticleFilter
     *
     * \param process_model         Process model instance
     * \param observation_model     Obsrv model instance
     * \param sampling_blocks
     * \param max_kl_divergence
     */
    RaoBlackwellCoordinateParticleFilter(
            const std::shared_ptr<ProcessModel> process_model,
            const std::shared_ptr<ObservationModel>  observation_model,
            const std::vector<std::vector<size_t>>& sampling_blocks,
            const Scalar& max_kl_divergence = 0)
        : observation_model_(observation_model),
          process_model_(process_model),
          max_kl_divergence_(max_kl_divergence)
    {
        static_assert_base(
            ProcessModel,
            ProcessModelInterface<State, Noise, Input>);

        static_assert_base(
            ProcessModel,
            StandardGaussianMapping<State, Noise>);

        static_assert_base(
            ObservationModel,
            RaoBlackwellObservationModel<State, Observation>);

        SamplingBlocks(sampling_blocks);
    }

    /**
     * \brief Overridable default constructor
     */
    virtual ~RaoBlackwellCoordinateParticleFilter() { }

public:
    /**
     * \param observation
     * \param delta_time
     * \param input
     */
    void Filter(const Observation&  observation,
                const Scalar&       delta_time,
                const Input&        input)
    {
        observation_model_->SetObservation(observation, delta_time);

        loglikes_ = std::vector<Scalar>(samples_.size(), 0);
        noises_ = std::vector<Noise>(samples_.size(), Noise::Zero(process_model_->noise_dimension()));
        next_samples_ = samples_;

        for(size_t block_index = 0; block_index < sampling_blocks_.size(); block_index++)
        {
            for(size_t particle_index = 0; particle_index < samples_.size(); particle_index++)
            {
                for(size_t i = 0; i < sampling_blocks_[block_index].size(); i++)
                    noises_[particle_index](sampling_blocks_[block_index][i]) = unit_gaussian_.sample();

                next_samples_[particle_index] =
                        process_model_->predict_state(delta_time,
                                                      samples_[particle_index],
                                                      noises_[particle_index],
                                                      input);
            }

            bool update_occlusions = (block_index == sampling_blocks_.size()-1);
            std::vector<Scalar> new_loglikes = observation_model_->Loglikes(next_samples_,
                                                                           indices_,
                                                                           update_occlusions);
            std::vector<Scalar> delta_loglikes(new_loglikes.size());
            for(size_t i = 0; i < delta_loglikes.size(); i++)
                delta_loglikes[i] = new_loglikes[i] - loglikes_[i];
            loglikes_ = new_loglikes;
            UpdateWeights(delta_loglikes);
        }

        samples_ = next_samples_;
        state_distribution_.SetDeltas(samples_); // not sure whether this is the right place
    }

    /**
     * \param sample_count
     */
    void Resample(const size_t& sample_count)
    {
        std::vector<State> samples(sample_count);
        std::vector<size_t> indices(sample_count);
        std::vector<Noise> noises(sample_count);
        std::vector<State> next_samples(sample_count);
        std::vector<Scalar> loglikes(sample_count);

        hf::DiscreteDistribution sampler(log_weights_);

        for(size_t i = 0; i < sample_count; i++)
        {
            size_t index = sampler.sample();

            samples[i]      = samples_[index];
            indices[i]      = indices_[index];
            noises[i]       = noises_[index];
            next_samples[i] = next_samples_[index];
            loglikes[i]     = loglikes_[index];
        }
        samples_        = samples;
        indices_        = indices;
        noises_         = noises;
        next_samples_   = next_samples;
        loglikes_       = loglikes;

        log_weights_        = std::vector<Scalar>(samples_.size(), 0.);

        state_distribution_.SetDeltas(samples_); // not sure whether this is the right place
    }

private:
    // O(6n + nlog(n)) might be reducible to O(4n)
    void UpdateWeights(std::vector<Scalar> log_weight_diffs)
    {
        for(size_t i = 0; i < log_weight_diffs.size(); i++)
            log_weights_[i] += log_weight_diffs[i];

        std::vector<Scalar> weights = log_weights_;
        // descendant sorting
        std::sort(weights.begin(), weights.end(), std::greater<Scalar>());

        for(int i = weights.size() - 1; i >= 0; i--)
            weights[i] -= weights[0];

        std::for_each(weights.begin(), weights.end(), [](Scalar& w){ w = std::exp(w); });

        weights = fl::normalize(weights, Scalar(1));

        // compute KL divergence to uniform distribution KL(p|u)
        Scalar kl_divergence = std::log(Scalar(weights.size()));
        for(size_t i = 0; i < weights.size(); i++)
        {
            Scalar information = - std::log(weights[i]) * weights[i];
            if(!std::isfinite(information))
                information = 0; // the limit for weight -> 0 is equal to 0
            kl_divergence -= information;
        }

        if(kl_divergence > max_kl_divergence_)
            Resample(samples_.size());
    }

public:
    // set
    void Samples(const std::vector<State >& samples)
    {
        samples_ = samples;
        indices_ = std::vector<size_t>(samples_.size(), 0); observation_model_->Reset();
        log_weights_ = std::vector<Scalar>(samples_.size(), 0);
    }
    void SamplingBlocks(const std::vector<std::vector<size_t>>& sampling_blocks)
    {
        sampling_blocks_ = sampling_blocks;

        // make sure sizes are consistent
        size_t dimension = 0;
        for(size_t i = 0; i < sampling_blocks_.size(); i++)
            for(size_t j = 0; j < sampling_blocks_[i].size(); j++)
                dimension++;

        if(dimension != process_model_->standard_variate_dimension())
        {
            std::cout << "the dimension of the sampling blocks is " << dimension
                      << " while the dimension of the noise is "
                      << process_model_->standard_variate_dimension() << std::endl;
            exit(-1);
        }
    }

    // get
    const std::vector<State>& Samples() const
    {
        return samples_;
    }

    StateDistribution& state_distribution()
    {
        return state_distribution_;
    }

private:
    // internal state TODO: THIS COULD BE MADE MORE COMPACT!!
    StateDistribution state_distribution_;

    std::vector<State > samples_;
    std::vector<size_t> indices_;
    std::vector<Scalar>  log_weights_;
    std::vector<Noise> noises_;
    std::vector<State> next_samples_;
    std::vector<Scalar> loglikes_;

    std::shared_ptr<ObservationModel> observation_model_;
    std::shared_ptr<ProcessModel> process_model_;

    // parameters
    std::vector<std::vector<size_t>> sampling_blocks_;
    Scalar max_kl_divergence_;

    // distribution for sampling
    //Gaussian<Eigen::Matrix<Scalar,1,1>> unit_gaussian_;
    StandardGaussian<Scalar> unit_gaussian_;
};

}

#endif
<commit_msg>removed Gaussian<Eigen::Matrix<Scalar,1,1>> comment<commit_after>/*
 * This is part of the FL library, a C++ Bayesian filtering library
 * (https://github.com/filtering-library)
 *
 * Copyright (c) 2014 Jan Issac (jan.issac@gmail.com)
 * Copyright (c) 2014 Manuel Wuthrich (manuel.wuthrich@gmail.com)
 *
 * Max-Planck Institute for Intelligent Systems, AMD Lab
 * University of Southern California, CLMC Lab
 *
 * This Source Code Form is subject to the terms of the MIT License (MIT).
 * A copy of the license can be found in the LICENSE file distributed with this
 * source code.
 */

/**
 * \file rao_blackwell_coordinate_particle_filter.hpp
 * \date 05/25/2014
 * \author Manuel Wuthrich (manuel.wuthrich@gmail.com)
 */

#ifndef FAST_FILTERING_FILTERS_STOCHASTIC_RAO_BLACKWELL_COORDINATE_PARTICLE_FILTER_HPP
#define FAST_FILTERING_FILTERS_STOCHASTIC_RAO_BLACKWELL_COORDINATE_PARTICLE_FILTER_HPP

#include <vector>
#include <limits>
#include <string>
#include <algorithm>
#include <cmath>
#include <memory>

#include <Eigen/Core>

#include <fl/util/math.hpp>
#include <fl/util/traits.hpp>
#include <fl/util/profiling.hpp>
#include <fl/util/assertions.hpp>
#include <fl/util/discrete_distribution.hpp>

#include <fl/distribution/sum_of_deltas.hpp>
#include <fl/distribution/standard_gaussian.hpp>
#include <fl/distribution/interface/standard_gaussian_mapping.hpp>
#include <fl/model/process/process_model_interface.hpp>

#include <ff/models/observation_models/interfaces/rao_blackwell_observation_model.hpp>

namespace fl
{

// Forward declarations
template <
    typename ProcessModel,
    typename ObservationModel
> class RaoBlackwellCoordinateParticleFilter;

/**
 * RaoBlackwellCoordinateParticleFilter Traits
 */
template <
    typename ProcessModel,
    typename ObservationModel
>
struct Traits<
           RaoBlackwellCoordinateParticleFilter<ProcessModel, ObservationModel>
       >
{
    typedef RaoBlackwellCoordinateParticleFilter<
                ProcessModel,
                ObservationModel
            > Filter;

    /*
     * Required concept (interface) types
     *
     * - Ptr
     * - State
     * - Input
     * - Observation
     * - StateDistribution
     */
    typedef std::shared_ptr<Filter> Ptr;
    typedef typename Traits<ProcessModel>::State State;
    typedef typename Traits<ProcessModel>::Input Input;
    typedef typename Traits<ProcessModel>::Noise Noise;
    typedef typename ObservationModel::Observation Observation; //!< \todo traits missing

    /**
     * Represents the underlying distribution of the estimated state.
     */
    typedef SumOfDeltas<State> StateDistribution;

    /** \cond INTERNAL */
    typedef typename StateDistribution::Scalar Scalar;
    /** \endcond */
};

/**
 *
 *
 * \todo MISSING DOC. MISSING UTESTS
 */
template<typename ProcessModel, typename ObservationModel>
class RaoBlackwellCoordinateParticleFilter
{
protected:
    /** \cond INTERNAL */
    typedef RaoBlackwellCoordinateParticleFilter<
                ProcessModel,
                ObservationModel
            > This;
    /** \endcond */

public:
    /* public concept interface types */
    typedef typename Traits<This>::Scalar            Scalar;
    typedef typename Traits<This>::State             State;
    typedef typename Traits<This>::Input             Input;
    typedef typename Traits<This>::Noise             Noise;
    typedef typename Traits<This>::Observation       Observation;
    typedef typename Traits<This>::StateDistribution StateDistribution;

public:
    /**
     * Creates a RaoBlackwellCoordinateParticleFilter
     *
     * \param process_model         Process model instance
     * \param observation_model     Obsrv model instance
     * \param sampling_blocks
     * \param max_kl_divergence
     */
    RaoBlackwellCoordinateParticleFilter(
            const std::shared_ptr<ProcessModel> process_model,
            const std::shared_ptr<ObservationModel>  observation_model,
            const std::vector<std::vector<size_t>>& sampling_blocks,
            const Scalar& max_kl_divergence = 0)
        : observation_model_(observation_model),
          process_model_(process_model),
          max_kl_divergence_(max_kl_divergence)
    {
        static_assert_base(
            ProcessModel,
            ProcessModelInterface<State, Noise, Input>);

        static_assert_base(
            ProcessModel,
            StandardGaussianMapping<State, Noise>);

        static_assert_base(
            ObservationModel,
            RaoBlackwellObservationModel<State, Observation>);

        SamplingBlocks(sampling_blocks);
    }

    /**
     * \brief Overridable default constructor
     */
    virtual ~RaoBlackwellCoordinateParticleFilter() { }

public:
    /**
     * \param observation
     * \param delta_time
     * \param input
     */
    void Filter(const Observation&  observation,
                const Scalar&       delta_time,
                const Input&        input)
    {
        observation_model_->SetObservation(observation, delta_time);

        loglikes_ = std::vector<Scalar>(samples_.size(), 0);
        noises_ = std::vector<Noise>(samples_.size(), Noise::Zero(process_model_->noise_dimension()));
        next_samples_ = samples_;

        for(size_t block_index = 0; block_index < sampling_blocks_.size(); block_index++)
        {
            for(size_t particle_index = 0; particle_index < samples_.size(); particle_index++)
            {
                for(size_t i = 0; i < sampling_blocks_[block_index].size(); i++)
                    noises_[particle_index](sampling_blocks_[block_index][i]) = unit_gaussian_.sample();

                next_samples_[particle_index] =
                        process_model_->predict_state(delta_time,
                                                      samples_[particle_index],
                                                      noises_[particle_index],
                                                      input);
            }

            bool update_occlusions = (block_index == sampling_blocks_.size()-1);
            std::vector<Scalar> new_loglikes = observation_model_->Loglikes(next_samples_,
                                                                           indices_,
                                                                           update_occlusions);
            std::vector<Scalar> delta_loglikes(new_loglikes.size());
            for(size_t i = 0; i < delta_loglikes.size(); i++)
                delta_loglikes[i] = new_loglikes[i] - loglikes_[i];
            loglikes_ = new_loglikes;
            UpdateWeights(delta_loglikes);
        }

        samples_ = next_samples_;
        state_distribution_.SetDeltas(samples_); // not sure whether this is the right place
    }

    /**
     * \param sample_count
     */
    void Resample(const size_t& sample_count)
    {
        std::vector<State> samples(sample_count);
        std::vector<size_t> indices(sample_count);
        std::vector<Noise> noises(sample_count);
        std::vector<State> next_samples(sample_count);
        std::vector<Scalar> loglikes(sample_count);

        hf::DiscreteDistribution sampler(log_weights_);

        for(size_t i = 0; i < sample_count; i++)
        {
            size_t index = sampler.sample();

            samples[i]      = samples_[index];
            indices[i]      = indices_[index];
            noises[i]       = noises_[index];
            next_samples[i] = next_samples_[index];
            loglikes[i]     = loglikes_[index];
        }
        samples_        = samples;
        indices_        = indices;
        noises_         = noises;
        next_samples_   = next_samples;
        loglikes_       = loglikes;

        log_weights_        = std::vector<Scalar>(samples_.size(), 0.);

        state_distribution_.SetDeltas(samples_); // not sure whether this is the right place
    }

private:
    // O(6n + nlog(n)) might be reducible to O(4n)
    void UpdateWeights(std::vector<Scalar> log_weight_diffs)
    {
        for(size_t i = 0; i < log_weight_diffs.size(); i++)
            log_weights_[i] += log_weight_diffs[i];

        std::vector<Scalar> weights = log_weights_;
        // descendant sorting
        std::sort(weights.begin(), weights.end(), std::greater<Scalar>());

        for(int i = weights.size() - 1; i >= 0; i--)
            weights[i] -= weights[0];

        std::for_each(weights.begin(), weights.end(), [](Scalar& w){ w = std::exp(w); });

        weights = fl::normalize(weights, Scalar(1));

        // compute KL divergence to uniform distribution KL(p|u)
        Scalar kl_divergence = std::log(Scalar(weights.size()));
        for(size_t i = 0; i < weights.size(); i++)
        {
            Scalar information = - std::log(weights[i]) * weights[i];
            if(!std::isfinite(information))
                information = 0; // the limit for weight -> 0 is equal to 0
            kl_divergence -= information;
        }

        if(kl_divergence > max_kl_divergence_)
            Resample(samples_.size());
    }

public:
    // set
    void Samples(const std::vector<State >& samples)
    {
        samples_ = samples;
        indices_ = std::vector<size_t>(samples_.size(), 0); observation_model_->Reset();
        log_weights_ = std::vector<Scalar>(samples_.size(), 0);
    }
    void SamplingBlocks(const std::vector<std::vector<size_t>>& sampling_blocks)
    {
        sampling_blocks_ = sampling_blocks;

        // make sure sizes are consistent
        size_t dimension = 0;
        for(size_t i = 0; i < sampling_blocks_.size(); i++)
            for(size_t j = 0; j < sampling_blocks_[i].size(); j++)
                dimension++;

        if(dimension != process_model_->standard_variate_dimension())
        {
            std::cout << "the dimension of the sampling blocks is " << dimension
                      << " while the dimension of the noise is "
                      << process_model_->standard_variate_dimension() << std::endl;
            exit(-1);
        }
    }

    // get
    const std::vector<State>& Samples() const
    {
        return samples_;
    }

    StateDistribution& state_distribution()
    {
        return state_distribution_;
    }

private:
    // internal state TODO: THIS COULD BE MADE MORE COMPACT!!
    StateDistribution state_distribution_;

    std::vector<State > samples_;
    std::vector<size_t> indices_;
    std::vector<Scalar>  log_weights_;
    std::vector<Noise> noises_;
    std::vector<State> next_samples_;
    std::vector<Scalar> loglikes_;

    std::shared_ptr<ObservationModel> observation_model_;
    std::shared_ptr<ProcessModel> process_model_;

    // parameters
    std::vector<std::vector<size_t>> sampling_blocks_;
    Scalar max_kl_divergence_;

    // distribution for sampling
    StandardGaussian<Scalar> unit_gaussian_;
};

}

#endif
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>

#include "dbstore.h"

using namespace v8;

DbStore::DbStore() : _db(0), _env(0), _txn(0) {};
DbStore::~DbStore() {
  fprintf(stderr, "~DbStore %p\n", this);
  close();
};

void DbStore::Init(Handle<Object> target) {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("DbStore"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  // Prototype
  tpl->PrototypeTemplate()->Set(String::NewSymbol("open"),
      FunctionTemplate::New(Open)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("close"),
      FunctionTemplate::New(Close)->GetFunction());

  tpl->PrototypeTemplate()->Set(String::NewSymbol("_put"),
      FunctionTemplate::New(Put)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("_get"),
      FunctionTemplate::New(Get)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("del"),
      FunctionTemplate::New(Del)->GetFunction());

  tpl->PrototypeTemplate()->Set(String::NewSymbol("sync"),
      FunctionTemplate::New(Sync)->GetFunction());

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("DbStore"), constructor);
}

int
DbStore::open(char const *fname, char const *db,
	      DBTYPE type, u_int32_t flags, int mode)
{
  int ret = db_create(&_db, NULL, 0);
  if (ret) return ret;

  fprintf(stderr, "%p: open %p\n", this, _db);
  return _db->open(_db, NULL, fname, db, type, flags, mode);
}

int
DbStore::close()
{
  int ret = 0;
  if (_db && _db->pgsize) {
    fprintf(stderr, "%p: close %p\n", this, _db);
    ret = _db->close(_db, 0);
    _db = NULL;
  }
  return ret;
}

static void
dbt_set(DBT *dbt, void *data, u_int32_t size, u_int32_t flags = DB_DBT_USERMEM)
{
  memset(dbt, 0, sizeof(*dbt));
  dbt->data = data;
  dbt->size = size;
  dbt->flags = flags;
}

int
DbStore::put(DBT *key, DBT *data, u_int32_t flags)
{
  return _db->put(_db, 0, key, data, flags);
}

int
DbStore::get(DBT *key, DBT *data, u_int32_t flags)
{
  return _db->get(_db, 0, key, data, flags);
}

int
DbStore::del(DBT *key, u_int32_t flags)
{
  return _db->del(_db, 0, key, flags);
}

int
DbStore::sync(u_int32_t flags)
{
  return 0;
}

Handle<Value> DbStore::New(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = new DbStore();
  obj->Wrap(args.This());

  return args.This();
}

struct WorkBaton {
  uv_work_t *req;
  DbStore *store;

  char *str_arg;
  Persistent<Function> callback;
  Persistent<Object> data;

  char const *call;
  DBT retbuf;
  int ret;

  WorkBaton(uv_work_t *_r, DbStore *_s);
  ~WorkBaton();
};

WorkBaton::WorkBaton(uv_work_t *_r, DbStore *_s) : req(_r), store(_s), str_arg(0) {
  //fprintf(stderr, "new WorkBaton %p\n", this);
}
WorkBaton::~WorkBaton() {
  //fprintf(stderr, "~WorkBaton %p\n", this);
  delete req;

  if (str_arg) free(str_arg);
  callback.Dispose();
  data.Dispose();
  // Ignore retbuf since it will be freed by Buffer
}

static void
After(WorkBaton *baton, Handle<Value> *argv, int argc)
{
  if (baton->ret) {
    fprintf(stderr, "%s %s error %d\n", baton->call, baton->str_arg, baton->ret);
    argv[0] = node::UVException(0, baton->call, db_strerror(baton->ret));
  } else {
    argv[0] = Local<Value>::New(Null());
  }

  // surround in a try/catch for safety
  TryCatch try_catch;

  // execute the callback function
  //fprintf(stderr, "%p.%s Calling cb\n", baton->store, call);
  baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);

  if (try_catch.HasCaught())
    node::FatalException(try_catch);

  delete baton;
}

void
OpenWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;
  baton->call = "open";
  baton->ret = store->open(baton->str_arg, NULL, DB_BTREE, DB_CREATE|DB_THREAD, 0);
}

void
OpenAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[1];

  After(baton, argv, 1);
}

Handle<Value> DbStore::Open(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args[0]->IsString()) {
    ThrowException(Exception::TypeError(String::New("First argument must be String")));
    return scope.Close(Undefined());
  }

  if (! args[1]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Second argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  String::Utf8Value fname(args[0]);
  baton->str_arg = strdup(*fname);
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

  uv_queue_work(uv_default_loop(), req, OpenWork, OpenAfter);

  return args.This();
}

static void
CloseWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;
  baton->call = "close";
  baton->ret = store->close();
}

static void
CloseAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[1];
  After(baton, argv, 1);
}

Handle<Value> DbStore::Close(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args[0]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));

  uv_queue_work(uv_default_loop(), req, CloseWork, CloseAfter);

  return args.This();
}

static void
PutWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;

  DBT key_dbt;
  dbt_set(&key_dbt, baton->str_arg, strlen(baton->str_arg));

  DBT data_dbt;
  dbt_set(&data_dbt,
	  node::Buffer::Data(baton->data),
	  node::Buffer::Length(baton->data));

  baton->call = "put";
  baton->ret = store->put(&key_dbt, &data_dbt, 0);
  //fprintf(stderr, "put %s\n", baton->str_arg);
}

static void
PutAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[1];
  After(baton, argv, 1);
}

Handle<Value> DbStore::Put(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args.Length() > 0 && ! args[0]->IsString()) {
     ThrowException(Exception::TypeError(String::New("First argument must be a string")));
    return scope.Close(Undefined());
  }
  String::Utf8Value key(args[0]);

  if (! args.Length() > 1 && ! node::Buffer::HasInstance(args[1])) {
     ThrowException(Exception::TypeError(String::New("Second argument must be a Buffer")));
    return scope.Close(Undefined());
  }
  Persistent<Object> data = Persistent<Object>::New(Local<Object>::Cast(args[1]));

  if (! args.Length() > 2 && ! args[2]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->str_arg = strdup(*key);
  baton->data = data;
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  uv_queue_work(uv_default_loop(), req, PutWork, PutAfter);

  return args.This();
}

static void
GetWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;

  DBT key_dbt;
  dbt_set(&key_dbt, baton->str_arg, strlen(baton->str_arg));

  DBT *retbuf = &baton->retbuf;
  dbt_set(retbuf, 0, 0, DB_DBT_MALLOC);

  baton->call = "get";
  baton->ret = store->get(&key_dbt, retbuf, 0);
  //fprintf(stderr, "get %s => %p[%d]\n", baton->str_arg, key_dbt.data, key_dbt.size);
}

static void
free_buf(char *data, void *hint)
{
  //fprintf(stderr, "Free %p\n", data);
  free(data);
}

static void
GetAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[2];

  DBT *retbuf = &baton->retbuf;
  node::Buffer *buf = node::Buffer::New((char*)retbuf->data, retbuf->size,
					free_buf, NULL);
  argv[1] = buf->handle_;
  After(baton, argv, 2);
}

Handle<Value> DbStore::Get(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args.Length() > 0 && ! args[0]->IsString()) {
     ThrowException(Exception::TypeError(String::New("First argument must be a string")));
    return scope.Close(Undefined());
  }
  String::Utf8Value key(args[0]);

  if (! args.Length() > 1 && ! args[1]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->str_arg = strdup(*key);
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

  uv_queue_work(uv_default_loop(), req, GetWork, GetAfter);

  return args.This();
}

static void
DelWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;

  DBT key_dbt;
  dbt_set(&key_dbt, baton->str_arg, strlen(baton->str_arg));

  //fprintf(stderr, "del %s\n", baton->str_arg);
  baton->call = "del";
  baton->ret = store->del(&key_dbt, 0);
}

Handle<Value> DbStore::Del(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args.Length() > 0 && ! args[0]->IsString()) {
     ThrowException(Exception::TypeError(String::New("First argument must be a string")));
    return scope.Close(Undefined());
  }
  String::Utf8Value key(args[0]);

  if (! args.Length() > 1 && ! args[1]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->str_arg = strdup(*key);
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

  uv_queue_work(uv_default_loop(), req, DelWork, PutAfter); // Yes, use the same.

  return args.This();
}

Handle<Value> DbStore::Sync(const Arguments& args) {
  HandleScope scope;

  //DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  return scope.Close(Number::New(0));
}

<commit_msg>Remove extraneous debug output<commit_after>#include <node.h>
#include <node_buffer.h>

#include "dbstore.h"

using namespace v8;

DbStore::DbStore() : _db(0), _env(0), _txn(0) {};
DbStore::~DbStore() {
  fprintf(stderr, "~DbStore %p\n", this);
  close();
};

void DbStore::Init(Handle<Object> target) {
  // Prepare constructor template
  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
  tpl->SetClassName(String::NewSymbol("DbStore"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  // Prototype
  tpl->PrototypeTemplate()->Set(String::NewSymbol("open"),
      FunctionTemplate::New(Open)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("close"),
      FunctionTemplate::New(Close)->GetFunction());

  tpl->PrototypeTemplate()->Set(String::NewSymbol("_put"),
      FunctionTemplate::New(Put)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("_get"),
      FunctionTemplate::New(Get)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("del"),
      FunctionTemplate::New(Del)->GetFunction());

  tpl->PrototypeTemplate()->Set(String::NewSymbol("sync"),
      FunctionTemplate::New(Sync)->GetFunction());

  Persistent<Function> constructor = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("DbStore"), constructor);
}

int
DbStore::open(char const *fname, char const *db,
	      DBTYPE type, u_int32_t flags, int mode)
{
  int ret = db_create(&_db, NULL, 0);
  if (ret) return ret;

  //fprintf(stderr, "%p: open %p\n", this, _db);
  return _db->open(_db, NULL, fname, db, type, flags, mode);
}

int
DbStore::close()
{
  int ret = 0;
  if (_db && _db->pgsize) {
    //fprintf(stderr, "%p: close %p\n", this, _db);
    ret = _db->close(_db, 0);
    _db = NULL;
  }
  return ret;
}

static void
dbt_set(DBT *dbt, void *data, u_int32_t size, u_int32_t flags = DB_DBT_USERMEM)
{
  memset(dbt, 0, sizeof(*dbt));
  dbt->data = data;
  dbt->size = size;
  dbt->flags = flags;
}

int
DbStore::put(DBT *key, DBT *data, u_int32_t flags)
{
  return _db->put(_db, 0, key, data, flags);
}

int
DbStore::get(DBT *key, DBT *data, u_int32_t flags)
{
  return _db->get(_db, 0, key, data, flags);
}

int
DbStore::del(DBT *key, u_int32_t flags)
{
  return _db->del(_db, 0, key, flags);
}

int
DbStore::sync(u_int32_t flags)
{
  return 0;
}

Handle<Value> DbStore::New(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = new DbStore();
  obj->Wrap(args.This());

  return args.This();
}

struct WorkBaton {
  uv_work_t *req;
  DbStore *store;

  char *str_arg;
  Persistent<Function> callback;
  Persistent<Object> data;

  char const *call;
  DBT retbuf;
  int ret;

  WorkBaton(uv_work_t *_r, DbStore *_s);
  ~WorkBaton();
};

WorkBaton::WorkBaton(uv_work_t *_r, DbStore *_s) : req(_r), store(_s), str_arg(0) {
  //fprintf(stderr, "new WorkBaton %p\n", this);
}
WorkBaton::~WorkBaton() {
  //fprintf(stderr, "~WorkBaton %p\n", this);
  delete req;

  if (str_arg) free(str_arg);
  callback.Dispose();
  data.Dispose();
  // Ignore retbuf since it will be freed by Buffer
}

static void
After(WorkBaton *baton, Handle<Value> *argv, int argc)
{
  if (baton->ret) {
    //fprintf(stderr, "%s %s error %d\n", baton->call, baton->str_arg, baton->ret);
    argv[0] = node::UVException(0, baton->call, db_strerror(baton->ret));
  } else {
    argv[0] = Local<Value>::New(Null());
  }

  // surround in a try/catch for safety
  TryCatch try_catch;

  // execute the callback function
  //fprintf(stderr, "%p.%s Calling cb\n", baton->store, call);
  baton->callback->Call(Context::GetCurrent()->Global(), argc, argv);

  if (try_catch.HasCaught())
    node::FatalException(try_catch);

  delete baton;
}

void
OpenWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;
  baton->call = "open";
  baton->ret = store->open(baton->str_arg, NULL, DB_BTREE, DB_CREATE|DB_THREAD, 0);
}

void
OpenAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[1];

  After(baton, argv, 1);
}

Handle<Value> DbStore::Open(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args[0]->IsString()) {
    ThrowException(Exception::TypeError(String::New("First argument must be String")));
    return scope.Close(Undefined());
  }

  if (! args[1]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Second argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  String::Utf8Value fname(args[0]);
  baton->str_arg = strdup(*fname);
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

  uv_queue_work(uv_default_loop(), req, OpenWork, OpenAfter);

  return args.This();
}

static void
CloseWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;
  baton->call = "close";
  baton->ret = store->close();
}

static void
CloseAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[1];
  After(baton, argv, 1);
}

Handle<Value> DbStore::Close(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args[0]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[0]));

  uv_queue_work(uv_default_loop(), req, CloseWork, CloseAfter);

  return args.This();
}

static void
PutWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;

  DBT key_dbt;
  dbt_set(&key_dbt, baton->str_arg, strlen(baton->str_arg));

  DBT data_dbt;
  dbt_set(&data_dbt,
	  node::Buffer::Data(baton->data),
	  node::Buffer::Length(baton->data));

  baton->call = "put";
  baton->ret = store->put(&key_dbt, &data_dbt, 0);
  //fprintf(stderr, "put %s\n", baton->str_arg);
}

static void
PutAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[1];
  After(baton, argv, 1);
}

Handle<Value> DbStore::Put(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args.Length() > 0 && ! args[0]->IsString()) {
     ThrowException(Exception::TypeError(String::New("First argument must be a string")));
    return scope.Close(Undefined());
  }
  String::Utf8Value key(args[0]);

  if (! args.Length() > 1 && ! node::Buffer::HasInstance(args[1])) {
     ThrowException(Exception::TypeError(String::New("Second argument must be a Buffer")));
    return scope.Close(Undefined());
  }
  Persistent<Object> data = Persistent<Object>::New(Local<Object>::Cast(args[1]));

  if (! args.Length() > 2 && ! args[2]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->str_arg = strdup(*key);
  baton->data = data;
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));

  uv_queue_work(uv_default_loop(), req, PutWork, PutAfter);

  return args.This();
}

static void
GetWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;

  DBT key_dbt;
  dbt_set(&key_dbt, baton->str_arg, strlen(baton->str_arg));

  DBT *retbuf = &baton->retbuf;
  dbt_set(retbuf, 0, 0, DB_DBT_MALLOC);

  baton->call = "get";
  baton->ret = store->get(&key_dbt, retbuf, 0);
  //fprintf(stderr, "get %s => %p[%d]\n", baton->str_arg, key_dbt.data, key_dbt.size);
}

static void
free_buf(char *data, void *hint)
{
  //fprintf(stderr, "Free %p\n", data);
  free(data);
}

static void
GetAfter(uv_work_t *req) {
  HandleScope scope;

  // fetch our data structure
  WorkBaton *baton = (WorkBaton *)req->data;

  // create an arguments array for the callback
  Handle<Value> argv[2];

  DBT *retbuf = &baton->retbuf;
  node::Buffer *buf = node::Buffer::New((char*)retbuf->data, retbuf->size,
					free_buf, NULL);
  argv[1] = buf->handle_;
  After(baton, argv, 2);
}

Handle<Value> DbStore::Get(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args.Length() > 0 && ! args[0]->IsString()) {
     ThrowException(Exception::TypeError(String::New("First argument must be a string")));
    return scope.Close(Undefined());
  }
  String::Utf8Value key(args[0]);

  if (! args.Length() > 1 && ! args[1]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->str_arg = strdup(*key);
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

  uv_queue_work(uv_default_loop(), req, GetWork, GetAfter);

  return args.This();
}

static void
DelWork(uv_work_t *req) {
  WorkBaton *baton = (WorkBaton *) req->data;

  DbStore *store = baton->store;

  DBT key_dbt;
  dbt_set(&key_dbt, baton->str_arg, strlen(baton->str_arg));

  //fprintf(stderr, "del %s\n", baton->str_arg);
  baton->call = "del";
  baton->ret = store->del(&key_dbt, 0);
}

Handle<Value> DbStore::Del(const Arguments& args) {
  HandleScope scope;

  DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  if (! args.Length() > 0 && ! args[0]->IsString()) {
     ThrowException(Exception::TypeError(String::New("First argument must be a string")));
    return scope.Close(Undefined());
  }
  String::Utf8Value key(args[0]);

  if (! args.Length() > 1 && ! args[1]->IsFunction()) {
    ThrowException(Exception::TypeError(String::New("Argument must be callback function")));
    return scope.Close(Undefined());
  }

  // create an async work token
  uv_work_t *req = new uv_work_t;

  // assign our data structure that will be passed around
  WorkBaton *baton = new WorkBaton(req, obj);
  req->data = baton;

  baton->str_arg = strdup(*key);
  baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));

  uv_queue_work(uv_default_loop(), req, DelWork, PutAfter); // Yes, use the same.

  return args.This();
}

Handle<Value> DbStore::Sync(const Arguments& args) {
  HandleScope scope;

  //DbStore* obj = ObjectWrap::Unwrap<DbStore>(args.This());

  return scope.Close(Number::New(0));
}

<|endoftext|>


<commit_before>//
// ulib - a collection of useful classes
// Copyright (C) 2006,2007,2008,2012,2013,2016,2017 Michael Fink
//
/// \file Timer.hpp Timer class
//
#pragma once

#pragma warning(push)
#pragma warning(disable: 28159) // Consider using 'GetTickCount64' instead of 'GetTickCount'. Reason: GetTickCount overflows roughly every 49 days.  Code that does not take that into account can loop indefinitely.  GetTickCount64 operates on 64 bit values and does not have that problem

/// \brief Timer class
/// \details Has a precision of about 15 ms.
class Timer
{
public:
   /// ctor
   Timer()
      :m_isStarted(false),
      m_tickStart(0),
      m_totalElapsed(0)
   {
   }

   /// starts timer; timer must be stopped or reset
   void Start()
   {
      ATLASSERT(m_isStarted == false);
      m_tickStart = GetTickCount();
      m_isStarted = true;
   }

   /// stops timer; timer must be started
   void Stop()
   {
      ATLASSERT(m_isStarted == true);

      DWORD tickEnd = GetTickCount();
      m_totalElapsed += (tickEnd - m_tickStart);
      m_isStarted = false;
   }

   /// resets timer; timer must be stopped
   void Reset()
   {
      ATLASSERT(m_isStarted == false); // must be stopped when calling Reset()
      m_totalElapsed = 0;
   }

   /// restarts timer by resetting and starting again
   void Restart()
   {
      // can either be stopped or started when restarting
      if (m_isStarted)
         Stop();
      Reset();
      Start();
   }

   /// returns elapsed time since Start() was called, in seconds
   double Elapsed() const
   {
      if (!m_isStarted)
         return 0.0; // no time elapsed, since timer isn't started

      DWORD tickNow = GetTickCount();
      return 0.001 * (tickNow - m_tickStart);
   }

   /// returns total elapsed time in seconds
   double TotalElapsed() const
   {
      DWORD tickNow = GetTickCount();
      return 0.001 * (m_totalElapsed + (m_isStarted ? (tickNow - m_tickStart) : 0));
   }

   /// returns if timer is running
   bool IsStarted() const { return m_isStarted; }

private:
   /// indicates if timer is started
   bool m_isStarted;

   /// tick count of start
   DWORD m_tickStart;

   /// number of ticks already elapsed
   DWORD m_totalElapsed;
};

#pragma warning(pop)
<commit_msg>added comment about TraceOutputStopwatch<commit_after>//
// ulib - a collection of useful classes
// Copyright (C) 2006,2007,2008,2012,2013,2016,2017 Michael Fink
//
/// \file Timer.hpp Timer class
//
#pragma once

#pragma warning(push)
#pragma warning(disable: 28159) // Consider using 'GetTickCount64' instead of 'GetTickCount'. Reason: GetTickCount overflows roughly every 49 days.  Code that does not take that into account can loop indefinitely.  GetTickCount64 operates on 64 bit values and does not have that problem

/// \brief Timer class
/// \details Has a precision of about 15 ms. Has identical interface as class
/// HighResolutionTimer. Can be used in TraceOutputStopwatch.
class Timer
{
public:
   /// ctor
   Timer()
      :m_isStarted(false),
      m_tickStart(0),
      m_totalElapsed(0)
   {
   }

   /// starts timer; timer must be stopped or reset
   void Start()
   {
      ATLASSERT(m_isStarted == false);
      m_tickStart = GetTickCount();
      m_isStarted = true;
   }

   /// stops timer; timer must be started
   void Stop()
   {
      ATLASSERT(m_isStarted == true);

      DWORD tickEnd = GetTickCount();
      m_totalElapsed += (tickEnd - m_tickStart);
      m_isStarted = false;
   }

   /// resets timer; timer must be stopped
   void Reset()
   {
      ATLASSERT(m_isStarted == false); // must be stopped when calling Reset()
      m_totalElapsed = 0;
   }

   /// restarts timer by resetting and starting again
   void Restart()
   {
      // can either be stopped or started when restarting
      if (m_isStarted)
         Stop();
      Reset();
      Start();
   }

   /// returns elapsed time since Start() was called, in seconds
   double Elapsed() const
   {
      if (!m_isStarted)
         return 0.0; // no time elapsed, since timer isn't started

      DWORD tickNow = GetTickCount();
      return 0.001 * (tickNow - m_tickStart);
   }

   /// returns total elapsed time in seconds
   double TotalElapsed() const
   {
      DWORD tickNow = GetTickCount();
      return 0.001 * (m_totalElapsed + (m_isStarted ? (tickNow - m_tickStart) : 0));
   }

   /// returns if timer is running
   bool IsStarted() const { return m_isStarted; }

private:
   /// indicates if timer is started
   bool m_isStarted;

   /// tick count of start
   DWORD m_tickStart;

   /// number of ticks already elapsed
   DWORD m_totalElapsed;
};

#pragma warning(pop)
<|endoftext|>


<commit_before>// vi:cin:et:sw=4 ts=4
//
//  drafter.cc
//
//  Created by Jiri Kratochvil on 2015-02-11
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//
//
//

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

#include <tr1/memory>
#include <tr1/shared_ptr.h>

#include "snowcrash.h"
#include "SectionParserData.h"  // snowcrash::BlueprintParserOptions

#include "sos.h"
#include "sosJSON.h"
#include "sosYAML.h"

#include "SerializeAST.h"
#include "SerializeSourcemap.h"

#include "reporting.h"
#include "config.h"

namespace sc = snowcrash;

template<typename T>
struct dummy_deleter {
    void operator()(T* obj) const {
      // do nothing
    }
};

template<typename T> struct std_io_selector;

template<>
struct std_io_selector<std::ostream>{
    std::ostream* operator()() { return &std::cout; }
};

template<>
struct std_io_selector<std::istream>{
    std::istream* operator()() { return &std::cin; }
};

template <typename Stream> struct to_fstream;

template<>
struct to_fstream<std::istream>{
  typedef std::ifstream stream_type;
};

template<>
struct to_fstream<std::ostream>{
  typedef std::ofstream stream_type;
};

template<typename T> struct file_io_selector;

template<>
struct file_io_selector<std::ofstream>{
    std::ofstream* operator()(const char* name) { return new std::ofstream(name); }
};

template<>
struct file_io_selector<std::ifstream>{
    std::ifstream* operator()(const char* name) { return new std::ifstream(name); }
};

template<typename T>
std::tr1::shared_ptr<T> CreateStreamFromName(const std::string& file)
{
    if(file.empty()) {
        return std::tr1::shared_ptr<T>(
            std_io_selector<T>()(),
            dummy_deleter<T>()
        );
    }

    typedef typename to_fstream<T>::stream_type stream_type;
    std::tr1::shared_ptr<stream_type>stream(
        file_io_selector<stream_type>()(file.c_str())
    );

    if (!stream->is_open()) {
      std::cerr << "fatal: unable to open file '" << file << "'\n";
      exit(EXIT_FAILURE);
    }

    return stream;
}

void Serialization(const std::string& out,
    const sos::Object& object,
    sos::Serialize* serializer)
{
    std::tr1::shared_ptr<std::ostream> stream = CreateStreamFromName<std::ostream>(out);
    serializer->process(object, *stream);
    *stream << std::endl;
}

sos::Serialize* CreateSerializer(const std::string& format)
{
    if(format == "json") {
        return new sos::SerializeJSON;
    } else if(format == "yaml") {
        return new sos::SerializeYAML;
    }

    std::cerr << "fatal: unknow serialization format: '" << format << "'\n";
    exit(EXIT_FAILURE);
}

int main(int argc, const char *argv[])
{
    Config config;
    ParseCommadLineOptions(argc, argv, config);

    sc::BlueprintParserOptions options = 0;  // Or snowcrash::RequireBlueprintNameOption
    if(!config.sourceMap.empty()) {
        options |= snowcrash::ExportSourcemapOption;
    }

    std::stringstream inputStream;
    std::tr1::shared_ptr<std::istream> in = CreateStreamFromName<std::istream>(config.input);
    inputStream << in->rdbuf();

    sc::ParseResult<sc::Blueprint> blueprint;
    sc::parse(inputStream.str(), options, blueprint);

    if (!config.validate) {
        sos::Serialize* serializer = CreateSerializer(config.format);

        Serialization(config.output,
            snowcrash::WrapBlueprint(blueprint.node),
            serializer
            );

        Serialization(config.sourceMap,
            snowcrash::WrapBlueprintSourcemap(blueprint.sourceMap),
            serializer
            );

        delete serializer;
    }

    PrintReport(blueprint.report, inputStream.str(), config.lineNumbers);

    return blueprint.report.error.code;

}
<commit_msg>* refactoring CreateStreamFromName()<commit_after>// vi:cin:et:sw=4 ts=4
//
//  drafter.cc
//
//  Created by Jiri Kratochvil on 2015-02-11
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//
//
//

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

#include <tr1/memory>
#include <tr1/shared_ptr.h>

#include "snowcrash.h"
#include "SectionParserData.h"  // snowcrash::BlueprintParserOptions

#include "sos.h"
#include "sosJSON.h"
#include "sosYAML.h"

#include "SerializeAST.h"
#include "SerializeSourcemap.h"

#include "reporting.h"
#include "config.h"

namespace sc = snowcrash;

template<typename T>
struct dummy_deleter {
    void operator()(T* obj) const {
      // do nothing
    }
};

template<typename T> struct std_io;

template<> struct std_io<std::istream> {
    static std::istream* io() { return &std::cin; }
};

template<> struct std_io<std::ostream> {
    static std::ostream* io() { return &std::cout; }
};

template<typename T> struct std_io_selector {
    typedef T stream_type;
    typedef std::tr1::shared_ptr<stream_type> return_type;

    return_type operator()() { return return_type(std_io<T>::io(), dummy_deleter<stream_type>()); }
};

template <typename Stream> struct to_fstream;

template<>
struct to_fstream<std::istream>{
  typedef std::ifstream stream_type;
};

template<>
struct to_fstream<std::ostream>{
  typedef std::ofstream stream_type;
};

template<typename T> struct file_io_selector{
    typedef typename to_fstream<T>::stream_type stream_type;
    typedef std::tr1::shared_ptr<stream_type> return_type;

    return_type operator()(const char* name) const
    {
        return return_type(new stream_type(name));
    }
};

template<typename T>
std::tr1::shared_ptr<T> CreateStreamFromName(const std::string& file)
{
    if(file.empty()) {
        return std_io_selector<T>()();
    }

    typedef typename file_io_selector<T>::return_type return_type;

    return_type stream = file_io_selector<T>()(file.c_str());

    if (!stream->is_open()) {
      std::cerr << "fatal: unable to open file '" << file << "'\n";
      exit(EXIT_FAILURE);
    }

    return stream;
}

void Serialization(const std::string& out,
    const sos::Object& object,
    sos::Serialize* serializer)
{
    std::tr1::shared_ptr<std::ostream> stream = CreateStreamFromName<std::ostream>(out);
    serializer->process(object, *stream);
    *stream << std::endl;
}

sos::Serialize* CreateSerializer(const std::string& format)
{
    if(format == "json") {
        return new sos::SerializeJSON;
    } else if(format == "yaml") {
        return new sos::SerializeYAML;
    }

    std::cerr << "fatal: unknow serialization format: '" << format << "'\n";
    exit(EXIT_FAILURE);
}

int main(int argc, const char *argv[])
{
    Config config;
    ParseCommadLineOptions(argc, argv, config);

    sc::BlueprintParserOptions options = 0;  // Or snowcrash::RequireBlueprintNameOption
    if(!config.sourceMap.empty()) {
        options |= snowcrash::ExportSourcemapOption;
    }

    std::stringstream inputStream;
    std::tr1::shared_ptr<std::istream> in = CreateStreamFromName<std::istream>(config.input);
    inputStream << in->rdbuf();

    sc::ParseResult<sc::Blueprint> blueprint;
    sc::parse(inputStream.str(), options, blueprint);

    if (!config.validate) {
        sos::Serialize* serializer = CreateSerializer(config.format);

        Serialization(config.output,
            snowcrash::WrapBlueprint(blueprint.node),
            serializer
            );

        Serialization(config.sourceMap,
            snowcrash::WrapBlueprintSourcemap(blueprint.sourceMap),
            serializer
            );

        delete serializer;
    }

    PrintReport(blueprint.report, inputStream.str(), config.lineNumbers);

    return blueprint.report.error.code;

}
<|endoftext|>


<commit_before>#include "driver.hpp"
#include "scanner.hpp"
#include "parser.hpp"
#include "ast.hpp"
#include "codegen.hpp"

#include <sstream>
#include <vector>
#include <cstdlib>
#include <getopt.h>
#include <fstream>
#include <functional>
#include <boost/filesystem.hpp>

using namespace std;
using boost::filesystem::path;

lisplike_driver::lisplike_driver()
    : trace_scanning(false)
    , trace_parsing(false) { }

lisplike_driver::~lisplike_driver()
    { }

bool lisplike_driver::parse_stream(istream& in, const string& sname, std::ostream& out)
{
    streamname = sname;
    lisplike_scanner scanner(&in);
    scanner.set_debug(trace_scanning);
    lexer = &scanner;
    yy::lisplike_parser parser(*this);
    parser.set_debug_level(trace_parsing);
    return parser.parse() == 0;
}

bool lisplike_driver::parse_string(const string& line, const string& sname, std::ostream& out)
{
    istringstream iss(line);
    return parse_stream(iss, sname);
}

bool lisplike_driver::parse_file(const string& filename, std::ostream& out)
{
    ifstream in(filename);
    if(!in.good()) return false;
    return parse_stream(in, filename);
}

void lisplike_driver::error (const yy::location& l, const string& m)
{
    cerr << l << ": " << m << endl;
}

void lisplike_driver::error (const string& m)
{
    cerr << m << endl;
}

static vector<string> filenames;
static path outdir = ".";
bool verbose = false;
static bool outfile = true;
static bool genheader = true;
static bool genmain = true;

static void print_usage(int argc, char **argv)
{
    cout << "usage: " << argv[0] << " [opts] [input1 [input2 input3 ...]]" << endl;
    cout << "opts:" << endl <<
    "-p --trace-parsing         traces the Bison parse of the input" << endl <<
    "-s --trace-scanning        traces the Lexx scan of the input" << endl <<
    "-o --no-outfile            don't generate an output file" << endl <<
    "-h --no-header             don't generate a header file" << endl <<
    "-m --no-main               don't generate a main file" << endl <<
    "-d --dir [outdir]          directory to save output file to" << endl <<
    "-v --verbose               verbose output" << endl <<
    "-? --help                  shows this help message" << endl;
}

static void parse_args(int argc, char **argv, lisplike_driver &driver)
{
    while(1)
    {
        int optindex;
        static struct option long_options[] = {
            { "trace-parsing",      no_argument,        0,  'p' },
            { "trace-scanning",     no_argument,        0,  's' },
            { "outfile",            no_argument,        0,  'o' },
            { "gen-header",         no_argument,        0,  'h' },
            { "gen-main",           no_argument,        0,  'm' },
            { "dir",                required_argument,  0,  'd' },
            { "verbose",            no_argument,        0,  'v' },
            { "help",               required_argument,  0,  '?' },
            { nullptr,              0,                  0,   0  },
        };

        int c = getopt_long(argc, argv, "sphogmd:v", long_options, &optindex);
        if(c == -1)
            break;
        switch(c)
        {
            case 's':
                driver.trace_scanning = true;
                break;
            case 'p':
                driver.trace_parsing = true;
                break;
            case 'o':
                outfile = false;
                break;
            case 'h':
                genheader = false;
                break;
            case 'm':
                genmain = false;
                break;
            case 'd':
                outdir = path(optarg);
                break;
            case 'v':
                verbose = true;
                break;
            case '?':
                print_usage(argc, argv);
                exit(0);
                break;
            default:
                break;
        }
    }

    while(optind < argc)
        filenames.push_back(argv[optind++]);
    for(; optind < argc; optind++)
        cerr << "ignoring input file: " << argv[optind] << endl;
}

static int do_codegen(function<string(const ll_children&)> codegen_fn,
    const ll_children& ast, cstref filename)
{
    path outpath = outdir / (path(filename).filename());
    ofstream out_stream(outpath.string());
    if(!out_stream.good())
    {
        cerr << "could not open " << outpath << endl;
        return 1;
    }
    VCERR << "generating " << outpath.string() << endl;
    out_stream << codegen_fn(ast);
    return 0;
}

int main(int argc, char **argv)
{
    int mainresult = 0;
    lisplike_driver driver;
    parse_args(argc, argv, driver);

    if(!filenames.empty())
    {
        ll_children ast;
        if(!create_directory_tree(outdir))
        {
            cerr << "could not create directory tree " << outdir << endl;
            return 1;
        }

        for(auto filename : filenames)
        {
            if(!driver.parse_file(filename))
            {
                cerr << "error in " << filename << endl;
                return 1;
            }
            else
            {
                ast.insert(ast.end(), driver.ast.begin(), driver.ast.end());
                if(outfile)
                    mainresult |= do_codegen(gen_cpp, driver.ast, filename + ".cpp");
                if(genheader)
                    mainresult |= do_codegen(gen_header, driver.ast, filename + ".hpp");
            }
        }
        if(genmain)
            mainresult |= do_codegen(gen_main, ast, "main.cpp");

        if(mainresult == 0)
            cerr << "OK" << endl;
    }
    else
    {
        string line;
        while(getline(cin, line))
        {
            bool result = driver.parse_string(line, "stdin");
            if(result)
                cout << "OK" << endl;
        }
    }
    return mainresult;
}
<commit_msg>Changed code generation filenames to not include the original file extension<commit_after>#include "driver.hpp"
#include "scanner.hpp"
#include "parser.hpp"
#include "ast.hpp"
#include "codegen.hpp"

#include <sstream>
#include <vector>
#include <cstdlib>
#include <getopt.h>
#include <fstream>
#include <functional>
#include <boost/filesystem.hpp>

using namespace std;
using boost::filesystem::path;

lisplike_driver::lisplike_driver()
    : trace_scanning(false)
    , trace_parsing(false) { }

lisplike_driver::~lisplike_driver()
    { }

bool lisplike_driver::parse_stream(istream& in, const string& sname, std::ostream& out)
{
    streamname = sname;
    lisplike_scanner scanner(&in);
    scanner.set_debug(trace_scanning);
    lexer = &scanner;
    yy::lisplike_parser parser(*this);
    parser.set_debug_level(trace_parsing);
    return parser.parse() == 0;
}

bool lisplike_driver::parse_string(const string& line, const string& sname, std::ostream& out)
{
    istringstream iss(line);
    return parse_stream(iss, sname);
}

bool lisplike_driver::parse_file(const string& filename, std::ostream& out)
{
    ifstream in(filename);
    if(!in.good()) return false;
    return parse_stream(in, filename);
}

void lisplike_driver::error (const yy::location& l, const string& m)
{
    cerr << l << ": " << m << endl;
}

void lisplike_driver::error (const string& m)
{
    cerr << m << endl;
}

static vector<string> filenames;
static path outdir = ".";
bool verbose = false;
static bool outfile = true;
static bool genheader = true;
static bool genmain = true;

static void print_usage(int argc, char **argv)
{
    cout << "usage: " << argv[0] << " [opts] [input1 [input2 input3 ...]]" << endl;
    cout << "opts:" << endl <<
    "-p --trace-parsing         traces the Bison parse of the input" << endl <<
    "-s --trace-scanning        traces the Lexx scan of the input" << endl <<
    "-o --no-outfile            don't generate an output file" << endl <<
    "-h --no-header             don't generate a header file" << endl <<
    "-m --no-main               don't generate a main file" << endl <<
    "-d --dir [outdir]          directory to save output file to" << endl <<
    "-v --verbose               verbose output" << endl <<
    "-? --help                  shows this help message" << endl;
}

static void parse_args(int argc, char **argv, lisplike_driver &driver)
{
    while(1)
    {
        int optindex;
        static struct option long_options[] = {
            { "trace-parsing",      no_argument,        0,  'p' },
            { "trace-scanning",     no_argument,        0,  's' },
            { "outfile",            no_argument,        0,  'o' },
            { "gen-header",         no_argument,        0,  'h' },
            { "gen-main",           no_argument,        0,  'm' },
            { "dir",                required_argument,  0,  'd' },
            { "verbose",            no_argument,        0,  'v' },
            { "help",               required_argument,  0,  '?' },
            { nullptr,              0,                  0,   0  },
        };

        int c = getopt_long(argc, argv, "sphogmd:v", long_options, &optindex);
        if(c == -1)
            break;
        switch(c)
        {
            case 's':
                driver.trace_scanning = true;
                break;
            case 'p':
                driver.trace_parsing = true;
                break;
            case 'o':
                outfile = false;
                break;
            case 'h':
                genheader = false;
                break;
            case 'm':
                genmain = false;
                break;
            case 'd':
                outdir = path(optarg);
                break;
            case 'v':
                verbose = true;
                break;
            case '?':
                print_usage(argc, argv);
                exit(0);
                break;
            default:
                break;
        }
    }

    while(optind < argc)
        filenames.push_back(argv[optind++]);
    for(; optind < argc; optind++)
        cerr << "ignoring input file: " << argv[optind] << endl;
}

static int do_codegen(function<string(const ll_children&)> codegen_fn,
    const ll_children& ast, const path& filename)
{
    path outpath = outdir / (path(filename).filename());
    ofstream out_stream(outpath.string());
    if(!out_stream.good())
    {
        cerr << "could not open " << outpath << endl;
        return 1;
    }
    VCERR << "generating " << outpath.string() << endl;
    out_stream << codegen_fn(ast);
    return 0;
}

int main(int argc, char **argv)
{
    int mainresult = 0;
    lisplike_driver driver;
    parse_args(argc, argv, driver);

    if(!filenames.empty())
    {
        ll_children ast;
        if(!create_directory_tree(outdir))
        {
            cerr << "could not create directory tree " << outdir << endl;
            return 1;
        }

        for(path filename : filenames)
        {
            if(!driver.parse_file(filename.string()))
            {
                cerr << "error in " << filename << endl;
                return 1;
            }
            else
            {
                ast.insert(ast.end(), driver.ast.begin(), driver.ast.end());
                if(outfile)
                    mainresult |= do_codegen(gen_cpp, driver.ast, filename.replace_extension(".cpp"));
                if(genheader)
                    mainresult |= do_codegen(gen_header, driver.ast, filename.replace_extension(".hpp"));
            }
        }
        if(genmain)
            mainresult |= do_codegen(gen_main, ast, path("main.cpp"));

        if(mainresult == 0)
            cerr << "OK" << endl;
    }
    else
    {
        string line;
        while(getline(cin, line))
        {
            bool result = driver.parse_string(line, "stdin");
            if(result)
                cout << "OK" << endl;
        }
    }
    return mainresult;
}
<|endoftext|>