<commit_before>/*
 * opencog/atoms/core/PutLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Put Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Put Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atomspace/atom_types.h>
#include <opencog/atomspace/ClassServer.h>
#include "DefineLink.h"
#include "FreeLink.h"
#include "LambdaLink.h"
#include "PutLink.h"

using namespace opencog;

PutLink::PutLink(const HandleSeq& oset,
                 TruthValuePtr tv,
                 AttentionValuePtr av)
    : ScopeLink(PUT_LINK, oset, tv, av)
{
	init();
}

PutLink::PutLink(const Handle& a,
                 TruthValuePtr tv,
                 AttentionValuePtr av)
    : ScopeLink(PUT_LINK, a, tv, av)
{
	init();
}

PutLink::PutLink(Link& l)
    : ScopeLink(l)
{
	Type tscope = l.getType();
	if (not classserver().isA(tscope, PUT_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PutLink");
	init();
}

/* ================================================================= */

/// PutLink expects a very strict format: an arity-2 link, with
/// the first part being a pattern, and the second a list or set
/// of values. If the pattern has N variables, then the seccond
/// part must have N values.  Furthermore, any type restrictions on
/// the variables must be satisfied by the values.
///
/// The following formats are understood:
///
///    PutLink
///       <pattern with 1 variable>
///       <any single atom>
///
///    PutLink
///       <pattern with N variables>
///       ListLink     ;; must have arity N
///          <atom 1>
///          ...
///          <atom N>
///
/// The below is a handy-dandy easy-to-use form. When it is reduced,
/// it will result in the creation of a set of reduced forms, not
/// just one (the two sets haveing the same arity). Unfortunately,
/// this trick cannot work for N=1 unless the variable is cosntrained
/// to not be a set.
///
///    PutLink
///       <pattern with N variables>
///       SetLink        ;; Must hold a set of ListLinks
///          ListLink    ;; must have arity N
///             <atom 1>
///             ...
///             <atom N>
///
void PutLink::init(void)
{
	size_t sz = _outgoing.size();
	if (2 != sz and 3 != sz)
		throw InvalidParamException(TRACE_INFO,
			"Expecting an outgoing set size of two or three, got %d", sz);

	ScopeLink::extract_variables(_outgoing);

	if (2 == sz)
		_values = _outgoing[1];
	else
		_values = _outgoing[2];

	static_typecheck_values();
}

/// Check that the values in the PutLink obey the type constraints.
/// This only performs "static" typechecking, at construction-time;
/// the values may be dynamically obtained at run-time, we cannot check
/// these here.
void PutLink::static_typecheck_values(void)
{
	// Cannot typecheck at this pont in time, because the schema
	// might not be defined yet...
	Type btype = _body->getType();
	if (DEFINED_SCHEMA_NODE == btype)
		return;

	size_t sz = _varlist.varseq.size();
	Type vtype = _values->getType();

	if (1 == sz)
	{
		if (not _varlist.is_type(_values)
		    and SET_LINK != vtype)
		{
				throw InvalidParamException(TRACE_INFO,
					"PutLink mismatched type!");
		}
		return;
	}

	LinkPtr lval(LinkCast(_values));
	if (LIST_LINK == vtype)
	{
		if (not _varlist.is_type(lval->getOutgoingSet()))
			throw InvalidParamException(TRACE_INFO,
				"PutLink has mismatched value list!");
		return;
	}

	// GetLinks are evaluated dynamically, later.
	if (GET_LINK == vtype)
		return;

	if (SET_LINK != vtype)
		throw InvalidParamException(TRACE_INFO,
			"PutLink was expecting a ListLink, SetLink or GetLink!");

	if (1 < sz)
	{
		for (const Handle& h : lval->getOutgoingSet())
		{
			LinkPtr lse(LinkCast(h));
			// If the arity is greater than one, then the values must be in a list.
		   if (lse->getType() != LIST_LINK)
				throw InvalidParamException(TRACE_INFO,
					"PutLink expected value list!");

			if (not _varlist.is_type(lse->getOutgoingSet()))
				throw InvalidParamException(TRACE_INFO,
					"PutLink bad value list!");
		}
		return;
	}

	// If the arity is one, the values must obey type constraint.
	for (const Handle& h : lval->getOutgoingSet())
	{
		if (not _varlist.is_type(h))
			throw InvalidParamException(TRACE_INFO,
					"PutLink bad type!");
	}
}
/* ================================================================= */

/**
 * Perform the actual beta reduction --
 *
 * Substitute values for the variables in the pattern tree.
 * This is a lot like applying the function fun to the argument list
 * args, except that no actual evaluation is performed; only
 * substitution.  The resulting tree is NOT placed into any atomspace,
 * either. If you want that, you must do it youself.  If you want
 * evaluation or execution to happen during or after sustitution, use
 * either the EvaluationLink, the ExecutionOutputLink, or the Instantiator.
 *
 * So, for example, if this PutLink looks like this:
 *
 *   PutLink
 *      EvaluationLink
 *         PredicateNode "is a kind of"
 *         ListLink
 *            VariableNode $a
 *            ConceptNode "hot patootie"
 *      ConceptNode "cowpie"
 *
 * then the reduced value will be
 *
 *   EvaluationLink
 *      PredicateNode "is a kind of"
 *      ListLink
 *         ConceptNode "cowpie"
 *         ConceptNode "hot patootie"
 *
 * Type checking is performed during substitution; if the values fail to
 * have the desired types, no substituion is performed.  In this case,
 * an undefined handle is returned. For set substitutions, this acts as
 * a filter, removeing (filtering out) the mismatched types.
 *
 * Again, only a substitution is performed, there is no evaluation.
 * Note also that the resulting tree is NOT placed into any atomspace!
 */
Handle PutLink::do_reduce(void) const
{
	Handle bods(_body);
	Variables vars(_varlist);
	// Resolve the body, if needed:
	if (DEFINED_SCHEMA_NODE == _body->getType())
	{
		Handle dfn(DefineLink::get_definition(_body));
		// XXX TODO we should perform a type-check on the function.
		if (not classserver().isA(dfn->getType(), LAMBDA_LINK))
			throw InvalidParamException(TRACE_INFO,
					"Expecting a LambdaLink, got %s",
			      dfn->toString().c_str());

		LambdaLinkPtr lam(LambdaLinkCast(dfn));
		if (NULL == lam)
			lam = createLambdaLink(*LinkCast(dfn));
		bods = lam->get_body();
		vars = lam->get_variables();
	}

	Type vtype = _values->getType();

	if (1 == vars.varseq.size())
	{
		if (SET_LINK != vtype)
		{
			HandleSeq oset;
			oset.emplace_back(_values);
			try
			{
				return vars.substitute(bods, oset);
			}
			catch (...)
			{
				return Handle::UNDEFINED;
			}
		}

		// Iterate over the set...
		HandleSeq bset;
		for (Handle h : LinkCast(_values)->getOutgoingSet())
		{
			HandleSeq oset;
			oset.emplace_back(h);
			try
			{
				bset.emplace_back(vars.substitute(bods, oset));
			}
			catch (...) {}
		}
		return Handle(createLink(SET_LINK, bset));
	}
	if (LIST_LINK == vtype)
	{
		const HandleSeq& oset = LinkCast(_values)->getOutgoingSet();
		try
		{
			return vars.substitute(bods, oset);
		}
		catch (...)
		{
			return Handle::UNDEFINED;
		}
	}

	OC_ASSERT(SET_LINK == vtype,
		"Should have caught this earlier, in the ctor");

	HandleSeq bset;
	for (Handle h : LinkCast(_values)->getOutgoingSet())
	{
		const HandleSeq& oset = LinkCast(h)->getOutgoingSet();
		try
		{
			bset.emplace_back(vars.substitute(bods, oset));
		}
		catch (...) {}
	}
	return Handle(createLink(SET_LINK, bset));
}

Handle PutLink::reduce(void)
{
	return do_reduce();
}

/* ===================== END OF FILE ===================== */
<commit_msg>Improve error message<commit_after>/*
 * opencog/atoms/core/PutLink.cc
 *
 * Copyright (C) 2015 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Put Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Put Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atomspace/atom_types.h>
#include <opencog/atomspace/ClassServer.h>
#include "DefineLink.h"
#include "FreeLink.h"
#include "LambdaLink.h"
#include "PutLink.h"

using namespace opencog;

PutLink::PutLink(const HandleSeq& oset,
                 TruthValuePtr tv,
                 AttentionValuePtr av)
    : ScopeLink(PUT_LINK, oset, tv, av)
{
	init();
}

PutLink::PutLink(const Handle& a,
                 TruthValuePtr tv,
                 AttentionValuePtr av)
    : ScopeLink(PUT_LINK, a, tv, av)
{
	init();
}

PutLink::PutLink(Link& l)
    : ScopeLink(l)
{
	Type tscope = l.getType();
	if (not classserver().isA(tscope, PUT_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a PutLink");
	init();
}

/* ================================================================= */

/// PutLink expects a very strict format: an arity-2 link, with
/// the first part being a pattern, and the second a list or set
/// of values. If the pattern has N variables, then the seccond
/// part must have N values.  Furthermore, any type restrictions on
/// the variables must be satisfied by the values.
///
/// The following formats are understood:
///
///    PutLink
///       <pattern with 1 variable>
///       <any single atom>
///
///    PutLink
///       <pattern with N variables>
///       ListLink     ;; must have arity N
///          <atom 1>
///          ...
///          <atom N>
///
/// The below is a handy-dandy easy-to-use form. When it is reduced,
/// it will result in the creation of a set of reduced forms, not
/// just one (the two sets haveing the same arity). Unfortunately,
/// this trick cannot work for N=1 unless the variable is cosntrained
/// to not be a set.
///
///    PutLink
///       <pattern with N variables>
///       SetLink        ;; Must hold a set of ListLinks
///          ListLink    ;; must have arity N
///             <atom 1>
///             ...
///             <atom N>
///
void PutLink::init(void)
{
	size_t sz = _outgoing.size();
	if (2 != sz and 3 != sz)
		throw InvalidParamException(TRACE_INFO,
			"Expecting an outgoing set size of two or three, got %d; %s",
			sz, toString().c_str());

	ScopeLink::extract_variables(_outgoing);

	if (2 == sz)
		_values = _outgoing[1];
	else
		_values = _outgoing[2];

	static_typecheck_values();
}

/// Check that the values in the PutLink obey the type constraints.
/// This only performs "static" typechecking, at construction-time;
/// the values may be dynamically obtained at run-time, we cannot check
/// these here.
void PutLink::static_typecheck_values(void)
{
	// Cannot typecheck at this pont in time, because the schema
	// might not be defined yet...
	Type btype = _body->getType();
	if (DEFINED_SCHEMA_NODE == btype)
		return;

	size_t sz = _varlist.varseq.size();
	Type vtype = _values->getType();

	if (1 == sz)
	{
		if (not _varlist.is_type(_values)
		    and SET_LINK != vtype)
		{
				throw InvalidParamException(TRACE_INFO,
					"PutLink mismatched type!");
		}
		return;
	}

	LinkPtr lval(LinkCast(_values));
	if (LIST_LINK == vtype)
	{
		if (not _varlist.is_type(lval->getOutgoingSet()))
			throw InvalidParamException(TRACE_INFO,
				"PutLink has mismatched value list!");
		return;
	}

	// GetLinks are evaluated dynamically, later.
	if (GET_LINK == vtype)
		return;

	if (SET_LINK != vtype)
		throw InvalidParamException(TRACE_INFO,
			"PutLink was expecting a ListLink, SetLink or GetLink!");

	if (1 < sz)
	{
		for (const Handle& h : lval->getOutgoingSet())
		{
			LinkPtr lse(LinkCast(h));
			// If the arity is greater than one, then the values must be in a list.
		   if (lse->getType() != LIST_LINK)
				throw InvalidParamException(TRACE_INFO,
					"PutLink expected value list!");

			if (not _varlist.is_type(lse->getOutgoingSet()))
				throw InvalidParamException(TRACE_INFO,
					"PutLink bad value list!");
		}
		return;
	}

	// If the arity is one, the values must obey type constraint.
	for (const Handle& h : lval->getOutgoingSet())
	{
		if (not _varlist.is_type(h))
			throw InvalidParamException(TRACE_INFO,
					"PutLink bad type!");
	}
}
/* ================================================================= */

/**
 * Perform the actual beta reduction --
 *
 * Substitute values for the variables in the pattern tree.
 * This is a lot like applying the function fun to the argument list
 * args, except that no actual evaluation is performed; only
 * substitution.  The resulting tree is NOT placed into any atomspace,
 * either. If you want that, you must do it youself.  If you want
 * evaluation or execution to happen during or after sustitution, use
 * either the EvaluationLink, the ExecutionOutputLink, or the Instantiator.
 *
 * So, for example, if this PutLink looks like this:
 *
 *   PutLink
 *      EvaluationLink
 *         PredicateNode "is a kind of"
 *         ListLink
 *            VariableNode $a
 *            ConceptNode "hot patootie"
 *      ConceptNode "cowpie"
 *
 * then the reduced value will be
 *
 *   EvaluationLink
 *      PredicateNode "is a kind of"
 *      ListLink
 *         ConceptNode "cowpie"
 *         ConceptNode "hot patootie"
 *
 * Type checking is performed during substitution; if the values fail to
 * have the desired types, no substituion is performed.  In this case,
 * an undefined handle is returned. For set substitutions, this acts as
 * a filter, removeing (filtering out) the mismatched types.
 *
 * Again, only a substitution is performed, there is no evaluation.
 * Note also that the resulting tree is NOT placed into any atomspace!
 */
Handle PutLink::do_reduce(void) const
{
	Handle bods(_body);
	Variables vars(_varlist);
	// Resolve the body, if needed:
	if (DEFINED_SCHEMA_NODE == _body->getType())
	{
		Handle dfn(DefineLink::get_definition(_body));
		// XXX TODO we should perform a type-check on the function.
		if (not classserver().isA(dfn->getType(), LAMBDA_LINK))
			throw InvalidParamException(TRACE_INFO,
					"Expecting a LambdaLink, got %s",
			      dfn->toString().c_str());

		LambdaLinkPtr lam(LambdaLinkCast(dfn));
		if (NULL == lam)
			lam = createLambdaLink(*LinkCast(dfn));
		bods = lam->get_body();
		vars = lam->get_variables();
	}

	Type vtype = _values->getType();

	if (1 == vars.varseq.size())
	{
		if (SET_LINK != vtype)
		{
			HandleSeq oset;
			oset.emplace_back(_values);
			try
			{
				return vars.substitute(bods, oset);
			}
			catch (...)
			{
				return Handle::UNDEFINED;
			}
		}

		// Iterate over the set...
		HandleSeq bset;
		for (Handle h : LinkCast(_values)->getOutgoingSet())
		{
			HandleSeq oset;
			oset.emplace_back(h);
			try
			{
				bset.emplace_back(vars.substitute(bods, oset));
			}
			catch (...) {}
		}
		return Handle(createLink(SET_LINK, bset));
	}
	if (LIST_LINK == vtype)
	{
		const HandleSeq& oset = LinkCast(_values)->getOutgoingSet();
		try
		{
			return vars.substitute(bods, oset);
		}
		catch (...)
		{
			return Handle::UNDEFINED;
		}
	}

	OC_ASSERT(SET_LINK == vtype,
		"Should have caught this earlier, in the ctor");

	HandleSeq bset;
	for (Handle h : LinkCast(_values)->getOutgoingSet())
	{
		const HandleSeq& oset = LinkCast(h)->getOutgoingSet();
		try
		{
			bset.emplace_back(vars.substitute(bods, oset));
		}
		catch (...) {}
	}
	return Handle(createLink(SET_LINK, bset));
}

Handle PutLink::reduce(void)
{
	return do_reduce();
}

/* ===================== END OF FILE ===================== */
<|endoftext|>


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

#ifndef __VLE_KERNEL_GENERIC_HPP__
#define __VLE_KERNEL_GENERIC_HPP__

#include <vle/dsde.hpp>
#include <vle/utils.hpp>
#include <fstream>
#include <memory>
#include <sstream>
#include <unordered_map>

namespace vle { namespace dsde {

struct fileformat_error: std::invalid_argument
{
    fileformat_error()
        : std::invalid_argument("dsde::fileformat: file format error")
    {}

    fileformat_error(std::size_t idx, std::size_t size)
        : std::invalid_argument(
            vle::stringf("dsde::fileformat: child index [%" PRIuMAX "]"
                         ">= size of the children list (%" PRIuMAX ")",
                         (std::uintmax_t)idx,
                         (std::uintmax_t)size))
    {}

    fileformat_error(std::size_t idx)
        : std::invalid_argument(
            vle::stringf("dsde::fileformat: port index [%" PRIuMAX "] too big",
                         (std::uintmax_t)idx))
    {}
};

struct factory_error : std::invalid_argument
{
    factory_error(const std::string& dynamicsname)
        : std::invalid_argument(
            vle::stringf("dsde::factory: unknown dynamics [%s]",
                         dynamicsname.c_str()))
    {}
};

template <typename Time, typename Value>
struct Factory
{
    typedef typename Time::time_type time_type;
    typedef Value value_type;

    typedef std::unique_ptr <Model <Time, Value>> modelptr;
    typedef std::function <modelptr(void)> function_t;

    modelptr get(const std::string& dynamicsname) const
    {
        auto it = functions.find(dynamicsname);
        if (it != functions.end())
            return std::move(it->second());

        throw factory_error(dynamicsname);
    }

    std::unordered_map <std::string, function_t> functions;
};

/*
 * @e GenericCoupledModel can read a TGF file format to initialize children
 * and connections.
 *
 * \example
 * Generator
 * Generator
 * Counter
 * #
 * 0 3 0 0
 * 1 2 0 0
 * 2 3 0 0
 * \endexample
 *
 * @TODO Move this class into a dsde-basic ?
 */
template <typename Time, typename Value,
         typename Policy = TransitionPolicyDefault <Time, Value>>
struct GenericCoupledModel : CoupledModel <Time, Value, Policy>
{
    typedef typename Time::time_type time_type;
    typedef Value value_type;
    typedef Policy transition_policy;

    typedef std::pair <Model <Time, Value>*, int> inputport;
    typedef std::pair <Model <Time, Value>*, int> outputport;
    typedef std::vector <std::unique_ptr <Model <Time, Value>>> vertices;

    enum ReaderOption
    {
        INDEXED_BY_INT,
        INDEXED_BY_STRING
    };

    struct hash_inputport
    {
        std::size_t operator()(const inputport& lhs) const
        {
            std::hash <Model <Time, Value>*> hasher;

            return hasher(lhs.first);
        }
    };

    struct equalto_inputport
    {
        constexpr bool operator()(const inputport& lhs, const inputport& rhs) const
        {
            return lhs.first == rhs.first && rhs.second == lhs.second;
        }
    };

    typedef std::unordered_multimap <
        inputport, outputport, hash_inputport, equalto_inputport> edges;

    GenericCoupledModel(const Context& ctx)
        : CoupledModel <Time, Value, Policy>(ctx)
    {}

    GenericCoupledModel(const Context& ctx,
                        std::initializer_list <std::string> lst_x,
                        std::initializer_list <std::string> lst_y)
        : CoupledModel <Time, Value, Policy>(ctx, lst_x, lst_y)
    {}

    virtual ~GenericCoupledModel()
    {}

    virtual typename CoupledModel <Time, Value>::children_t
    children(const vle::Common& /*common*/) override final
    {
        return {};
    }

    virtual void apply_common(const vle::Common& common)
    {
        (void)common;
    }

    virtual vle::Common update_common(const vle::Common& common,
                                      const GenericCoupledModel::vertices& v,
                                      const GenericCoupledModel::edges& e,
                                      int child)
    {
        (void) common;
        (void) v;
        (void) e;
        (void) child;

        return vle::Common();
    }

    virtual void start(const vle::Common& common,
                       const time_type& time) override
    {
        apply_common(common);

        int tgf_source = common_get <int>(common, "tgf-source");
        int tgf_format = common_get <int>(common, "tgf-format");

        typedef std::shared_ptr <Factory <Time, Value>> FactoryPtr;

        FactoryPtr factory = common_get <FactoryPtr>(common, "tgf-factory");

        if (tgf_source == 0) {
            std::string tgf_filesource = common_get <std::string>(common,
                                                                  "tgf-filesource");
            std::ifstream ifs(tgf_filesource);
            if (!ifs)
                throw std::invalid_argument(
                    stringf("GenericCoupledModel: failed to open file %s",
                            tgf_filesource.c_str()));

            read(ifs, *factory.get(), (tgf_format == 0) ? INDEXED_BY_INT :
                 INDEXED_BY_STRING);
        } else {
            std::string string_source = common_get <std::string>(common,
                                                                 "tgf-stringsource");

            std::istringstream iss(string_source);

            read(iss, *factory.get(), (tgf_format == 0) ? INDEXED_BY_INT :
                 INDEXED_BY_STRING);
        }

        typename CoupledModel <Time, Value>::children_t ret;
        ret.reserve(m_children.size());

        for (int i = 0, e = m_children.size(); i != e; ++i) {
            m_children[i]->parent = this;
            vle::Common localcommon = update_common(common,
                                                    m_children,
                                                    m_connections,
                                                    i);

            m_children[i]->start(localcommon, time);

            auto id = CoupledModel <Time, Value, Policy>::heap.emplace(
                m_children[i].get(),
                m_children[i]->tn);

            m_children[i]->heapid = id;
            (*id).heapid = id;
        };

        Model <Time, Value>::tl = time;
        Model <Time, Value>::tn =
            CoupledModel <Time, Value, Policy>::heap.top().tn;
    }

    virtual void post(const UpdatedPort <Time, Value> &out,
                      UpdatedPort <Time, Value> &in) const override final
    {
        for (auto& model : out) {
            std::size_t i = 0;
            std::size_t e = (model == this) ?
                Model <Time, Value>::x.size() : model->y.size();

            for (; i != e; ++i) {
                if ((model == this &&
                     !Model <Time, Value>::x[i].empty()) or
                    (model != this && !model->y[i].empty())) {
                    auto result = m_connections.equal_range(
                        std::make_pair(
                            const_cast <Model <Time, Value>*>(model),
                            i));

                    for (; result.first != result.second; ++result.first) {
                        Model <Time, Value>* dst =
                            const_cast <Model <Time, Value>*>(
                                result.first->second.first);

                        std::size_t portdst = result.first->second.second;

                        in.emplace(dst);

                        if (dst == this) {
                            if (model == this) {
                                assert(false);
                            } else {
                                dst->y[portdst].insert(dst->y[portdst].end(),
                                                       model->y[i].begin(),
                                                       model->y[i].end());
                            }
                        } else {
                            if (model == this) {
                                dst->x[portdst].insert(dst->x[portdst].end(),
                                                       model->x[i].begin(),
                                                       model->x[i].end());
                            } else {
                                dst->x[portdst].insert(dst->x[portdst].end(),
                                                       model->y[i].begin(),
                                                       model->y[i].end());
                            }
                        }
                    }
                }
            }
        }
    }

    vertices m_children;
    edges m_connections;

private:
    void read(std::istream& is, const Factory <Time, Value>& factory,
              ReaderOption opt)
    {
        while (is.good()) {
            std::string dynamics;
            if (is >> dynamics) {
                if (!dynamics.empty() && dynamics[0] != '#') {
                    m_children.emplace_back(factory.get(dynamics));
                } else {
                    break;
                }
            } else
                throw fileformat_error();
        }

        if (opt == INDEXED_BY_INT) {
            while (is.good()) {
                std::size_t model_i, model_j;
                std::size_t port_i, port_j;

                if (is >> model_i >> model_j >> port_i >> port_j) {
                    if (model_i > m_children.size())
                        throw fileformat_error(model_i, m_children.size());

                    if (model_j > m_children.size())
                        throw fileformat_error(model_j, m_children.size());

                    Model <Time, Value>* src;

                    if (model_i == 0) {
                        src = this;

                        if (port_i >= src->x.size())
                            throw fileformat_error(port_i);
                    } else {
                        src = m_children[model_i - 1].get();

                        if (port_i >= src->y.size())
                            throw fileformat_error(port_i);
                    }

                    Model <Time, Value>* dst;

                    if (model_j == 0) {
                        dst = this;

                        if (port_j >= dst->y.size())
                            throw fileformat_error(port_j);
                    } else {
                        dst = m_children[model_j - 1].get();

                        if (port_j >= dst->x.size())
                            throw fileformat_error(port_j);
                    };

                    m_connections.emplace(std::make_pair(src, port_i),
                                          std::make_pair(dst, port_j));
                }
            }
        } else {
            while (is.good()) {
                std::size_t model_i, model_j;
                std::size_t port_i, port_j;
                std::string str_port_i, str_port_j;

                if (is >> model_i >> model_j >> str_port_i >> str_port_j) {
                    if (model_i > m_children.size())
                        throw fileformat_error(model_i, m_children.size());

                    if (model_j > m_children.size())
                        throw fileformat_error(model_j, m_children.size());

                    Model <Time, Value>* src;

                    if (model_i == 0) {
                        src = this;
                        port_i = src->x.add_port(str_port_i);
                    } else {
                        src = m_children[model_i - 1].get();
                        port_i = src->y.add_port(str_port_i);
                    }

                    Model <Time, Value>* dst;

                    try {
                        if (model_j == 0) {
                            dst = this;
                            port_j = dst->y.add_port(str_port_j);
                        } else {
                            dst = m_children[model_j - 1].get();
                            port_j = dst->x.add_port(str_port_j);
                        }
                    } catch (const std::exception& e) {
                        throw fileformat_error();
                    }

                    m_connections.emplace(std::make_pair(src, port_i),
                                          std::make_pair(dst, port_j));
                }
            }
        }
    }
};

}}

#endif
<commit_msg>generic: adding more vle_dbg trace<commit_after>/*
 * Copyright (C) 2013-2014 INRA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __VLE_KERNEL_GENERIC_HPP__
#define __VLE_KERNEL_GENERIC_HPP__

#include <vle/dsde.hpp>
#include <vle/utils.hpp>
#include <fstream>
#include <memory>
#include <sstream>
#include <unordered_map>

namespace vle { namespace dsde {

struct fileformat_error: std::invalid_argument
{
    fileformat_error()
        : std::invalid_argument("dsde::fileformat: file format error")
    {}

    fileformat_error(std::size_t idx, std::size_t size)
        : std::invalid_argument(
            vle::stringf("dsde::fileformat: child index [%" PRIuMAX "]"
                         ">= size of the children list (%" PRIuMAX ")",
                         (std::uintmax_t)idx,
                         (std::uintmax_t)size))
    {}

    fileformat_error(std::size_t idx)
        : std::invalid_argument(
            vle::stringf("dsde::fileformat: port index [%" PRIuMAX "] too big",
                         (std::uintmax_t)idx))
    {}
};

struct factory_error : std::invalid_argument
{
    factory_error(const std::string& dynamicsname)
        : std::invalid_argument(
            vle::stringf("dsde::factory: unknown dynamics [%s]",
                         dynamicsname.c_str()))
    {}
};

template <typename Time, typename Value>
struct Factory
{
    typedef typename Time::time_type time_type;
    typedef Value value_type;

    typedef std::unique_ptr <Model <Time, Value>> modelptr;
    typedef std::function <modelptr(void)> function_t;

    modelptr get(const std::string& dynamicsname) const
    {
        auto it = functions.find(dynamicsname);
        if (it != functions.end())
            return std::move(it->second());

        throw factory_error(dynamicsname);
    }

    std::unordered_map <std::string, function_t> functions;
};

/*
 * @e GenericCoupledModel can read a TGF file format to initialize children
 * and connections.
 *
 * \example
 * Generator
 * Generator
 * Counter
 * #
 * 0 3 0 0
 * 1 2 0 0
 * 2 3 0 0
 * \endexample
 *
 * @TODO Move this class into a dsde-basic ?
 */
template <typename Time, typename Value,
         typename Policy = TransitionPolicyDefault <Time, Value>>
struct GenericCoupledModel : CoupledModel <Time, Value, Policy>
{
    typedef typename Time::time_type time_type;
    typedef Value value_type;
    typedef Policy transition_policy;

    typedef std::pair <Model <Time, Value>*, int> inputport;
    typedef std::pair <Model <Time, Value>*, int> outputport;
    typedef std::vector <std::unique_ptr <Model <Time, Value>>> vertices;

    enum ReaderOption
    {
        INDEXED_BY_INT,
        INDEXED_BY_STRING
    };

    struct hash_inputport
    {
        std::size_t operator()(const inputport& lhs) const
        {
            std::hash <Model <Time, Value>*> hasher;

            return hasher(lhs.first);
        }
    };

    struct equalto_inputport
    {
        constexpr bool operator()(const inputport& lhs, const inputport& rhs) const
        {
            return lhs.first == rhs.first && rhs.second == lhs.second;
        }
    };

    typedef std::unordered_multimap <
        inputport, outputport, hash_inputport, equalto_inputport> edges;

    GenericCoupledModel(const Context& ctx)
        : CoupledModel <Time, Value, Policy>(ctx)
    {}

    GenericCoupledModel(const Context& ctx,
                        std::initializer_list <std::string> lst_x,
                        std::initializer_list <std::string> lst_y)
        : CoupledModel <Time, Value, Policy>(ctx, lst_x, lst_y)
    {}

    virtual ~GenericCoupledModel()
    {}

    virtual typename CoupledModel <Time, Value>::children_t
    children(const vle::Common& /*common*/) override final
    {
        return {};
    }

    virtual void apply_common(const vle::Common& common)
    {
        (void)common;
    }

    virtual vle::Common update_common(const vle::Common& common,
                                      const GenericCoupledModel::vertices& v,
                                      const GenericCoupledModel::edges& e,
                                      int child)
    {
        (void) common;
        (void) v;
        (void) e;
        (void) child;

        return vle::Common();
    }

    virtual void start(const vle::Common& common,
                       const time_type& time) override
    {
        apply_common(common);

        int tgf_source = common_get <int>(common, "tgf-source");
        int tgf_format = common_get <int>(common, "tgf-format");

        typedef std::shared_ptr <Factory <Time, Value>> FactoryPtr;

        FactoryPtr factory = common_get <FactoryPtr>(common, "tgf-factory");

        if (tgf_source == 0) {
            std::string tgf_filesource = common_get <std::string>(common,
                                                                  "tgf-filesource");
            std::ifstream ifs(tgf_filesource);
            if (!ifs)
                throw std::invalid_argument(
                    stringf("GenericCoupledModel: failed to open file %s",
                            tgf_filesource.c_str()));

            read(ifs, *factory.get(), (tgf_format == 0) ? INDEXED_BY_INT :
                 INDEXED_BY_STRING);
        } else {
            std::string string_source = common_get <std::string>(common,
                                                                 "tgf-stringsource");

            std::istringstream iss(string_source);

            read(iss, *factory.get(), (tgf_format == 0) ? INDEXED_BY_INT :
                 INDEXED_BY_STRING);
        }

        typename CoupledModel <Time, Value>::children_t ret;
        ret.reserve(m_children.size());

        for (int i = 0, e = m_children.size(); i != e; ++i) {
            m_children[i]->parent = this;
            vle::Common localcommon = update_common(common,
                                                    m_children,
                                                    m_connections,
                                                    i);

            m_children[i]->start(localcommon, time);

            auto id = CoupledModel <Time, Value, Policy>::heap.emplace(
                m_children[i].get(),
                m_children[i]->tn);

            m_children[i]->heapid = id;
            (*id).heapid = id;
        };

        Model <Time, Value>::tl = time;
        Model <Time, Value>::tn =
            CoupledModel <Time, Value, Policy>::heap.top().tn;
    }

    virtual void post(const UpdatedPort <Time, Value> &out,
                      UpdatedPort <Time, Value> &in) const override final
    {
        for (auto& model : out) {
            std::size_t i = 0;
            std::size_t e = (model == this) ?
                Model <Time, Value>::x.size() : model->y.size();

            for (; i != e; ++i) {
                if ((model == this &&
                     !Model <Time, Value>::x[i].empty()) or
                    (model != this && !model->y[i].empty())) {
                    auto result = m_connections.equal_range(
                        std::make_pair(
                            const_cast <Model <Time, Value>*>(model),
                            i));

                    for (; result.first != result.second; ++result.first) {
                        Model <Time, Value>* dst =
                            const_cast <Model <Time, Value>*>(
                                result.first->second.first);

                        std::size_t portdst = result.first->second.second;

                        in.emplace(dst);

                        if (dst == this) {
                            if (model == this) {
                                assert(false);
                            } else {
                                dst->y[portdst].insert(dst->y[portdst].end(),
                                                       model->y[i].begin(),
                                                       model->y[i].end());

                                vle_dbg(GenericCoupledModel::ctx,
                                        "Move from %p port %lu to coupled model %p port %lu\n",
                                        model, i, dst, portdst);
                            }
                        } else {
                            if (model == this) {
                                dst->x[portdst].insert(dst->x[portdst].end(),
                                                       model->x[i].begin(),
                                                       model->x[i].end());

                                vle_dbg(GenericCoupledModel::ctx,
                                        "Move from coupled model %p port %lu to %p port %lu\n",
                                        model, i, dst, portdst);
                            } else {
                                dst->x[portdst].insert(dst->x[portdst].end(),
                                                       model->y[i].begin(),
                                                       model->y[i].end());

                                vle_dbg(GenericCoupledModel::ctx,
                                        "Move from model %p port %lu to model %p port %lu\n",
                                        model, i, dst, portdst);
                            }
                        }
                    }
                }
            }
        }
    }

    vertices m_children;
    edges m_connections;

private:
    void read(std::istream& is, const Factory <Time, Value>& factory,
              ReaderOption opt)
    {
        while (is.good()) {
            std::string dynamics;
            if (is >> dynamics) {
                if (!dynamics.empty() && dynamics[0] != '#') {
                    m_children.emplace_back(factory.get(dynamics));
                } else {
                    break;
                }
            } else
                throw fileformat_error();
        }

        if (opt == INDEXED_BY_INT) {
            while (is.good()) {
                std::size_t model_i, model_j;
                std::size_t port_i, port_j;

                if (is >> model_i >> model_j >> port_i >> port_j) {
                    if (model_i > m_children.size())
                        throw fileformat_error(model_i, m_children.size());

                    if (model_j > m_children.size())
                        throw fileformat_error(model_j, m_children.size());

                    Model <Time, Value>* src;

                    if (model_i == 0) {
                        src = this;

                        if (port_i >= src->x.size())
                            throw fileformat_error(port_i);
                    } else {
                        src = m_children[model_i - 1].get();

                        if (port_i >= src->y.size())
                            throw fileformat_error(port_i);
                    }

                    Model <Time, Value>* dst;

                    if (model_j == 0) {
                        dst = this;

                        if (port_j >= dst->y.size())
                            throw fileformat_error(port_j);
                    } else {
                        dst = m_children[model_j - 1].get();

                        if (port_j >= dst->x.size())
                            throw fileformat_error(port_j);
                    };

                    m_connections.emplace(std::make_pair(src, port_i),
                                          std::make_pair(dst, port_j));
                }
            }
        } else {
            while (is.good()) {
                std::size_t model_i, model_j;
                std::size_t port_i, port_j;
                std::string str_port_i, str_port_j;

                if (is >> model_i >> model_j >> str_port_i >> str_port_j) {
                    if (model_i > m_children.size())
                        throw fileformat_error(model_i, m_children.size());

                    if (model_j > m_children.size())
                        throw fileformat_error(model_j, m_children.size());

                    Model <Time, Value>* src;

                    if (model_i == 0) {
                        src = this;
                        port_i = src->x.add_port(str_port_i);
                    } else {
                        src = m_children[model_i - 1].get();
                        port_i = src->y.add_port(str_port_i);
                    }

                    Model <Time, Value>* dst;

                    try {
                        if (model_j == 0) {
                            dst = this;
                            port_j = dst->y.add_port(str_port_j);
                        } else {
                            dst = m_children[model_j - 1].get();
                            port_j = dst->x.add_port(str_port_j);
                        }
                    } catch (const std::exception& e) {
                        throw fileformat_error();
                    }

                    m_connections.emplace(std::make_pair(src, port_i),
                                          std::make_pair(dst, port_j));
                }
            }
        }
    }
};

}}

#endif
<|endoftext|>


<commit_before>/*
 *  main.cpp
 *  vm
 *
 *  Created by dracks on 01/03/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

/**
 * @mainpage Objective Fenix - Virtual Machine
 * @author Jaume Singla Valls
 * @date 2010
 */

#include "stdlib.h"
#include "stdio.h"

#include "ASM_instructions.h"
#include "SDK/Stackable.h"
/*#include "BuiltIn/Shell.h"
#include "BuiltIn/String.h"
#include "BuiltIn/Integer.h"
#include "SDK/SuperClass.h"
#include "SDK/Super.h"
*/
#include "tools/Adapter.h"
#include "tools/Cache.h"

#include <time.h>
#include "tools.h"

#include "BuiltIn/Boolean.h"
#include "BuiltIn/Integer.h"
#include "BuiltIn/String.h"

#include "BuiltIn/Shell.h"

#include <dlfcn.h>

#ifdef _WIN32 // note the underscore: without it, it's not msdn official!
#define kLibraryExtension(name) name ".dll"
// Windows (x64 and x86)
#elif __unix__ // all unices
// Unix
#elif __posix__
// POSIX
#elif __linux__
// linux
#define kLibraryExtension(name)  name ".so"
//"
#elif __APPLE__
#define kLibraryExtension(name)  name ".dylib"
//"
// Mac OS, not sure if this is covered by __posix__ and/or __unix__ though...
#endif

using namespace SDK;
using namespace ofxBI;
using namespace ofxbytecode;
using namespace ofxtools;
//static Stackable* cache[10];

typedef struct headerSave{
	int		 ByteCodeVersion;
	int		 uid_programClass;
	long int p_Constants; // Position where found the sections.
	int		 n_Constants;
	long int p_Class;
	int		 n_Class;
	long int p_ByteCode;
	int		 n_ByteCode;
} t_HeaderSave;

/**
 * @brief load the bytecodefile, and charge all libraries
 * @param file Name of the file .ofb to load
 * @param data pointer to the library of the code
 * @return The bytecode loaded
 */
pair<ASM_line*, int> loadByteCode(string file, Library* data){
	t_HeaderSave header;
	FILE*	bytecodeFile;
	ASM_line* bytecode;
	int count1, count2;
	bytecodeFile=fopen(file.c_str(), "r");

	if (!bytecodeFile){
		cout << "ERROR file not found" << endl;
		exit(-1);
	}

	fread(&header, sizeof(headerSave), 1, bytecodeFile); // A partir d'aqui tenim la capçalera carregada
	printf("Debugging: (%d)\n", header.ByteCodeVersion);
	printf("Constants:	%d despl: %ld\n",header.n_Constants, header.p_Constants);
	printf("Class:		%d despl: %ld\n",header.n_Class, header.p_Class);
	printf("ByteCode:	%d despl: %ld\n",header.n_ByteCode, header.p_ByteCode);

	void *hndl = dlopen(kLibraryExtension("./build/lib/libBuiltIn"), RTLD_NOW);
	if(hndl == NULL){
		cerr << dlerror() << endl;
		exit(-1);
	}
	//void *mkr = dlsym(hndl, "maker");*/

	Adapter* adaptador=new Adapter();

	// We read the Classes from bytecode
	count1=0;
	fseek(bytecodeFile, header.p_Class, SEEK_SET);

	while (count1<header.n_Class){
		int cid;
		int fatherUID;
		char native;
		char constructor,isStatic;
		int line;
		int aux,aux2;
		int limit2;
		char* name;
		CacheClass* cache;
		fread(&cid,		sizeof(int),	1, bytecodeFile);
		fread(&fatherUID,	sizeof(int),	1, bytecodeFile);
		fread(&native,	sizeof(char),	1, bytecodeFile);
		fread(&aux,		sizeof(int),	1, bytecodeFile);
		//name=(char*) malloc(aux*sizeof(char));
		name=new char[aux];
		fread(name,		sizeof(char),	aux,	bytecodeFile);

		if (native){
			cache=new NativeCacheClass(cid,name);
		} else {
			cache=new OfxCacheClass(cid, name, fatherUID);
		}
		//cout << "Parsejant la clase: " << name << endl;
		//free(name);
		delete[] name;

		fread(&aux2, sizeof(int), 1, bytecodeFile);
		//cout << "Propietats: " << aux2 << endl;
		count2=0;
		while (count2<aux2){
			int uid;
			fread(&uid,		sizeof(int),	1, bytecodeFile);
			fread(&aux,	sizeof(int),	1, bytecodeFile);
			//name=(char*) malloc(sizeof(char)*(aux+1));
			name=new char[aux];
			fread(name, sizeof(char), aux, bytecodeFile);
			//cout << "\tPropietat: " << name << endl;
			cache->addProperty(uid, name);

			delete[] name;
			//free(name);

			count2++;
		}

		fread(&aux2, sizeof(int), 1, bytecodeFile);
		count2=0;
		//cout << "Metodes: " << aux2 << endl;
		while (count2<aux2){
			int uid;
			fread(&uid,		sizeof(int),	1, bytecodeFile);
			fread(&line,	sizeof(int),	1, bytecodeFile);
			fread(&constructor,	sizeof(char),	1, bytecodeFile);
			fread(&isStatic,	sizeof(char),	1, bytecodeFile);
			fread(&aux,	sizeof(int),	1, bytecodeFile);
			//name=(char*) malloc(sizeof(char)*(aux+1));
			name=new char[aux];
			fread(name, sizeof(char), aux, bytecodeFile);

			//cout << "\tMetode: $" << name << "$" << endl;

			if (native){
				((NativeCacheClass*)cache)->addMethod(uid, name);
			} else {
				OfxCacheMethod* method=new OfxCacheMethod(uid,name,line);
				((OfxCacheClass*) cache)->addMethod(method);
				if (constructor)
					method->setConstructor(true);
				if (isStatic)
					method->setIsStatic(true);
			}
			//free(name);
			delete[] name;

			count2++;
		}//*/
		if (strcmp(cache->getName().c_str(),"Object")!=0)
			adaptador->assignClass(cache);
		count1++;
	}

	OnStartUp::registerAll(adaptador);
	adaptador->apply();

	// Reading the constants.
	count1=0;
	fseek(bytecodeFile, header.p_Constants, SEEK_SET);
	while(count1<header.n_Constants){
		int cid;
		char type;
		int itype;
		bool booleanValue;
		char characterValue;
		int integerValue;
		float floatValue;
		int stringSize;
		char* stringValue;

		fread(&type, 	sizeof(char), 	1, 	bytecodeFile);
		fread(&cid, 	sizeof(int),	1,	bytecodeFile);
		itype=type;
		//cout << "Constant " << cid << " de tipus: " << itype << " ->";
		switch (itype) {
			case 1: // Boolean
				fread(&characterValue, sizeof(char), 1, bytecodeFile);
				booleanValue=characterValue;
				data->addConstant(cid,
								  checkAndCast<BooleanClass>(data->getClass("Boolean"))->getNewInstance(booleanValue));
				//cout << booleanValue << endl;
				break;
			case 2: // Character -- Undefined
				fread(&characterValue, sizeof(char), 1, bytecodeFile);
				cerr << "Warning: Char not defined" << endl;
				//cout << characterValue << endl;
				break;
			case 3: // Integer
				fread(&integerValue, sizeof(int), 1, bytecodeFile);
				data->addConstant(cid,
								  checkAndCast<IntegerClass>(data->getClass("Integer"))->getNewInstance(integerValue));
				//cout << integerValue << endl;
				break;
			case 4: // Float
				cerr << "Warning: Float not defined" << endl;
				fread(&floatValue, sizeof(float), 1, bytecodeFile);
				//cout << floatValue << endl;
				break;
			case 5: // String
				fread(&stringSize, sizeof(int), 1, bytecodeFile);
				stringValue=new char[stringSize];
				fread(stringValue, sizeof(char), stringSize, bytecodeFile);
				//stringValue[stringSize]='\0';
				data->addConstant(cid,
								  checkAndCast<StringClass>(data->getClass("String"))->getNewInstance(stringValue));
				//cout << stringValue << endl;
				delete[] stringValue;
				break;
			default:
				break;
		}
		count1++;
	}

	bytecode=new ASM_line[header.n_ByteCode+6];

	fseek(bytecodeFile, header.p_ByteCode, SEEK_SET);
	fread(bytecode, sizeof(ASM_line), header.n_ByteCode, bytecodeFile);

	fclose(bytecodeFile);

	SuperClass* programObject=data->getClass(header.uid_programClass);

	//cout << "Debug:" << programObject->getName() << programObject->getMethod("main") << endl;
	//cout << "Debug:" << programObject->getOfxName() << programObject->getCache()->getMethodUid("main") << endl;

	bytecode[header.n_ByteCode].instruction=LOAD_CLASS;
	bytecode[header.n_ByteCode].param=header.uid_programClass;
	bytecode[header.n_ByteCode+1].instruction=LOAD_METHOD;
	bytecode[header.n_ByteCode+1].param=programObject->getMethodUid(programObject->getOfxName());
	bytecode[header.n_ByteCode+2].instruction=CALL;
	bytecode[header.n_ByteCode+2].param=0;
	bytecode[header.n_ByteCode+3].instruction=LOAD_METHOD;
	bytecode[header.n_ByteCode+3].param=programObject->getCache()->getMethod("main");
	bytecode[header.n_ByteCode+4].instruction=CALL;
	bytecode[header.n_ByteCode+4].param=0;
	bytecode[header.n_ByteCode+5].instruction=RET;
	bytecode[header.n_ByteCode+5].param-1;

	return pair<ASM_line*, int>(bytecode, header.n_ByteCode);
}

int main(int argc,char* args[]){
	clock_t start, finish;

	//RegisterClass<ShellClass> registrador;

	printf("Objective-Fenix VM\nAuthor:\n\tJaume Singla Valls\nCollaborator:\n\tFernando Arroba\n");
	//printf("%d\n", argc);
	if (argc !=2){
		printf("Usage: %s file.ofb\n", args[0]);
		exit(-1);
	}
	//Library* data=new Library();
	pair<ASM_line*, int> program=loadByteCode(args[1], Library::getLibrary());

	Thread cpu(program.first, Library::getLibrary());

	start=clock();
	cpu.run(program.second);

	finish=clock();
	//printf("Debug:\nStack Quantity: %d\n", p.top);
	printf("Time: %f\n", ((float)(finish - start)/(float)CLOCKS_PER_SEC ));

	/*printf("Desglose:");
	vector<pair<int, int> > llista=cpu.getStadistics();
	int i=0;
	for (i=0; i<llista.size(); i++){
		printf("%i=>%d times, %f seconds, %f \n", i, llista[i].first,((float)(llista[i].second)/(float)CLOCKS_PER_SEC ), ((float)(llista[i].second)/((float)CLOCKS_PER_SEC*(float)llista[i].first) ));
	}
	//*/

	return 0;
}
<commit_msg>Add a condition to check the bytecode version<commit_after>/*
 *  main.cpp
 *  vm
 *
 *  Created by dracks on 01/03/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

/**
 * @mainpage Objective Fenix - Virtual Machine
 * @author Jaume Singla Valls
 * @date 2010
 */

#include "stdlib.h"
#include "stdio.h"

#include "ASM_instructions.h"
#include "SDK/Stackable.h"
/*#include "BuiltIn/Shell.h"
#include "BuiltIn/String.h"
#include "BuiltIn/Integer.h"
#include "SDK/SuperClass.h"
#include "SDK/Super.h"
*/
#include "tools/Adapter.h"
#include "tools/Cache.h"

#include <time.h>
#include "tools.h"

#include "BuiltIn/Boolean.h"
#include "BuiltIn/Integer.h"
#include "BuiltIn/String.h"

#include "BuiltIn/Shell.h"

#include <dlfcn.h>

#ifdef _WIN32 // note the underscore: without it, it's not msdn official!
#define kLibraryExtension(name) name ".dll"
// Windows (x64 and x86)
#elif __unix__ // all unices
// Unix
#elif __posix__
// POSIX
#elif __linux__
// linux
#define kLibraryExtension(name)  name ".so"
//"
#elif __APPLE__
#define kLibraryExtension(name)  name ".dylib"
//"
// Mac OS, not sure if this is covered by __posix__ and/or __unix__ though...
#endif

using namespace SDK;
using namespace ofxBI;
using namespace ofxbytecode;
using namespace ofxtools;
//static Stackable* cache[10];

typedef struct headerSave{
	int		 ByteCodeVersion;
	int		 uid_programClass;
	long int p_Constants; // Position where found the sections.
	int		 n_Constants;
	long int p_Class;
	int		 n_Class;
	long int p_ByteCode;
	int		 n_ByteCode;
} t_HeaderSave;

/**
 * @brief load the bytecodefile, and charge all libraries
 * @param file Name of the file .ofb to load
 * @param data pointer to the library of the code
 * @return The bytecode loaded
 */
pair<ASM_line*, int> loadByteCode(string file, Library* data){
	t_HeaderSave header;
	FILE*	bytecodeFile;
	ASM_line* bytecode;
	int count1, count2;
	bytecodeFile=fopen(file.c_str(), "r");

	if (!bytecodeFile){
		cout << "ERROR file not found" << endl;
		exit(-1);
	}

	fread(&header, sizeof(headerSave), 1, bytecodeFile); // A partir d'aqui tenim la capçalera carregada
	printf("Debugging: (%d)\n", header.ByteCodeVersion);
	printf("Constants:	%d despl: %ld\n",header.n_Constants, header.p_Constants);
	printf("Class:		%d despl: %ld\n",header.n_Class, header.p_Class);
	printf("ByteCode:	%d despl: %ld\n",header.n_ByteCode, header.p_ByteCode);

	if (header.ByteCodeVersion!=1){
		cerr << "ByteCode Version is incompatible, please, compile the code with the correct version of Compiler" << endl;
		exit(-1);
	}

	void *hndl = dlopen(kLibraryExtension("./build/lib/libBuiltIn"), RTLD_NOW);
	if(hndl == NULL){
		cerr << dlerror() << endl;
		exit(-1);
	}
	//void *mkr = dlsym(hndl, "maker");*/

	Adapter* adaptador=new Adapter();

	// We read the Classes from bytecode
	count1=0;
	fseek(bytecodeFile, header.p_Class, SEEK_SET);

	while (count1<header.n_Class){
		int cid;
		int fatherUID;
		char native;
		char constructor,isStatic;
		int line;
		int aux,aux2;
		int limit2;
		char* name;
		CacheClass* cache;
		fread(&cid,		sizeof(int),	1, bytecodeFile);
		fread(&fatherUID,	sizeof(int),	1, bytecodeFile);
		fread(&native,	sizeof(char),	1, bytecodeFile);
		fread(&aux,		sizeof(int),	1, bytecodeFile);
		//name=(char*) malloc(aux*sizeof(char));
		name=new char[aux];
		fread(name,		sizeof(char),	aux,	bytecodeFile);

		if (native){
			cache=new NativeCacheClass(cid,name);
		} else {
			cache=new OfxCacheClass(cid, name, fatherUID);
		}
		//cout << "Parsejant la clase: " << name << endl;
		//free(name);
		delete[] name;

		fread(&aux2, sizeof(int), 1, bytecodeFile);
		//cout << "Propietats: " << aux2 << endl;
		count2=0;
		while (count2<aux2){
			int uid;
			fread(&uid,		sizeof(int),	1, bytecodeFile);
			fread(&aux,	sizeof(int),	1, bytecodeFile);
			//name=(char*) malloc(sizeof(char)*(aux+1));
			name=new char[aux];
			fread(name, sizeof(char), aux, bytecodeFile);
			//cout << "\tPropietat: " << name << endl;
			cache->addProperty(uid, name);

			delete[] name;
			//free(name);

			count2++;
		}

		fread(&aux2, sizeof(int), 1, bytecodeFile);
		count2=0;
		//cout << "Metodes: " << aux2 << endl;
		while (count2<aux2){
			int uid;
			fread(&uid,		sizeof(int),	1, bytecodeFile);
			fread(&line,	sizeof(int),	1, bytecodeFile);
			fread(&constructor,	sizeof(char),	1, bytecodeFile);
			fread(&isStatic,	sizeof(char),	1, bytecodeFile);
			fread(&aux,	sizeof(int),	1, bytecodeFile);
			//name=(char*) malloc(sizeof(char)*(aux+1));
			name=new char[aux];
			fread(name, sizeof(char), aux, bytecodeFile);

			//cout << "\tMetode: $" << name << "$" << endl;

			if (native){
				((NativeCacheClass*)cache)->addMethod(uid, name);
			} else {
				OfxCacheMethod* method=new OfxCacheMethod(uid,name,line);
				((OfxCacheClass*) cache)->addMethod(method);
				if (constructor)
					method->setConstructor(true);
				if (isStatic)
					method->setIsStatic(true);
			}
			//free(name);
			delete[] name;

			count2++;
		}//*/
		if (strcmp(cache->getName().c_str(),"Object")!=0)
			adaptador->assignClass(cache);
		count1++;
	}

	OnStartUp::registerAll(adaptador);
	adaptador->apply();

	// Reading the constants.
	count1=0;
	fseek(bytecodeFile, header.p_Constants, SEEK_SET);
	while(count1<header.n_Constants){
		int cid;
		char type;
		int itype;
		bool booleanValue;
		char characterValue;
		int integerValue;
		float floatValue;
		int stringSize;
		char* stringValue;

		fread(&type, 	sizeof(char), 	1, 	bytecodeFile);
		fread(&cid, 	sizeof(int),	1,	bytecodeFile);
		itype=type;
		//cout << "Constant " << cid << " de tipus: " << itype << " ->";
		switch (itype) {
			case 1: // Boolean
				fread(&characterValue, sizeof(char), 1, bytecodeFile);
				booleanValue=characterValue;
				data->addConstant(cid,
								  checkAndCast<BooleanClass>(data->getClass("Boolean"))->getNewInstance(booleanValue));
				//cout << booleanValue << endl;
				break;
			case 2: // Character -- Undefined
				fread(&characterValue, sizeof(char), 1, bytecodeFile);
				cerr << "Warning: Char not defined" << endl;
				//cout << characterValue << endl;
				break;
			case 3: // Integer
				fread(&integerValue, sizeof(int), 1, bytecodeFile);
				data->addConstant(cid,
								  checkAndCast<IntegerClass>(data->getClass("Integer"))->getNewInstance(integerValue));
				//cout << integerValue << endl;
				break;
			case 4: // Float
				cerr << "Warning: Float not defined" << endl;
				fread(&floatValue, sizeof(float), 1, bytecodeFile);
				//cout << floatValue << endl;
				break;
			case 5: // String
				fread(&stringSize, sizeof(int), 1, bytecodeFile);
				stringValue=new char[stringSize];
				fread(stringValue, sizeof(char), stringSize, bytecodeFile);
				//stringValue[stringSize]='\0';
				data->addConstant(cid,
								  checkAndCast<StringClass>(data->getClass("String"))->getNewInstance(stringValue));
				//cout << stringValue << endl;
				delete[] stringValue;
				break;
			default:
				break;
		}
		count1++;
	}

	bytecode=new ASM_line[header.n_ByteCode+6];

	fseek(bytecodeFile, header.p_ByteCode, SEEK_SET);
	fread(bytecode, sizeof(ASM_line), header.n_ByteCode, bytecodeFile);

	fclose(bytecodeFile);

	SuperClass* programObject=data->getClass(header.uid_programClass);

	//cout << "Debug:" << programObject->getName() << programObject->getMethod("main") << endl;
	//cout << "Debug:" << programObject->getOfxName() << programObject->getCache()->getMethodUid("main") << endl;

	bytecode[header.n_ByteCode].instruction=LOAD_CLASS;
	bytecode[header.n_ByteCode].param=header.uid_programClass;
	bytecode[header.n_ByteCode+1].instruction=LOAD_METHOD;
	bytecode[header.n_ByteCode+1].param=programObject->getMethodUid(programObject->getOfxName());
	bytecode[header.n_ByteCode+2].instruction=CALL;
	bytecode[header.n_ByteCode+2].param=0;
	bytecode[header.n_ByteCode+3].instruction=LOAD_METHOD;
	bytecode[header.n_ByteCode+3].param=programObject->getCache()->getMethod("main");
	bytecode[header.n_ByteCode+4].instruction=CALL;
	bytecode[header.n_ByteCode+4].param=0;
	bytecode[header.n_ByteCode+5].instruction=RET;
	bytecode[header.n_ByteCode+5].param-1;

	return pair<ASM_line*, int>(bytecode, header.n_ByteCode);
}

int main(int argc,char* args[]){
	clock_t start, finish;

	//RegisterClass<ShellClass> registrador;

	printf("Objective-Fenix VM\nAuthor:\n\tJaume Singla Valls\nCollaborator:\n\tFernando Arroba\n");
	//printf("%d\n", argc);
	if (argc !=2){
		printf("Usage: %s file.ofb\n", args[0]);
		exit(-1);
	}
	//Library* data=new Library();
	pair<ASM_line*, int> program=loadByteCode(args[1], Library::getLibrary());

	Thread cpu(program.first, Library::getLibrary());

	start=clock();
	cpu.run(program.second);

	finish=clock();
	//printf("Debug:\nStack Quantity: %d\n", p.top);
	printf("Time: %f\n", ((float)(finish - start)/(float)CLOCKS_PER_SEC ));

	/*printf("Desglose:");
	vector<pair<int, int> > llista=cpu.getStadistics();
	int i=0;
	for (i=0; i<llista.size(); i++){
		printf("%i=>%d times, %f seconds, %f \n", i, llista[i].first,((float)(llista[i].second)/(float)CLOCKS_PER_SEC ), ((float)(llista[i].second)/((float)CLOCKS_PER_SEC*(float)llista[i].first) ));
	}
	//*/

	return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    vtk2itk.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// Disable warning for long symbol names in this file only
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif
#include <iostream>
#include "itkMesh.h"
#include "itkTriangleCell.h"
#include "itkQuadrilateralCell.h"
#include "vtkDataSetWriter.h"
#include "vtkDataSetMapper.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkActor.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkDataSetReader.h"
#include "vtkUnstructuredGrid.h"
#include "vtkDataSet.h"

typedef itk::Mesh<float, 3,
  itk::DefaultStaticMeshTraits< float, 3, 3, float, float > > floatMesh;

void Display(vtkUnstructuredGrid* itkgrid, vtkUnstructuredGrid* vtkgrid)
{
// Create the renderer and window stuff
  vtkRenderer* ren1 = vtkRenderer::New();
  vtkRenderer* ren2 = vtkRenderer::New();
  vtkRenderWindow* renWin = vtkRenderWindow::New();
  renWin->AddRenderer(ren1);
  renWin->AddRenderer(ren2);
  vtkRenderWindowInteractor* inter = vtkRenderWindowInteractor::New();
  inter->SetRenderWindow(renWin);

  vtkDataSetMapper* mapper = vtkDataSetMapper::New();
  mapper->SetInput(itkgrid);
  vtkActor* actor = vtkActor::New();
  actor->SetMapper(mapper);
  vtkDataSetMapper* mapper2 = vtkDataSetMapper::New();
  mapper2->SetInput(vtkgrid);
  vtkActor* actor2 = vtkActor::New();
  actor2->SetMapper(mapper2);
  ren1->SetViewport(0.0, 0.0, 0.5, 1.0);
  ren2->SetViewport(0.5, 0.0, 1.0, 1.0);
  ren2->AddActor(actor2);
  // add the actor and start the render loop
  ren1->AddActor(actor);
  renWin->Render();
  inter->Start();

  mapper->Delete();
  actor->Delete();
  ren1->Delete();
  mapper2->Delete();
  actor2->Delete();
  ren2->Delete();
  renWin->Delete();
}

#ifndef VTK_HAS_ID_TYPE
// if you get a syntax error hear, then your VTK
// has vtkIdType already defined
typedef long vtkIdType;
#endif

floatMesh::Pointer MeshFromUnstructuredGrid(vtkUnstructuredGrid* grid)
{
  // Create a new mesh
  floatMesh::Pointer mesh(floatMesh::New());
  // Get the points from vtk
  vtkPoints* vtkpoints = grid->GetPoints();
  int numPoints = vtkpoints->GetNumberOfPoints();
  // Create a compatible point container for the mesh
  // the mesh is created with a null points container
  floatMesh::PointsContainer::Pointer points =
    floatMesh::PointsContainer::New();
  // Resize the point container to be able to fit the vtk points
  points->Reserve(numPoints);
  // Set the point container on the mesh
  mesh->SetPoints(points);
  for(int i =0; i < numPoints; i++)
    {
    float* apoint = vtkpoints->GetPoint(i);
    mesh->SetPoint(i, floatMesh::PointType(apoint));
    }
  vtkCellArray* vtkcells = grid->GetCells();
  floatMesh::CellsContainerPointer cells = floatMesh::CellsContainer::New();
  mesh->SetCells(cells);
  // extract the cell id's from the vtkUnstructuredGrid
  int numcells = vtkcells->GetNumberOfCells();
  int* vtkCellTypes = new int[numcells];
  int cellId =0;
  for(; cellId < numcells; cellId++)
    {
    vtkCellTypes[cellId] = grid->GetCellType(cellId);
    }

  cells->Reserve(numcells);
  vtkIdType npts;
  vtkIdType* pts;
  cellId = 0;
  for(vtkcells->InitTraversal(); vtkcells->GetNextCell(npts, pts); cellId++)
    {
    floatMesh::Cell::Pointer c;
    switch(vtkCellTypes[cellId])
      {
      case VTK_TRIANGLE:
        {
        itk::TriangleCell<float, floatMesh::CellTraits>::Pointer t
        = itk::TriangleCell<float, floatMesh::CellTraits>::New();
        t->SetPointIds((unsigned long*)pts);
        c = t;
        break;
        }
      case VTK_QUAD:
        {
        itk::QuadrilateralCell<float, floatMesh::CellTraits>::Pointer t
        = itk::QuadrilateralCell<float, floatMesh::CellTraits>::New();
        t->SetPointIds((unsigned long*)pts);
        c = t;
        break;
        }
      case VTK_EMPTY_CELL:
      case VTK_VERTEX:
      case VTK_POLY_VERTEX:
      case VTK_LINE:
      case VTK_POLY_LINE:
      case VTK_TRIANGLE_STRIP:
      case VTK_POLYGON:
      case VTK_PIXEL:
      case VTK_TETRA:
      case VTK_VOXEL:
      case VTK_HEXAHEDRON:
      case VTK_WEDGE:
      case VTK_PYRAMID:
      case VTK_PARAMETRIC_CURVE:
      case VTK_PARAMETRIC_SURFACE:
      default:
        std::cerr << "Warning unhandled cell type "
                  << vtkCellTypes[cellId] << std::endl;
        ;
      }
    mesh->SetCell(cellId, c);
    }

  mesh->Print(std::cout);
  return mesh;
}

class VistVTKCellsClass
{
  vtkCellArray* m_Cells;
  int* m_LastCell;
  int* m_TypeArray;
public:
  // typedef the itk cells we are interested in
  typedef itk::TriangleCell<floatMesh::PixelType,
    floatMesh::CellTraits>  floatTriangleCell;
  typedef itk::QuadrilateralCell<floatMesh::PixelType,
    floatMesh::CellTraits> floatQuadrilateralCell;

  // Set the vtkCellArray that will be constructed
  void SetCellArray(vtkCellArray* a)
    {
      m_Cells = a;
    }
  // Set the cell counter pointer
  void SetCellCounter(int* i)
    {
      m_LastCell = i;
    }
  // Set the type array for storing the vtk cell types
  void SetTypeArray(int* i)
    {
      m_TypeArray = i;
    }
  // Visit a triangle and create the VTK_TRIANGLE cell
  void Visit(unsigned long cellId, floatTriangleCell* t)
    {
      m_Cells->InsertNextCell(3,  (vtkIdType*)t->PointIdsBegin());
      m_TypeArray[*m_LastCell] = VTK_TRIANGLE;
      (*m_LastCell)++;
    }
  // Visit a triangle and create the VTK_QUAD cell
  void Visit(unsigned long cellId, floatQuadrilateralCell* t)
    {
      m_Cells->InsertNextCell(4,  (vtkIdType*)t->PointIdsBegin());
      m_TypeArray[*m_LastCell] = VTK_QUAD;
      (*m_LastCell)++;
    }
};

typedef itk::CellInterfaceVisitorImplementation<
float, floatMesh::CellTraits,
  itk::TriangleCell<floatMesh::PixelType, floatMesh::CellTraits >,
  VistVTKCellsClass> TriangleVisitor;

typedef itk::CellInterfaceVisitorImplementation<
float, floatMesh::CellTraits,
  itk::QuadrilateralCell<floatMesh::PixelType, floatMesh::CellTraits >,
  VistVTKCellsClass> QuadrilateralVisitor;

vtkUnstructuredGrid* MeshToUnstructuredGrid(floatMesh* mesh)
{
  // Get the number of points in the mesh
  int numPoints = mesh->GetNumberOfPoints();
  if(numPoints == 0)
    {
    mesh->Print(std::cerr);
    std::cerr << "no points in Grid " << std::endl;
    exit(-1);
    }
  // Create a vtkUnstructuredGrid
  vtkUnstructuredGrid* vgrid = vtkUnstructuredGrid::New();

  // Create the vtkPoints object and set the number of points
  vtkPoints* vpoints = vtkPoints::New();
  vpoints->SetNumberOfPoints(numPoints);
  // iterate over all the points in the itk mesh filling in
  // the vtkPoints object as we go
  floatMesh::PointsContainer::Pointer points = mesh->GetPoints();
  for(floatMesh::PointsContainer::Iterator i = points->Begin();
      i != points->End(); ++i)
    {
    // Get the point index from the point container iterator
    int idx = i->Index();
    // Set the vtk point at the index with the the coord array from itk
    // itk returns a const pointer, but vtk is not const correct, so
    // we have to use a const cast to get rid of the const
    vpoints->SetPoint(idx, const_cast<float*>(i->Value().GetDataPointer()));
    }
  // Set the points on the vtk grid
  vgrid->SetPoints(vpoints);

  // Now create the cells using the MulitVisitor
  // 1. Create a MultiVisitor
  floatMesh::Cell::MultiVisitor::Pointer mv =
    floatMesh::Cell::MultiVisitor::New();
  // 2. Create a triangle and quadrilateral visitor
  TriangleVisitor::Pointer tv = TriangleVisitor::New();
  QuadrilateralVisitor::Pointer qv =  QuadrilateralVisitor::New();
  // 3. Set up the visitors
  int vtkCellCount = 0; // running counter for current cell being inserted into vtk
  int numCells = mesh->GetNumberOfCells();
  int *types = new int[numCells]; // type array for vtk
  // create vtk cells and estimate the size
  vtkCellArray* cells = vtkCellArray::New();
  cells->EstimateSize(numCells, 4);
  // Set the TypeArray CellCount and CellArray for both visitors
  tv->SetTypeArray(types);
  tv->SetCellCounter(&vtkCellCount);
  tv->SetCellArray(cells);
  qv->SetTypeArray(types);
  qv->SetCellCounter(&vtkCellCount);
  qv->SetCellArray(cells);
  // add the visitors to the multivisitor
  mv->AddVisitor(tv);
  mv->AddVisitor(qv);
  // Now ask the mesh to accept the multivisitor which
  // will Call Visit for each cell in the mesh that matches the
  // cell types of the visitors added to the MultiVisitor
  mesh->Accept(mv);

  // Now set the cells on the vtk grid with the type array and cell array
  vgrid->SetCells(types, cells);

  // Clean up vtk objects (no vtkSmartPointer ... )
  cells->Delete();
  vpoints->Delete();
  // return the vtkUnstructuredGrid
  return vgrid;
}

int main(int ac, char** av)
{
  const char* fname = "c:/blow.vtk";
  if(ac > 1 )
    {
    fname = av[1];
    }

  vtkDataSetReader* reader = vtkDataSetReader::New();
  reader->SetFileName(fname);
  reader->SetScalarsName("thickness9");
  reader->SetVectorsName("displacement9");
  std::cerr << "Begin reading vtk data " << std::endl;
  reader->Update();
  std::cerr << "End reading vtk data " << std::endl;
  vtkDataSet* data = reader->GetOutput();
  // Convert from vtk to itk
  std::cerr << "Begin conversion to itkMesh " << std::endl;
  floatMesh::Pointer m =
    MeshFromUnstructuredGrid(reader->GetUnstructuredGridOutput());
  std::cerr << "End conversion to itkMesh " << std::endl;
  // Convert back from itk to vtk
  std::cerr << "Begin conversion to vtkUnstructuredGrid " << std::endl;
  vtkUnstructuredGrid* grid = MeshToUnstructuredGrid(m);
  std::cerr << "End conversion to vtkUnstructuredGrid " << std::endl;

  std::cerr << "Begin vtk dispaly of both grids " << std::endl;
  Display(grid, reader->GetUnstructuredGridOutput());
  vtkDataSetWriter* writer = vtkDataSetWriter::New();
  writer->SetInput(grid);
  writer->SetFileName("./itkblow.vtk");
  writer->Update();
#ifdef VTK_USE_ANSI_STDLIB
  grid->Print(std::cout);
#endif
  reader->Delete();
  grid->Delete();
  return 0;
}

<commit_msg>ENH: Mesh cells are now templated over the CellInterface type.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    vtk2itk.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
// Disable warning for long symbol names in this file only
#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif
#include <iostream>
#include "itkMesh.h"
#include "itkTriangleCell.h"
#include "itkQuadrilateralCell.h"
#include "vtkDataSetWriter.h"
#include "vtkDataSetMapper.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkActor.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkDataSetReader.h"
#include "vtkUnstructuredGrid.h"
#include "vtkDataSet.h"

typedef itk::Mesh<float, 3,
  itk::DefaultStaticMeshTraits< float, 3, 3, float, float > > floatMesh;

void Display(vtkUnstructuredGrid* itkgrid, vtkUnstructuredGrid* vtkgrid)
{
// Create the renderer and window stuff
  vtkRenderer* ren1 = vtkRenderer::New();
  vtkRenderer* ren2 = vtkRenderer::New();
  vtkRenderWindow* renWin = vtkRenderWindow::New();
  renWin->AddRenderer(ren1);
  renWin->AddRenderer(ren2);
  vtkRenderWindowInteractor* inter = vtkRenderWindowInteractor::New();
  inter->SetRenderWindow(renWin);

  vtkDataSetMapper* mapper = vtkDataSetMapper::New();
  mapper->SetInput(itkgrid);
  vtkActor* actor = vtkActor::New();
  actor->SetMapper(mapper);
  vtkDataSetMapper* mapper2 = vtkDataSetMapper::New();
  mapper2->SetInput(vtkgrid);
  vtkActor* actor2 = vtkActor::New();
  actor2->SetMapper(mapper2);
  ren1->SetViewport(0.0, 0.0, 0.5, 1.0);
  ren2->SetViewport(0.5, 0.0, 1.0, 1.0);
  ren2->AddActor(actor2);
  // add the actor and start the render loop
  ren1->AddActor(actor);
  renWin->Render();
  inter->Start();

  mapper->Delete();
  actor->Delete();
  ren1->Delete();
  mapper2->Delete();
  actor2->Delete();
  ren2->Delete();
  renWin->Delete();
}

#ifndef VTK_HAS_ID_TYPE
// if you get a syntax error hear, then your VTK
// has vtkIdType already defined
typedef long vtkIdType;
#endif

floatMesh::Pointer MeshFromUnstructuredGrid(vtkUnstructuredGrid* grid)
{
  // Create a new mesh
  floatMesh::Pointer mesh(floatMesh::New());
  // Get the points from vtk
  vtkPoints* vtkpoints = grid->GetPoints();
  int numPoints = vtkpoints->GetNumberOfPoints();
  // Create a compatible point container for the mesh
  // the mesh is created with a null points container
  floatMesh::PointsContainer::Pointer points =
    floatMesh::PointsContainer::New();
  // Resize the point container to be able to fit the vtk points
  points->Reserve(numPoints);
  // Set the point container on the mesh
  mesh->SetPoints(points);
  for(int i =0; i < numPoints; i++)
    {
    float* apoint = vtkpoints->GetPoint(i);
    mesh->SetPoint(i, floatMesh::PointType(apoint));
    }
  vtkCellArray* vtkcells = grid->GetCells();
  floatMesh::CellsContainerPointer cells = floatMesh::CellsContainer::New();
  mesh->SetCells(cells);
  // extract the cell id's from the vtkUnstructuredGrid
  int numcells = vtkcells->GetNumberOfCells();
  int* vtkCellTypes = new int[numcells];
  int cellId =0;
  for(; cellId < numcells; cellId++)
    {
    vtkCellTypes[cellId] = grid->GetCellType(cellId);
    }

  cells->Reserve(numcells);
  vtkIdType npts;
  vtkIdType* pts;
  cellId = 0;
  for(vtkcells->InitTraversal(); vtkcells->GetNextCell(npts, pts); cellId++)
    {
    floatMesh::Cell::Pointer c;
    switch(vtkCellTypes[cellId])
      {
      case VTK_TRIANGLE:
        {
        typedef itk::CellInterface<float, floatMesh::CellTraits> CellInterfaceType;
        typedef itk::TriangleCell<CellInterfaceType> TriangleCellType;
        TriangleCellType::Pointer t = TriangleCellType::New();
        t->SetPointIds((unsigned long*)pts);
        c = t;
        break;
        }
      case VTK_QUAD:
        {
        typedef itk::CellInterface<float, floatMesh::CellTraits> CellInterfaceType;
        typedef itk::QuadrilateralCell<CellInterfaceType> QuadrilateralCellType;
        QuadrilateralCellType::Pointer t = QuadrilateralCellType::New();
        t->SetPointIds((unsigned long*)pts);
        c = t;
        break;
        }
      case VTK_EMPTY_CELL:
      case VTK_VERTEX:
      case VTK_POLY_VERTEX:
      case VTK_LINE:
      case VTK_POLY_LINE:
      case VTK_TRIANGLE_STRIP:
      case VTK_POLYGON:
      case VTK_PIXEL:
      case VTK_TETRA:
      case VTK_VOXEL:
      case VTK_HEXAHEDRON:
      case VTK_WEDGE:
      case VTK_PYRAMID:
      case VTK_PARAMETRIC_CURVE:
      case VTK_PARAMETRIC_SURFACE:
      default:
        std::cerr << "Warning unhandled cell type "
                  << vtkCellTypes[cellId] << std::endl;
        ;
      }
    mesh->SetCell(cellId, c);
    }

  mesh->Print(std::cout);
  return mesh;
}

class VistVTKCellsClass
{
  vtkCellArray* m_Cells;
  int* m_LastCell;
  int* m_TypeArray;
public:
  // typedef the itk cells we are interested in
  typedef itk::CellInterface<
                      floatMesh::PixelType,
                      floatMesh::CellTraits >  CellInterfaceType;

  typedef itk::TriangleCell<CellInterfaceType>      floatTriangleCell;
  typedef itk::QuadrilateralCell<CellInterfaceType> floatQuadrilateralCell;

  // Set the vtkCellArray that will be constructed
  void SetCellArray(vtkCellArray* a)
    {
      m_Cells = a;
    }
  // Set the cell counter pointer
  void SetCellCounter(int* i)
    {
      m_LastCell = i;
    }
  // Set the type array for storing the vtk cell types
  void SetTypeArray(int* i)
    {
      m_TypeArray = i;
    }
  // Visit a triangle and create the VTK_TRIANGLE cell
  void Visit(unsigned long cellId, floatTriangleCell* t)
    {
      m_Cells->InsertNextCell(3,  (vtkIdType*)t->PointIdsBegin());
      m_TypeArray[*m_LastCell] = VTK_TRIANGLE;
      (*m_LastCell)++;
    }
  // Visit a triangle and create the VTK_QUAD cell
  void Visit(unsigned long cellId, floatQuadrilateralCell* t)
    {
      m_Cells->InsertNextCell(4,  (vtkIdType*)t->PointIdsBegin());
      m_TypeArray[*m_LastCell] = VTK_QUAD;
      (*m_LastCell)++;
    }
};

typedef itk::CellInterfaceVisitorImplementation<
float, floatMesh::CellTraits,
  itk::TriangleCell< itk::CellInterface<floatMesh::PixelType, floatMesh::CellTraits > >,
  VistVTKCellsClass> TriangleVisitor;

typedef itk::CellInterfaceVisitorImplementation<
float, floatMesh::CellTraits,
  itk::QuadrilateralCell< itk::CellInterface<floatMesh::PixelType, floatMesh::CellTraits > >,
  VistVTKCellsClass> QuadrilateralVisitor;

vtkUnstructuredGrid* MeshToUnstructuredGrid(floatMesh* mesh)
{
  // Get the number of points in the mesh
  int numPoints = mesh->GetNumberOfPoints();
  if(numPoints == 0)
    {
    mesh->Print(std::cerr);
    std::cerr << "no points in Grid " << std::endl;
    exit(-1);
    }
  // Create a vtkUnstructuredGrid
  vtkUnstructuredGrid* vgrid = vtkUnstructuredGrid::New();

  // Create the vtkPoints object and set the number of points
  vtkPoints* vpoints = vtkPoints::New();
  vpoints->SetNumberOfPoints(numPoints);
  // iterate over all the points in the itk mesh filling in
  // the vtkPoints object as we go
  floatMesh::PointsContainer::Pointer points = mesh->GetPoints();
  for(floatMesh::PointsContainer::Iterator i = points->Begin();
      i != points->End(); ++i)
    {
    // Get the point index from the point container iterator
    int idx = i->Index();
    // Set the vtk point at the index with the the coord array from itk
    // itk returns a const pointer, but vtk is not const correct, so
    // we have to use a const cast to get rid of the const
    vpoints->SetPoint(idx, const_cast<float*>(i->Value().GetDataPointer()));
    }
  // Set the points on the vtk grid
  vgrid->SetPoints(vpoints);

  // Now create the cells using the MulitVisitor
  // 1. Create a MultiVisitor
  floatMesh::Cell::MultiVisitor::Pointer mv =
    floatMesh::Cell::MultiVisitor::New();
  // 2. Create a triangle and quadrilateral visitor
  TriangleVisitor::Pointer tv = TriangleVisitor::New();
  QuadrilateralVisitor::Pointer qv =  QuadrilateralVisitor::New();
  // 3. Set up the visitors
  int vtkCellCount = 0; // running counter for current cell being inserted into vtk
  int numCells = mesh->GetNumberOfCells();
  int *types = new int[numCells]; // type array for vtk
  // create vtk cells and estimate the size
  vtkCellArray* cells = vtkCellArray::New();
  cells->EstimateSize(numCells, 4);
  // Set the TypeArray CellCount and CellArray for both visitors
  tv->SetTypeArray(types);
  tv->SetCellCounter(&vtkCellCount);
  tv->SetCellArray(cells);
  qv->SetTypeArray(types);
  qv->SetCellCounter(&vtkCellCount);
  qv->SetCellArray(cells);
  // add the visitors to the multivisitor
  mv->AddVisitor(tv);
  mv->AddVisitor(qv);
  // Now ask the mesh to accept the multivisitor which
  // will Call Visit for each cell in the mesh that matches the
  // cell types of the visitors added to the MultiVisitor
  mesh->Accept(mv);

  // Now set the cells on the vtk grid with the type array and cell array
  vgrid->SetCells(types, cells);

  // Clean up vtk objects (no vtkSmartPointer ... )
  cells->Delete();
  vpoints->Delete();
  // return the vtkUnstructuredGrid
  return vgrid;
}

int main(int ac, char** av)
{
  const char* fname = "c:/blow.vtk";
  if(ac > 1 )
    {
    fname = av[1];
    }

  vtkDataSetReader* reader = vtkDataSetReader::New();
  reader->SetFileName(fname);
  reader->SetScalarsName("thickness9");
  reader->SetVectorsName("displacement9");
  std::cerr << "Begin reading vtk data " << std::endl;
  reader->Update();
  std::cerr << "End reading vtk data " << std::endl;
  vtkDataSet* data = reader->GetOutput();
  // Convert from vtk to itk
  std::cerr << "Begin conversion to itkMesh " << std::endl;
  floatMesh::Pointer m =
    MeshFromUnstructuredGrid(reader->GetUnstructuredGridOutput());
  std::cerr << "End conversion to itkMesh " << std::endl;
  // Convert back from itk to vtk
  std::cerr << "Begin conversion to vtkUnstructuredGrid " << std::endl;
  vtkUnstructuredGrid* grid = MeshToUnstructuredGrid(m);
  std::cerr << "End conversion to vtkUnstructuredGrid " << std::endl;

  std::cerr << "Begin vtk dispaly of both grids " << std::endl;
  Display(grid, reader->GetUnstructuredGridOutput());
  vtkDataSetWriter* writer = vtkDataSetWriter::New();
  writer->SetInput(grid);
  writer->SetFileName("./itkblow.vtk");
  writer->Update();
#ifdef VTK_USE_ANSI_STDLIB
  grid->Print(std::cout);
#endif
  reader->Delete();
  grid->Delete();
  return 0;
}

<|endoftext|>