<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_EVALUATOR_HPP
#define ETL_EVALUATOR_HPP

#include "traits_lite.hpp"   //forward declaration of the traits
#include "visitor.hpp"   //forward declaration of the traits

namespace etl {

namespace detail {

struct temporary_allocator_static_visitor : etl_visitor<temporary_allocator_static_visitor> {
    template<typename E>
    using enabled = cpp::bool_constant<decay_traits<E>::needs_temporary_visitor>;

    using etl_visitor<temporary_allocator_static_visitor>::operator();

    template <typename T, typename AExpr, typename Op, typename Forced>
    void operator()(etl::temporary_unary_expr<T, AExpr, Op, Forced>& v) const {
        v.allocate_temporary();

        (*this)(v.a());
    }

    template <typename T, typename AExpr, typename BExpr, typename Op, typename Forced>
    void operator()(etl::temporary_binary_expr<T, AExpr, BExpr, Op, Forced>& v) const {
        v.allocate_temporary();

        (*this)(v.a());
        (*this)(v.b());
    }
};

struct evaluator_static_visitor : etl_visitor<evaluator_static_visitor> {
    template<typename E>
    using enabled = cpp::bool_constant<decay_traits<E>::needs_evaluator_visitor>;

    using etl_visitor<evaluator_static_visitor>::operator();

    template <typename T, typename AExpr, typename Op, typename Forced>
    void operator()(etl::temporary_unary_expr<T, AExpr, Op, Forced>& v) const {
        (*this)(v.a());

        v.evaluate();
    }

    template <typename T, typename AExpr, typename BExpr, typename Op, typename Forced>
    void operator()(etl::temporary_binary_expr<T, AExpr, BExpr, Op, Forced>& v) const {
        (*this)(v.a());
        (*this)(v.b());

        v.evaluate();
    }
};

} //end of namespace detail

template<typename Expr, typename Result>
struct standard_evaluator {
    template<typename E>
    static void evaluate_only(E&& expr){
        apply_visitor<detail::temporary_allocator_static_visitor>(expr);
        apply_visitor<detail::evaluator_static_visitor>(expr);
    }

    template<typename E, typename R>
    struct vectorized_assign : cpp::and_u<
        vectorize_expr,
        decay_traits<E>::vectorizable,
        intrinsic_traits<value_t<R>>::vectorizable, intrinsic_traits<value_t<E>>::vectorizable,
        std::is_same<typename intrinsic_traits<value_t<R>>::intrinsic_type, typename intrinsic_traits<value_t<E>>::intrinsic_type>::value> {};

    template<typename E, typename R, cpp_enable_if(!vectorized_assign<E, R>::value && has_direct_access<R>::value && !is_temporary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        auto m = result.memory_start();

        const std::size_t size = etl::size(result);

        std::size_t iend = 0;

        if(unroll_normal_loops){
            iend = size & std::size_t(-4);

            for(std::size_t i = 0; i < iend; i += 4){
                m[i] = expr[i];
                m[i+1] = expr[i+1];
                m[i+2] = expr[i+2];
                m[i+3] = expr[i+3];
            }
        }

        for(std::size_t i = iend; i < size; ++i){
            m[i] = expr[i];
        }
    }

    template<typename E, typename R, cpp_enable_if(!vectorized_assign<E, R>::value && !has_direct_access<R>::value && !is_temporary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        const std::size_t size = etl::size(result);

        for(std::size_t i = 0; i < size; ++i){
            result[i] = expr[i];
        }
    }

    template<typename E, typename R, cpp_enable_if(vectorized_assign<E, R>::value && !is_temporary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        using IT = intrinsic_traits<value_t<E>>;

        auto m = result.memory_start();

        const std::size_t size = etl::size(result);

        std::size_t i = 0;

        //1. Peel loop

        constexpr const auto size_1 = sizeof(value_t<E>);
        auto u_bytes = (reinterpret_cast<uintptr_t>(m) % IT::alignment);

        if(u_bytes >= size_1 && u_bytes % size_1 == 0){
            auto u_loads = std::min(u_bytes & -size_1, size);

            for(; i < u_loads; ++i){
                m[i] = expr[i];
            }
        }

        //2. Vectorized loop

        if(size - i >= IT::size){
            if(reinterpret_cast<uintptr_t>(m + i) % IT::alignment == 0){
                if(unroll_vectorized_loops && size - i > IT::size * 4){
                    for(; i + IT::size * 4 - 1 < size; i += IT::size * 4){
                        vec::store(m + i, expr.load(i));
                        vec::store(m + i + 1 * IT::size, expr.load(i + 1 * IT::size));
                        vec::store(m + i + 2 * IT::size, expr.load(i + 2 * IT::size));
                        vec::store(m + i + 3 * IT::size, expr.load(i + 3 * IT::size));
                    }
                } else {
                    for(; i + IT::size  - 1 < size; i += IT::size){
                        vec::store(m + i, expr.load(i));
                    }
                }
            } else {
                if(unroll_vectorized_loops && size - i > IT::size * 4){
                    for(; i + IT::size * 4 - 1 < size; i += IT::size * 4){
                        vec::storeu(m + i, expr.load(i));
                        vec::storeu(m + i + 1 * IT::size, expr.load(i + 1 * IT::size));
                        vec::storeu(m + i + 2 * IT::size, expr.load(i + 2 * IT::size));
                        vec::storeu(m + i + 3 * IT::size, expr.load(i + 3 * IT::size));
                    }
                } else {
                    for(; i + IT::size  - 1 < size; i += IT::size){
                        vec::storeu(m + i, expr.load(i));
                    }
                }
            }
        }

        //3. Remainder loop

        //Finish the iterations in a non-vectorized fashion
        for(; i < size; ++i){
            m[i] = expr[i];
        }
    }

    template<typename E, typename R, cpp_disable_if(is_temporary_expr<E>::value)>
    static void add_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] += expr[i];
        }
    }

    template<typename E, typename R, cpp_disable_if(is_temporary_expr<E>::value)>
    static void sub_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] -= expr[i];
        }
    }

    template<typename E, typename R, cpp_disable_if(is_temporary_expr<E>::value)>
    static void mul_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] *= expr[i];
        }
    }

    template<typename E, typename R, cpp_disable_if(is_temporary_expr<E>::value)>
    static void div_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] /= expr[i];
        }
    }

    template<typename E, typename R, cpp_disable_if(is_temporary_expr<E>::value)>
    static void mod_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] %= expr[i];
        }
    }

    //Note: In case of direct evaluation, the temporary_expr itself must
    //not beevaluated by the static_visitor, otherwise, the result would
    //be evaluated twice and a temporary would be allocated for nothing

    template<typename E, typename R, cpp_enable_if(is_temporary_unary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        apply_visitor<detail::temporary_allocator_static_visitor>(expr.a());
        apply_visitor<detail::evaluator_static_visitor>(expr.a());

        expr.direct_evaluate(result);
    }

    template<typename E, typename R, cpp_enable_if(is_temporary_binary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        apply_visitor<detail::temporary_allocator_static_visitor>(expr.a());
        apply_visitor<detail::temporary_allocator_static_visitor>(expr.b());

        apply_visitor<detail::evaluator_static_visitor>(expr.a());
        apply_visitor<detail::evaluator_static_visitor>(expr.b());

        expr.direct_evaluate(result);
    }
};

//Only containers of the same storage order can be assigned directly
//Generators can be assigned to everything
template<typename Expr, typename Result>
struct direct_assign_compatible : cpp::or_u<
    decay_traits<Expr>::is_generator,
    decay_traits<Expr>::storage_order == decay_traits<Result>::storage_order> {};

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void assign_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::assign_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void assign_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::assign_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void add_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::add_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void add_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::add_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void sub_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::sub_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void sub_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::sub_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void mul_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mul_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void mul_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mul_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void div_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::div_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void div_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::div_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void mod_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mod_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void mod_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mod_evaluate(transpose(expr), std::forward<Result>(result));
}

/*!
 * \brief Force the internal evaluation of an expression
 * \param expr The expression to force inner evaluation
 *
 * This function can be used when complex expressions are used
 * lazily.
 */
template<typename Expr>
void force(Expr&& expr){
    standard_evaluator<Expr, void>::evaluate_only(std::forward<Expr>(expr));
}

} //end of namespace etl

#endif
<commit_msg>Improve support for compound assignment<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifndef ETL_EVALUATOR_HPP
#define ETL_EVALUATOR_HPP

#include "traits_lite.hpp"   //forward declaration of the traits
#include "visitor.hpp"   //forward declaration of the traits

namespace etl {

namespace detail {

struct temporary_allocator_static_visitor : etl_visitor<temporary_allocator_static_visitor> {
    template<typename E>
    using enabled = cpp::bool_constant<decay_traits<E>::needs_temporary_visitor>;

    using etl_visitor<temporary_allocator_static_visitor>::operator();

    template <typename T, typename AExpr, typename Op, typename Forced>
    void operator()(etl::temporary_unary_expr<T, AExpr, Op, Forced>& v) const {
        v.allocate_temporary();

        (*this)(v.a());
    }

    template <typename T, typename AExpr, typename BExpr, typename Op, typename Forced>
    void operator()(etl::temporary_binary_expr<T, AExpr, BExpr, Op, Forced>& v) const {
        v.allocate_temporary();

        (*this)(v.a());
        (*this)(v.b());
    }
};

struct evaluator_static_visitor : etl_visitor<evaluator_static_visitor> {
    template<typename E>
    using enabled = cpp::bool_constant<decay_traits<E>::needs_evaluator_visitor>;

    using etl_visitor<evaluator_static_visitor>::operator();

    template <typename T, typename AExpr, typename Op, typename Forced>
    void operator()(etl::temporary_unary_expr<T, AExpr, Op, Forced>& v) const {
        (*this)(v.a());

        v.evaluate();
    }

    template <typename T, typename AExpr, typename BExpr, typename Op, typename Forced>
    void operator()(etl::temporary_binary_expr<T, AExpr, BExpr, Op, Forced>& v) const {
        (*this)(v.a());
        (*this)(v.b());

        v.evaluate();
    }
};

} //end of namespace detail

template<typename Expr, typename Result>
struct standard_evaluator {
    template<typename E>
    static void evaluate_only(E&& expr){
        apply_visitor<detail::temporary_allocator_static_visitor>(expr);
        apply_visitor<detail::evaluator_static_visitor>(expr);
    }

    template<typename E, typename R>
    struct vectorized_assign : cpp::and_u<
        vectorize_expr,
        decay_traits<E>::vectorizable,
        intrinsic_traits<value_t<R>>::vectorizable, intrinsic_traits<value_t<E>>::vectorizable,
        std::is_same<typename intrinsic_traits<value_t<R>>::intrinsic_type, typename intrinsic_traits<value_t<E>>::intrinsic_type>::value> {};

    template<typename E, typename R, cpp_enable_if(!vectorized_assign<E, R>::value && has_direct_access<R>::value && !is_temporary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        auto m = result.memory_start();

        const std::size_t size = etl::size(result);

        std::size_t iend = 0;

        if(unroll_normal_loops){
            iend = size & std::size_t(-4);

            for(std::size_t i = 0; i < iend; i += 4){
                m[i] = expr[i];
                m[i+1] = expr[i+1];
                m[i+2] = expr[i+2];
                m[i+3] = expr[i+3];
            }
        }

        for(std::size_t i = iend; i < size; ++i){
            m[i] = expr[i];
        }
    }

    template<typename E, typename R, cpp_enable_if(!vectorized_assign<E, R>::value && !has_direct_access<R>::value && !is_temporary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        const std::size_t size = etl::size(result);

        for(std::size_t i = 0; i < size; ++i){
            result[i] = expr[i];
        }
    }

    template<typename E, typename R, cpp_enable_if(vectorized_assign<E, R>::value && !is_temporary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        using IT = intrinsic_traits<value_t<E>>;

        auto m = result.memory_start();

        const std::size_t size = etl::size(result);

        std::size_t i = 0;

        //1. Peel loop

        constexpr const auto size_1 = sizeof(value_t<E>);
        auto u_bytes = (reinterpret_cast<uintptr_t>(m) % IT::alignment);

        if(u_bytes >= size_1 && u_bytes % size_1 == 0){
            auto u_loads = std::min(u_bytes & -size_1, size);

            for(; i < u_loads; ++i){
                m[i] = expr[i];
            }
        }

        //2. Vectorized loop

        if(size - i >= IT::size){
            if(reinterpret_cast<uintptr_t>(m + i) % IT::alignment == 0){
                if(unroll_vectorized_loops && size - i > IT::size * 4){
                    for(; i + IT::size * 4 - 1 < size; i += IT::size * 4){
                        vec::store(m + i, expr.load(i));
                        vec::store(m + i + 1 * IT::size, expr.load(i + 1 * IT::size));
                        vec::store(m + i + 2 * IT::size, expr.load(i + 2 * IT::size));
                        vec::store(m + i + 3 * IT::size, expr.load(i + 3 * IT::size));
                    }
                } else {
                    for(; i + IT::size  - 1 < size; i += IT::size){
                        vec::store(m + i, expr.load(i));
                    }
                }
            } else {
                if(unroll_vectorized_loops && size - i > IT::size * 4){
                    for(; i + IT::size * 4 - 1 < size; i += IT::size * 4){
                        vec::storeu(m + i, expr.load(i));
                        vec::storeu(m + i + 1 * IT::size, expr.load(i + 1 * IT::size));
                        vec::storeu(m + i + 2 * IT::size, expr.load(i + 2 * IT::size));
                        vec::storeu(m + i + 3 * IT::size, expr.load(i + 3 * IT::size));
                    }
                } else {
                    for(; i + IT::size  - 1 < size; i += IT::size){
                        vec::storeu(m + i, expr.load(i));
                    }
                }
            }
        }

        //3. Remainder loop

        //Finish the iterations in a non-vectorized fashion
        for(; i < size; ++i){
            m[i] = expr[i];
        }
    }

    template<typename E, typename R>
    static void add_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] += expr[i];
        }
    }

    template<typename E, typename R>
    static void sub_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] -= expr[i];
        }
    }

    template<typename E, typename R>
    static void mul_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] *= expr[i];
        }
    }

    template<typename E, typename R>
    static void div_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] /= expr[i];
        }
    }

    template<typename E, typename R>
    static void mod_evaluate(E&& expr, R&& result){
        evaluate_only(expr);

        for(std::size_t i = 0; i < etl::size(result); ++i){
            result[i] %= expr[i];
        }
    }

    //Note: In case of direct evaluation, the temporary_expr itself must
    //not beevaluated by the static_visitor, otherwise, the result would
    //be evaluated twice and a temporary would be allocated for nothing

    template<typename E, typename R, cpp_enable_if(is_temporary_unary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        apply_visitor<detail::temporary_allocator_static_visitor>(expr.a());
        apply_visitor<detail::evaluator_static_visitor>(expr.a());

        expr.direct_evaluate(result);
    }

    template<typename E, typename R, cpp_enable_if(is_temporary_binary_expr<E>::value)>
    static void assign_evaluate(E&& expr, R&& result){
        apply_visitor<detail::temporary_allocator_static_visitor>(expr.a());
        apply_visitor<detail::temporary_allocator_static_visitor>(expr.b());

        apply_visitor<detail::evaluator_static_visitor>(expr.a());
        apply_visitor<detail::evaluator_static_visitor>(expr.b());

        expr.direct_evaluate(result);
    }
};

//Only containers of the same storage order can be assigned directly
//Generators can be assigned to everything
template<typename Expr, typename Result>
struct direct_assign_compatible : cpp::or_u<
    decay_traits<Expr>::is_generator,
    decay_traits<Expr>::storage_order == decay_traits<Result>::storage_order> {};

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void assign_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::assign_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void assign_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::assign_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void add_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::add_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void add_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::add_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void sub_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::sub_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void sub_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::sub_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void mul_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mul_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void mul_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mul_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void div_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::div_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void div_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::div_evaluate(transpose(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_enable_if(direct_assign_compatible<Expr, Result>::value)>
void mod_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mod_evaluate(std::forward<Expr>(expr), std::forward<Result>(result));
}

template<typename Expr, typename Result, cpp_disable_if(direct_assign_compatible<Expr, Result>::value)>
void mod_evaluate(Expr&& expr, Result&& result){
    standard_evaluator<Expr, Result>::mod_evaluate(transpose(expr), std::forward<Result>(result));
}

/*!
 * \brief Force the internal evaluation of an expression
 * \param expr The expression to force inner evaluation
 *
 * This function can be used when complex expressions are used
 * lazily.
 */
template<typename Expr>
void force(Expr&& expr){
    standard_evaluator<Expr, void>::evaluate_only(std::forward<Expr>(expr));
}

} //end of namespace etl

#endif
<|endoftext|>


<commit_before>#ifndef HELLOBYEPROTO_HPP
#define HELLOBYEPROTO_HPP

#include "stateMachine.hpp"

template <class Identifier, class Packet> class HelloByeServerHello {
	using SM = StateMachine<Identifier, Packet>;

private:
	int clientCookie;
	int serverCookie;

public:
	HelloByeServerHello();

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeServerHello *t = reinterpret_cast<HelloByeServerHello *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

template <class Identifier, class Packet> class HelloByeServerBye {
	using SM = StateMachine<Identifier, Packet>;

private:
	int clientCookie;
	int serverCookie;

public:
	HelloByeServerBye();

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeServerBye *t = reinterpret_cast<HelloByeServerBye *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

template <class Identifier, class Packet> class HelloByeClientHello {
	using SM = StateMachine<Identifier, Packet>;
	friend class HelloByeServerBye<Identifier, Packet>;

private:
	int clientCookie;

public:
	HelloByeClientHello();

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeClientHello *t = reinterpret_cast<HelloByeClientHello *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

template <class Identifier, class Packet> class HelloByeClientBye {
	using SM = StateMachine<Identifier, Packet>;

private:
	int clientCookie;
	int serverCookie;

public:
	HelloByeClientBye();
	HelloByeClientBye(const HelloByeClientHello<Identifier,Packet>& h);

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeClientBye *t = reinterpret_cast<HelloByeClientBye *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

#endif /* HELLOBYEPROTO_HPP */
<commit_msg>more HelloBye Header code<commit_after>#ifndef HELLOBYEPROTO_HPP
#define HELLOBYEPROTO_HPP

#include "common.hpp"
#include "stateMachine.hpp"

enum class HelloByeServer : StateID {
	Hello,
	Bye,
	Terminate,
};

enum class HelloByeClient : StateID {
	Hello,
	Bye,
	Terminate,
};

template <class Identifier, class Packet> class HelloByeServerHello;
template <class Identifier, class Packet> class HelloByeServerBye;
template <class Identifier, class Packet> class HelloByeClientHello;
template <class Identifier, class Packet> class HelloByeClientBye;

template <class Identifier, class Packet> class HelloByeServerHello {
	using SM = StateMachine<Identifier, Packet>;

private:
	int clientCookie;
	int serverCookie;

public:
	HelloByeServerHello();

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeServerHello *t = reinterpret_cast<HelloByeServerHello *>(state.stateData);
		t->fun(state, pkt, funIface);

		// Finish transision to other state
		if(state.state == HelloByeServer::Bye){
			state.stateData = new HelloByeServerBye<Identifier,Packet>(t);
			delete(t);
		} else if(state.state == HelloByeServer::Terminate){
			delete(t);
		}
	}
};

template <class Identifier, class Packet> class HelloByeServerBye {
	using SM = StateMachine<Identifier, Packet>;

private:
	int clientCookie;
	int serverCookie;

public:
	HelloByeServerBye(const HelloByeServerHello<Identifier, Packet> &in);

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeServerBye *t = reinterpret_cast<HelloByeServerBye *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

template <class Identifier, class Packet> class HelloByeClientHello {
	using SM = StateMachine<Identifier, Packet>;
	friend class HelloByeClientBye<Identifier, Packet>;

private:
	int clientCookie;

public:
	HelloByeClientHello();

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeClientHello *t = reinterpret_cast<HelloByeClientHello *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

template <class Identifier, class Packet> class HelloByeClientBye {
	using SM = StateMachine<Identifier, Packet>;

private:
	int clientCookie;
	int serverCookie;

public:
	HelloByeClientBye(const HelloByeClientHello<Identifier, Packet> &h);

	__attribute__((always_inline)) void fun(
		typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface);

	static void run(typename SM::State &state, Packet *pkt, typename SM::FunIface &funIface) {
		HelloByeClientBye *t = reinterpret_cast<HelloByeClientBye *>(state.stateData);
		t->fun(state, pkt, funIface);
	}
};

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


<commit_before>/*
 * Copyright (C) 2009-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file kernel/userver.hh
/// \brief Definition of the UServer class.

#ifndef KERNEL_USERVER_HH
# define KERNEL_USERVER_HH

# include <memory>
# include <sstream>

# include <libport/config.h>
# include <libport/attributes.hh>

# if LIBPORT_HAVE_WINDOWS_H
// Without this, windows.h may include winsock.h, which will conflict with
// winsock2.h when we will try to include it.
#  define WIN32_LEAN_AND_MEAN
# endif

# include <libport/fwd.hh>
# include <libport/compiler.hh>
# include <libport/file-library.hh>
# include <libport/lockable.hh>
# include <libport/ufloat.h>
# include <libport/utime.hh>
# include <libport/pthread.h>

#include <sched/scheduler.hh>

# include <kernel/fwd.hh>
# include <kernel/utypes.hh>
# include <urbi/export.hh>
# include <urbi/object/object.hh>
# include <urbi/urbi-root.hh>

namespace kernel
{
  /// Global variable for the server
  extern URBI_SDK_API class UServer* urbiserver;

  /// The current server.
  UServer& server();

  /// Convenience wrapper to get urbiserver's current runner.
  runner::Runner& runner();

  /// Convenience wrapper to get urbiserver's current interpreter.
  runner::Interpreter& interpreter();

  /// Convenience wrapper for Logger objects, to avoid having to
  /// export the symbols of Interpreter.
  URBI_SDK_API std::string current_function_name();
  URBI_SDK_API std::string current_file();
  URBI_SDK_API int current_line();

  /// Convenience wrapper to get urbiserver's current scheduler.
  sched::Scheduler& scheduler();

  //! Handle all Urbi system processing.
  /*! There must be one UServer defined in the program and it must be overloaded
      to make it specific to the particular robot.

      UServer is used to store the UConnection list and the UDevice list.
      This object does all the internal processing of Urbi and handles the pool
      of UCommand's.
  */
  class URBI_SDK_API UServer
  {
  public:
    UServer(UrbiRoot& urbi_root);
    virtual ~UServer();

  public:
    //! Initialization of the server. Displays the header message & init stuff
    /*! This function must be called once the server is operational and
     * able to print messages. It is a requirement for Urbi compliance to print
     * the header at start, so this function *must* be called. Beside, it also
     * do initalization work for the devices and system variables.
     *
     * \param interactive  whether the ghostconnection is interactive.
     *                     FIXME: this interface is unpleasant, something
     *                     nicer is needed.
     */
    void initialize(bool interactive = false);

    /// Accessors for interactive value bound to System.interactive,
    // also define the behavior when receiving SIGINT.
    bool interactive_get() const;
    void interactive_set(bool);

    /// Support a kernel and a user mode.
    ///
    /// Exceptions may not be launched in user mode, they are hard
    /// error.  This is used to catch error when the system is
    /// incomplete, say when an error occurs when loading urbi/urbi.u.
    /// Therefore, "of course", defaults to mode_kernel.
    enum mode_type
    {
      mode_kernel,
      mode_user,
    };
    ATTRIBUTE_R(mode_type, mode);

  public:
    /// Process the jobs.
    /// \return the time when should be called again.
    libport::utime_t work();

    /// Set the system.args list in Urbi.
    void main(int argc, const char* argv[]);

    //! Overload this function to return the running time of the server.
    /*! The running time of the server must be in microseconds.
     */
    virtual libport::utime_t getTime() const = 0;

    /// Path to explore when looking for .u files.
    libport::file_library search_path;

    /// Return the full file name, handle paths.
    /// Return \a f on failure.
    virtual std::string find_file(const libport::path& path) const;

    /// Load a file into the connection.
    /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
    virtual UErrorValue load_file(const std::string& file_name,
                                  UConnection& dest);

    /// Load \a fn in the ghostqueue.
    UErrorValue load_init_file(const char* fn);

    /// Same but calls init_error on errors.
    void xload_init_file(const char* fn);

    /// Save content to a file
    /// This function must be redefined by the robot-specific server.
    /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
    virtual UErrorValue save_file(const std::string& filename,
                                  const std::string& content) = 0;

    //! Overload this function to specify how your system will reboot
    virtual void reboot() = 0;

    //! Overload this function to specify how your system will shutdown
    virtual void shutdown();

    //! Function called before work
    /*! Redefine this virtual function if you need to do pre-processing before
      the work function starts.
    */
    virtual void beforeWork();

    //! Function called after work
    /*! Redefine this virtual function if you need to do post-processing
      before the work function ends.
    */
    virtual void afterWork();

    /// Display a message on the robot console.
    void display(const char*);

    //! Accessor for lastTime_.
    libport::utime_t lastTime();

    //! Update lastTime_ to current time.
    //! Update the server's time using the robot-specific implementation
    /*! It is necessary to have an update of the server time to
     increase the performance of successive calls to getTime.
     It allows also to see a whole processing session (like the
     processing of the command tree) as occuring AT the same time,
     from the server's point of view.
     */
    void updateTime();

    /*----------------.
    | Configuration.  |
    `----------------*/

    ATTRIBUTE_RW(bool, opt_banner);

    /*--------------.
    | Connections.  |
    `--------------*/

    public:
    /// Add a new connection to the connection list.
    /// Take ownership on c. Also perform some error testing on the connection
    /// value and UError return code
    /// \precondition c != 0
    void connection_add(UConnection* c);

    /// \returns A usual connection to stop dependencies.
    ///          (kernel/ghost-connection.hh is not public).
    UConnection& ghost_connection_get();

    /*--------------------.
    | Scheduler, runner.  |
    `--------------------*/
  public:
    const sched::Scheduler& scheduler_get() const;
    sched::Scheduler& scheduler_get();

    runner::Runner& getCurrentRunner() const;
    runner::Runner* getCurrentRunnerOpt() const;

    boost::asio::io_service& get_io_service();

    /// Wake up from main loop.
    void wake_up();

    /*--------------------------------------.
    | Thread-safe asynchronous scheduling   |
    `---------------------------------------*/

  public:
    /// Schedule a call in a new job.
    void schedule(urbi::object::rObject target, libport::Symbol method,
                  const urbi::object::objects_type& args =
                    urbi::object::objects_type());
    /// Schedule callback in a new job.
    void schedule(libport::Symbol method, boost::function0<void> callback);
    /// Schedule callback in the shared asynchronous job handler.
    void schedule_fast(boost::function0<void> callback);
  private:
    struct AsyncJob
    {
      AsyncJob(urbi::object::rObject t, libport::Symbol m,
               const urbi::object::objects_type& a);
      AsyncJob(boost::function0<void> callback, libport::Symbol m);
      urbi::object::rObject target;
      libport::Symbol method;
      urbi::object::objects_type args;
      boost::function0<void> callback;
      bool synchronous;
    };
    std::vector<AsyncJob> async_jobs_;
    libport::Lockable async_jobs_lock_;

    void async_jobs_process_();
    void schedule(const AsyncJob& j);

    /* We use an always running job fast_async_jobs_job_ to handle all
     * fast_async_jobs_ callback.
     * When it has nothing to do, it sleeps by freezing
     * fast_async_jobs_tag_. This tag is unfrozen by work() if
     * fast_async_jobs_start_ is true (because tags are not thread-safe).
     */
    std::vector<boost::function0<void> > fast_async_jobs_;
    bool fast_async_jobs_start_; // must wake async jobs handler
    object::rObject fast_async_jobs_tag_;
    libport::Lockable fast_async_jobs_lock_;
    sched::rJob fast_async_jobs_job_; // For the sake of consistency.
    void fast_async_jobs_run_();

  protected:
    /// Overload this function to specify how your robot is displaying messages.
    virtual void effectiveDisplay(const char* s) = 0;

  private:
    // Pointer to stop the header dependency.
    sched::Scheduler* scheduler_;

  private:
    /// \{ Various parts of @c UServer::work.
    /// Scan currently opened connections for deleting marked commands or
    /// killall order
    void work_handle_stopall_();
    void work_test_cpuoverload_();
    /// \}

  public:
    /// Stops all commands in all connections.
    bool stopall;

    /// True iff current thread is different from server thread Id.
    bool isAnotherThread() const;

    UrbiRoot& urbi_root_get();

    void connection_remove(UConnection& connection);

  private:
    /// Store the time on the last call to updateTime().
    libport::utime_t lastTime_;

    /// List of active connections: includes one UGhostConnection.
    // FIXME: This is meant to become a runner::Job and move out of this class.
    /// A pointer to stop dependencies.
    std::auto_ptr<kernel::ConnectionSet> connections_;

    /// The ghost connection used for urbi.u, URBI.INI, etc.
    // Does not need to be an auto_ptr, as it is stored in connections_
    // which handles memory management.
    UGhostConnection* ghost_;

    /// Whether this server is in interactive mode.
    bool interactive_;

    /// Store the server thread Id.
    pthread_t thread_id_;

    /// Urbi SDK installation
    UrbiRoot& urbi_root_;

    /// Socket pair used to wake us up
    std::pair<libport::Socket*, libport::Socket*> wake_up_pipe_;

    /// Dead jobs from last sched cycle.
    sched::jobs_type dead_jobs_;
  };

}

// Disable debug traces until we find a better means to do it.
# define DEBUG(Msg) ((void) 0)

# include <kernel/userver.hxx>

#endif // !KERNEL_USERVER_HH
<commit_msg>comment changes.<commit_after>/*
 * Copyright (C) 2009-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file kernel/userver.hh
/// \brief Definition of the UServer class.

#ifndef KERNEL_USERVER_HH
# define KERNEL_USERVER_HH

# include <memory>
# include <sstream>

# include <libport/config.h>
# include <libport/attributes.hh>

# if LIBPORT_HAVE_WINDOWS_H
// Without this, windows.h may include winsock.h, which will conflict with
// winsock2.h when we will try to include it.
#  define WIN32_LEAN_AND_MEAN
# endif

# include <libport/fwd.hh>
# include <libport/compiler.hh>
# include <libport/file-library.hh>
# include <libport/lockable.hh>
# include <libport/ufloat.h>
# include <libport/utime.hh>
# include <libport/pthread.h>

# include <sched/scheduler.hh>

# include <kernel/fwd.hh>
# include <kernel/utypes.hh>
# include <urbi/export.hh>
# include <urbi/object/object.hh>
# include <urbi/urbi-root.hh>

namespace kernel
{
  /// Global variable for the server
  extern URBI_SDK_API class UServer* urbiserver;

  /// The current server.
  UServer& server();

  /// Convenience wrapper to get urbiserver's current runner.
  runner::Runner& runner();

  /// Convenience wrapper to get urbiserver's current interpreter.
  runner::Interpreter& interpreter();

  /// Convenience wrapper for Logger objects, to avoid having to
  /// export the symbols of Interpreter.
  URBI_SDK_API std::string current_function_name();
  URBI_SDK_API std::string current_file();
  URBI_SDK_API int current_line();

  /// Convenience wrapper to get urbiserver's current scheduler.
  sched::Scheduler& scheduler();

  //! Handle all Urbi system processing.
  /*! There must be one UServer defined in the program and it must be
      overloaded to make it specific to the particular robot.

      UServer is used to store the UConnection list.
      This object does all the internal processing of Urbi.
  */
  class URBI_SDK_API UServer
  {
  public:
    UServer(UrbiRoot& urbi_root);
    virtual ~UServer();

  public:
    //! Initialization of the server. Displays the header message & init stuff
    /*! This function must be called once the server is operational and
     * able to print messages. It is a requirement for Urbi compliance to print
     * the header at start, so this function *must* be called. Beside, it also
     * do initalization work for the devices and system variables.
     *
     * \param interactive  whether the ghostconnection is interactive.
     *                     FIXME: this interface is unpleasant, something
     *                     nicer is needed.
     */
    void initialize(bool interactive = false);

    /// Accessors for interactive value bound to System.interactive,
    // also define the behavior when receiving SIGINT.
    bool interactive_get() const;
    void interactive_set(bool);

    /// Support a kernel and a user mode.
    ///
    /// Exceptions may not be launched in user mode, they are hard
    /// error.  This is used to catch error when the system is
    /// incomplete, say when an error occurs when loading urbi/urbi.u.
    /// Therefore, "of course", defaults to mode_kernel.
    enum mode_type
    {
      mode_kernel,
      mode_user,
    };
    ATTRIBUTE_R(mode_type, mode);

  public:
    /// Process the jobs.
    /// \return the time when should be called again.
    libport::utime_t work();

    /// Set the system.args list in Urbi.
    void main(int argc, const char* argv[]);

    //! Overload this function to return the running time of the server.
    /*! The running time of the server must be in microseconds.
     */
    virtual libport::utime_t getTime() const = 0;

    /// Path to explore when looking for .u files.
    libport::file_library search_path;

    /// Return the full file name, handle paths.
    /// Return \a f on failure.
    virtual std::string find_file(const libport::path& path) const;

    /// Load a file into the connection.
    /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
    virtual UErrorValue load_file(const std::string& file_name,
                                  UConnection& dest);

    /// Load \a fn in the ghostqueue.
    UErrorValue load_init_file(const char* fn);

    /// Same but calls init_error on errors.
    void xload_init_file(const char* fn);

    /// Save content to a file
    /// This function must be redefined by the robot-specific server.
    /// Returns UFAIL if anything goes wrong, USUCCESS otherwise.
    virtual UErrorValue save_file(const std::string& filename,
                                  const std::string& content) = 0;

    //! Overload this function to specify how your system will reboot
    virtual void reboot() = 0;

    //! Overload this function to specify how your system will shutdown
    virtual void shutdown();

    //! Function called before work
    /*! Redefine this virtual function if you need to do pre-processing before
      the work function starts.
    */
    virtual void beforeWork();

    //! Function called after work
    /*! Redefine this virtual function if you need to do post-processing
      before the work function ends.
    */
    virtual void afterWork();

    /// Display a message on the robot console.
    void display(const char*);

    //! Accessor for lastTime_.
    libport::utime_t lastTime();

    //! Update lastTime_ to current time.
    //! Update the server's time using the robot-specific implementation
    /*! It is necessary to have an update of the server time to
     increase the performance of successive calls to getTime.
     It allows also to see a whole processing session (like the
     processing of the command tree) as occuring AT the same time,
     from the server's point of view.
     */
    void updateTime();

    /*----------------.
    | Configuration.  |
    `----------------*/

    ATTRIBUTE_RW(bool, opt_banner);

    /*--------------.
    | Connections.  |
    `--------------*/

    public:
    /// Add a new connection to the connection list.
    /// Take ownership on c. Also perform some error testing on the connection
    /// value and UError return code
    /// \precondition c != 0
    void connection_add(UConnection* c);

    /// \returns A usual connection to stop dependencies.
    ///          (kernel/ghost-connection.hh is not public).
    UConnection& ghost_connection_get();

    /*--------------------.
    | Scheduler, runner.  |
    `--------------------*/
  public:
    const sched::Scheduler& scheduler_get() const;
    sched::Scheduler& scheduler_get();

    runner::Runner& getCurrentRunner() const;
    runner::Runner* getCurrentRunnerOpt() const;

    boost::asio::io_service& get_io_service();

    /// Wake up from main loop.
    void wake_up();

    /*--------------------------------------.
    | Thread-safe asynchronous scheduling   |
    `---------------------------------------*/

  public:
    /// Schedule a call in a new job.
    void schedule(urbi::object::rObject target, libport::Symbol method,
                  const urbi::object::objects_type& args =
                    urbi::object::objects_type());
    /// Schedule callback in a new job.
    void schedule(libport::Symbol method, boost::function0<void> callback);
    /// Schedule callback in the shared asynchronous job handler.
    void schedule_fast(boost::function0<void> callback);
  private:
    struct AsyncJob
    {
      AsyncJob(urbi::object::rObject t, libport::Symbol m,
               const urbi::object::objects_type& a);
      AsyncJob(boost::function0<void> callback, libport::Symbol m);
      urbi::object::rObject target;
      libport::Symbol method;
      urbi::object::objects_type args;
      boost::function0<void> callback;
      bool synchronous;
    };
    std::vector<AsyncJob> async_jobs_;
    libport::Lockable async_jobs_lock_;

    void async_jobs_process_();
    void schedule(const AsyncJob& j);

    /* We use an always running job fast_async_jobs_job_ to handle all
     * fast_async_jobs_ callback.
     * When it has nothing to do, it sleeps by freezing
     * fast_async_jobs_tag_. This tag is unfrozen by work() if
     * fast_async_jobs_start_ is true (because tags are not thread-safe).
     */
    std::vector<boost::function0<void> > fast_async_jobs_;
    bool fast_async_jobs_start_; // must wake async jobs handler
    object::rObject fast_async_jobs_tag_;
    libport::Lockable fast_async_jobs_lock_;
    sched::rJob fast_async_jobs_job_; // For the sake of consistency.
    void fast_async_jobs_run_();

  protected:
    /// Overload this function to specify how your robot is displaying messages.
    virtual void effectiveDisplay(const char* s) = 0;

  private:
    // Pointer to stop the header dependency.
    sched::Scheduler* scheduler_;

  private:
    /// \{ Various parts of @c UServer::work.
    /// Scan currently opened connections for deleting marked commands or
    /// killall order
    void work_handle_stopall_();
    void work_test_cpuoverload_();
    /// \}

  public:
    /// Stops all commands in all connections.
    bool stopall;

    /// True iff current thread is different from server thread Id.
    bool isAnotherThread() const;

    UrbiRoot& urbi_root_get();

    void connection_remove(UConnection& connection);

  private:
    /// Store the time on the last call to updateTime().
    libport::utime_t lastTime_;

    /// List of active connections: includes one UGhostConnection.
    // FIXME: This is meant to become a runner::Job and move out of this class.
    /// A pointer to stop dependencies.
    std::auto_ptr<kernel::ConnectionSet> connections_;

    /// The ghost connection used for urbi.u, URBI.INI, etc.
    // Does not need to be an auto_ptr, as it is stored in connections_
    // which handles memory management.
    UGhostConnection* ghost_;

    /// Whether this server is in interactive mode.
    bool interactive_;

    /// Store the server thread Id.
    pthread_t thread_id_;

    /// Urbi SDK installation
    UrbiRoot& urbi_root_;

    /// Socket pair used to wake us up
    std::pair<libport::Socket*, libport::Socket*> wake_up_pipe_;

    /// Dead jobs from last sched cycle.
    sched::jobs_type dead_jobs_;
  };

}

// Disable debug traces until we find a better means to do it.
# define DEBUG(Msg) ((void) 0)

# include <kernel/userver.hxx>

#endif // !KERNEL_USERVER_HH
<|endoftext|>


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

#include <utility>

/* This counts the number of args */
#define NARGS_SEQ(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will pop the last argument off */
#define POP_LAST(...) CAT(POP_LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define POP_LAST_1(x1)
#define POP_LAST_2(x1, x2) x1
#define POP_LAST_3(x1, x2, x3) x1, x2
#define POP_LAST_4(x1, x2, x3, x4) x1, x2, x3
#define POP_LAST_5(x1, x2, x3, x4, x5) x1, x2, x3, x4
#define POP_LAST_6(x1, x2, x3, x4, x5, x6) x1, x2, x3, x4, x5
#define POP_LAST_7(x1, x2, x3, x4, x5, x6, x7) x1, x2, x3, x4, x5, x6
#define POP_LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x1, x2, x3, x4, x5, x6, x7
#define POP_LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x1, x2, x3, x4, x5, x6, x7, x8
#define POP_LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x1, x2, x3, x4, x5, x6, x7, x8, x9

/* This will return the last argument */
#define LAST(...) CAT(LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define LAST_1(x1) x1
#define LAST_2(x1, x2) x2
#define LAST_3(x1, x2, x3) x3
#define LAST_4(x1, x2, x3, x4) x4
#define LAST_5(x1, x2, x3, x4, x5) x5
#define LAST_6(x1, x2, x3, x4, x5, x6) x6
#define LAST_7(x1, x2, x3, x4, x5, x6, x7) x7
#define LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x8
#define LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x9
#define LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x10

namespace detail
{

template <typename T>
class scope_exit
{
public:
  explicit scope_exit(T&& f) : f_(::std::move(f))
  {
    static_assert(noexcept(f_()), "throwing functors are unsupported");
  }

  scope_exit(scope_exit&& other) : f_(::std::move(other.f_)) { }

  ~scope_exit() noexcept { f_(); }

private:
  T f_;
};

class scope_exit_helper { };

template<typename T>
inline scope_exit<T> make_scope_exit(T&& f)
{
  return scope_exit<T>(::std::forward<T>(f));
}

template<typename T>
inline scope_exit<T> operator+(scope_exit_helper&&, T&& f)
{
  return scope_exit<T>(::std::forward<T>(f));
}

}

#define SCOPE_EXIT(...) auto const CAT(scope_exit_, __LINE__)          \
  (::detail::make_scope_exit([POP_LAST(__VA_ARGS__)]() mutable noexcept\
    { LAST(__VA_ARGS__); }))
#define SCOPE_EXIT_ auto const CAT(scope_exit_, __LINE__) =            \
  ::detail::scope_exit_helper()+[&]() mutable noexcept
#define SCOPE_EXIT__(...) auto const CAT(scope_exit_, __LINE__) =      \
  ::detail::scope_exit_helper()+[__VA_ARGS__]() mutable noexcept

#endif // SCOPEEXIT_HPP
<commit_msg>some fixes<commit_after>#pragma once
#ifndef SCOPEEXIT_HPP
# define SCOPEEXIT_HPP

#include <utility>

/* This counts the number of args */
#define NARGS_SEQ(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will pop the last argument off */
#define POP_LAST(...) CAT(POP_LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define POP_LAST_1(x1)
#define POP_LAST_2(x1, x2) x1
#define POP_LAST_3(x1, x2, x3) x1, x2
#define POP_LAST_4(x1, x2, x3, x4) x1, x2, x3
#define POP_LAST_5(x1, x2, x3, x4, x5) x1, x2, x3, x4
#define POP_LAST_6(x1, x2, x3, x4, x5, x6) x1, x2, x3, x4, x5
#define POP_LAST_7(x1, x2, x3, x4, x5, x6, x7) x1, x2, x3, x4, x5, x6
#define POP_LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x1, x2, x3, x4, x5, x6, x7
#define POP_LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x1, x2, x3, x4, x5, x6, x7, x8
#define POP_LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x1, x2, x3, x4, x5, x6, x7, x8, x9

/* This will return the last argument */
#define LAST(...) CAT(LAST_, NARGS(__VA_ARGS__))(__VA_ARGS__)
#define LAST_1(x1) x1
#define LAST_2(x1, x2) x2
#define LAST_3(x1, x2, x3) x3
#define LAST_4(x1, x2, x3, x4) x4
#define LAST_5(x1, x2, x3, x4, x5) x5
#define LAST_6(x1, x2, x3, x4, x5, x6) x6
#define LAST_7(x1, x2, x3, x4, x5, x6, x7) x7
#define LAST_8(x1, x2, x3, x4, x5, x6, x7, x8) x8
#define LAST_9(x1, x2, x3, x4, x5, x6, x7, x8, x9) x9
#define LAST_10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) x10

namespace detail
{

template <typename T>
class scope_exit
{
public:
  explicit scope_exit(T&& f) : f_(::std::forward<T>(f))
  {
    static_assert(noexcept(f_()), "throwing functors are unsupported");
  }

  scope_exit(scope_exit&& other) : f_(::std::move(other.f_)) { }

  ~scope_exit() noexcept { f_(); }

private:
  T f_;
};

class scope_exit_helper { };

template<typename T>
inline scope_exit<T> make_scope_exit(T&& f)
{
  return scope_exit<T>(::std::forward<T>(f));
}

template<typename T>
inline scope_exit<T> operator+(scope_exit_helper&&, T&& f)
{
  return scope_exit<T>(::std::forward<T>(f));
}

}

#define SCOPE_EXIT(...) auto const CAT(scope_exit_, __LINE__)          \
  (::detail::make_scope_exit([POP_LAST(__VA_ARGS__)]() mutable noexcept\
    { LAST(__VA_ARGS__); }))
#define SCOPE_EXIT_ auto const CAT(scope_exit_, __LINE__) =            \
  ::detail::scope_exit_helper()+[&]() mutable noexcept
#define SCOPE_EXIT__(...) auto const CAT(scope_exit_, __LINE__) =      \
  ::detail::scope_exit_helper()+[__VA_ARGS__]() mutable noexcept

#endif // SCOPEEXIT_HPP
<|endoftext|>


<commit_before>#ifndef TOKEN_I_HH
#define TOKEN_I_HH

#ifndef TOKEN_HH
#error "Please include via parent file"
#endif

#include <utility>
#include "decl.hh"
#include "util.hh"

// Type mapping
template<Token::Type t, typename T>
T to_type() = delete;

template<>
std::string to_type<Token::Type::identifier>() = delete;

template<>
bool to_type<Token::Type::boolean>() = delete;

template<>
Number to_type<Token::Type::number>() = delete;

template<>
char to_type<Token::Type::character>() = delete;

template<>
std::string to_type<Token::Type::string>() = delete;

template<>
Token::Notation to_type<Token::Type::notation>() = delete;

// std::string -> Token::Type is ambigious

template<>
inline constexpr
Token::Type to_tag<Token::Type, Number>(){
  return Token::Type::number;
}

template<>
inline constexpr
Token::Type to_tag<Token::Type, bool>(){
  return Token::Type::boolean;
}

template<>
inline constexpr
Token::Type to_tag<Token::Type, char>(){
  return Token::Type::character;
}

template<>
inline constexpr
Token::Type to_tag<Token::Type, Token::Notation>(){
  return Token::Type::notation;
}

// Token definitions
inline
Token::~Token(){
  using namespace std;

  switch(type_){
  case Type::identifier:
  case Type::string:
    str_.~string();
    break;

  case Type::number:
    num_.~Number();
    break;

  case Type::uninitialized:
  case Type::boolean:
  case Type::character:
  case Type::notation:
  default:
    break;
  }

  type_ = Type::uninitialized;
}

template<>
inline
std::string Token::get() const{
  switch(type_){
  case Type::identifier:
  case Type::string:
    return str_;
  default:
    UNEXP_CONVERSION("(no string token)", "string");
  }
}

template<>
inline
Number Token::get() const{
  if(type_ == Type::number)
    return num_;
  else
    UNEXP_CONVERSION("(no number token)", "number");
}

template<>
inline
bool Token::get() const{
  if(type_ == Type::boolean)
    return b_;
  else
    UNEXP_CONVERSION("(no boolean token)", "boolean");
}

template<>
inline
char Token::get() const{
  if(type_ == Type::character)
    return c_;
  else
    UNEXP_CONVERSION("(no char token)", "char");
}

template<>
inline
Token::Notation Token::get() const{
  if(type_ == Type::notation)
    return not_;
  else
    UNEXP_CONVERSION("(no notation token)", "notation");
}

#endif // TOKEN_I_HH
<commit_msg>bitly cleanup<commit_after>#ifndef TOKEN_I_HH
#define TOKEN_I_HH

#ifndef TOKEN_HH
#error "Please include via parent file"
#endif

#include <utility>
#include "decl.hh"
#include "util.hh"

// Type mapping
template<Token::Type t, typename T>
T to_type() = delete;

template<>
std::string to_type<Token::Type::identifier>() = delete;

template<>
bool to_type<Token::Type::boolean>() = delete;

template<>
Number to_type<Token::Type::number>() = delete;

template<>
char to_type<Token::Type::character>() = delete;

template<>
std::string to_type<Token::Type::string>() = delete;

template<>
Token::Notation to_type<Token::Type::notation>() = delete;

// std::string -> Token::Type is ambigious
template<>
inline constexpr
Token::Type to_tag<Token::Type, std::string>() = delete;

template<>
inline constexpr
Token::Type to_tag<Token::Type, Number>(){
  return Token::Type::number;
}

template<>
inline constexpr
Token::Type to_tag<Token::Type, bool>(){
  return Token::Type::boolean;
}

template<>
inline constexpr
Token::Type to_tag<Token::Type, char>(){
  return Token::Type::character;
}

template<>
inline constexpr
Token::Type to_tag<Token::Type, Token::Notation>(){
  return Token::Type::notation;
}

// Token definitions
inline
Token::~Token(){
  using namespace std;

  switch(type_){
  case Type::identifier:
  case Type::string:
    str_.~string();
    break;

  case Type::number:
    num_.~Number();
    break;

  case Type::uninitialized:
  case Type::boolean:
  case Type::character:
  case Type::notation:
  default:
    break;
  }

  type_ = Type::uninitialized;
}

template<>
inline
std::string Token::get() const{
  switch(type_){
  case Type::identifier:
  case Type::string:
    return str_;
  default:
    UNEXP_CONVERSION("(no string token)", "string");
  }
}

template<>
inline
Number Token::get() const{
  if(type_ == Type::number)
    return num_;
  else
    UNEXP_CONVERSION("(no number token)", "number");
}

template<>
inline
bool Token::get() const{
  if(type_ == Type::boolean)
    return b_;
  else
    UNEXP_CONVERSION("(no boolean token)", "boolean");
}

template<>
inline
char Token::get() const{
  if(type_ == Type::character)
    return c_;
  else
    UNEXP_CONVERSION("(no char token)", "char");
}

template<>
inline
Token::Notation Token::get() const{
  if(type_ == Type::notation)
    return not_;
  else
    UNEXP_CONVERSION("(no notation token)", "notation");
}

#endif // TOKEN_I_HH
<|endoftext|>


<commit_before>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "DistrhoUIInternal.hpp"

#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# error DSSI UIs do not support direct access!
#endif

#include "../extra/d_sleep.hpp"

#include <lo/lo.h>

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------

struct OscData {
    lo_address  addr;
    const char* path;
    lo_server   server;

    OscData()
        : addr(nullptr),
          path(nullptr),
          server(nullptr) {}

    void idle() const
    {
        if (server == nullptr)
            return;

        while (lo_server_recv_noblock(server, 0) != 0) {}
    }

    void send_configure(const char* const key, const char* const value) const
    {
        char targetPath[std::strlen(path)+11];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/configure");
        lo_send(addr, targetPath, "ss", key, value);
    }

    void send_control(const int32_t index, const float value) const
    {
        char targetPath[std::strlen(path)+9];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/control");
        lo_send(addr, targetPath, "if", index, value);
    }

    void send_midi(uchar data[4]) const
    {
        char targetPath[std::strlen(path)+6];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/midi");
        lo_send(addr, targetPath, "m", data);
    }

    void send_update(const char* const url) const
    {
        char targetPath[std::strlen(path)+8];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/update");
        lo_send(addr, targetPath, "s", url);
    }

    void send_exiting() const
    {
        char targetPath[std::strlen(path)+9];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/exiting");
        lo_send(addr, targetPath, "");
    }
};

// -----------------------------------------------------------------------

class UIDssi
{
public:
    UIDssi(const OscData& oscData, const char* const uiTitle)
        : fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback),
          fHostClosed(false),
          fShowCalled(false),
          fOscData(oscData)
    {
        fUI.setTitle(uiTitle);
    }

    ~UIDssi()
    {
        if (fOscData.server != nullptr && ! fHostClosed)
            fOscData.send_exiting();
    }

    void exec()
    {
        for (;;)
        {
            fOscData.idle();

            if (! fUI.idle())
            {
                // host might not have called show yet
                if (fShowCalled)
                    break;
            }
            else if (fHostClosed)
                break;

            d_msleep(30);
        }
    }

    // -------------------------------------------------------------------

#if DISTRHO_PLUGIN_WANT_STATE
    void dssiui_configure(const char* key, const char* value)
    {
        fUI.stateChanged(key, value);
    }
#endif

    void dssiui_control(ulong index, float value)
    {
        fUI.parameterChanged(index, value);
    }

#if DISTRHO_PLUGIN_WANT_PROGRAMS
    void dssiui_program(ulong bank, ulong program)
    {
        fUI.programChanged(bank * 128 + program);
    }
#endif

    void dssiui_show()
    {
        fShowCalled = true;
        fUI.setVisible(true);
    }

    void dssiui_hide()
    {
        fUI.setVisible(false);
    }

    void dssiui_quit()
    {
        fHostClosed = true;
        fUI.quit();
    }

    // -------------------------------------------------------------------

protected:
    void setParameterValue(const uint32_t rindex, const float value)
    {
        if (fOscData.server == nullptr)
            return;

        fOscData.send_control(rindex, value);
    }

    void setState(const char* const key, const char* const value)
    {
        if (fOscData.server == nullptr)
            return;

        fOscData.send_configure(key, value);
    }

    void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
    {
        if (fOscData.server == nullptr)
            return;
        if (channel > 0xF)
            return;

        uint8_t mdata[4] = { 0, channel, note, velocity };
        mdata[1] += (velocity != 0) ? 0x90 : 0x80;

        fOscData.send_midi(mdata);
    }

    void setSize(const uint width, const uint height)
    {
        fUI.setSize(width, height);
    }

private:
    UIExporter fUI;
    bool fHostClosed;
    bool fShowCalled;

    const OscData& fOscData;

    // -------------------------------------------------------------------
    // Callbacks

    #define uiPtr ((UIDssi*)ptr)

    static void setParameterCallback(void* ptr, uint32_t rindex, float value)
    {
        uiPtr->setParameterValue(rindex, value);
    }

    static void setStateCallback(void* ptr, const char* key, const char* value)
    {
        uiPtr->setState(key, value);
    }

    static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
    {
        uiPtr->sendNote(channel, note, velocity);
    }

    static void setSizeCallback(void* ptr, uint width, uint height)
    {
        uiPtr->setSize(width, height);
    }

    #undef uiPtr
};

// -----------------------------------------------------------------------

static OscData     gOscData;
static const char* gUiTitle = nullptr;
static UIDssi*     globalUI = nullptr;

static void initUiIfNeeded()
{
    if (globalUI != nullptr)
        return;

    if (d_lastUiSampleRate == 0.0)
        d_lastUiSampleRate = 44100.0;

    globalUI = new UIDssi(gOscData, gUiTitle);
}

// -----------------------------------------------------------------------

int osc_debug_handler(const char* path, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_debug_handler(\"%s\")", path);
    return 0;

#ifndef DEBUG
    // unused
    (void)path;
#endif
}

void osc_error_handler(int num, const char* msg, const char* path)
{
    d_stderr("osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
}

#if DISTRHO_PLUGIN_WANT_STATE
int osc_configure_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const char* const key   = &argv[0]->s;
    const char* const value = &argv[1]->s;
    d_debug("osc_configure_handler(\"%s\", \"%s\")", key, value);

    initUiIfNeeded();

    globalUI->dssiui_configure(key, value);

    return 0;
}
#endif

int osc_control_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const int32_t rindex = argv[0]->i;
    const float   value  = argv[1]->f;
    d_debug("osc_control_handler(%i, %f)", rindex, value);

    int32_t index = rindex - DISTRHO_PLUGIN_NUM_INPUTS - DISTRHO_PLUGIN_NUM_OUTPUTS;

    // latency
#if DISTRHO_PLUGIN_WANT_LATENCY
    index -= 1;
#endif

    if (index < 0)
        return 0;

    initUiIfNeeded();

    globalUI->dssiui_control(index, value);

    return 0;
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
int osc_program_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const int32_t bank    = argv[0]->i;
    const int32_t program = argv[1]->f;
    d_debug("osc_program_handler(%i, %i)", bank, program);

    initUiIfNeeded();

    globalUI->dssiui_program(bank, program);

    return 0;
}
#endif

int osc_sample_rate_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const int32_t sampleRate = argv[0]->i;
    d_debug("osc_sample_rate_handler(%i)", sampleRate);

    d_lastUiSampleRate = sampleRate;

    return 0;
}

int osc_show_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_show_handler()");

    initUiIfNeeded();

    globalUI->dssiui_show();

    return 0;
}

int osc_hide_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_hide_handler()");

    if (globalUI != nullptr)
        globalUI->dssiui_hide();

    return 0;
}

int osc_quit_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_quit_handler()");

    if (globalUI != nullptr)
        globalUI->dssiui_quit();

    return 0;
}

END_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------

int main(int argc, char* argv[])
{
    USE_NAMESPACE_DISTRHO

    // dummy test mode
    if (argc == 1)
    {
        gUiTitle = "DSSI UI Test";

        initUiIfNeeded();
        globalUI->dssiui_show();
        globalUI->exec();

        delete globalUI;
        globalUI = nullptr;

        return 0;
    }

    if (argc != 5)
    {
        fprintf(stderr, "Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>\n", argv[0]);
        return 1;
    }

    const char* oscUrl  = argv[1];
    const char* uiTitle = argv[4];

    char* const oscHost = lo_url_get_hostname(oscUrl);
    char* const oscPort = lo_url_get_port(oscUrl);
    char* const oscPath = lo_url_get_path(oscUrl);
    size_t  oscPathSize = strlen(oscPath);
    lo_address  oscAddr = lo_address_new(oscHost, oscPort);
    lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, osc_error_handler);

    char* const oscServerPath = lo_server_get_url(oscServer);

    char pluginPath[strlen(oscServerPath)+oscPathSize];
    strcpy(pluginPath, oscServerPath);
    strcat(pluginPath, oscPath+1);

#if DISTRHO_PLUGIN_WANT_STATE
    char oscPathConfigure[oscPathSize+11];
    strcpy(oscPathConfigure, oscPath);
    strcat(oscPathConfigure, "/configure");
    lo_server_add_method(oscServer, oscPathConfigure, "ss", osc_configure_handler, nullptr);
#endif

    char oscPathControl[oscPathSize+9];
    strcpy(oscPathControl, oscPath);
    strcat(oscPathControl, "/control");
    lo_server_add_method(oscServer, oscPathControl, "if", osc_control_handler, nullptr);

    d_stdout("oscServerPath:  \"%s\"", oscServerPath);
    d_stdout("pluginPath:     \"%s\"", pluginPath);
    d_stdout("oscPathControl: \"%s\"", oscPathControl);

#if DISTRHO_PLUGIN_WANT_PROGRAMS
    char oscPathProgram[oscPathSize+9];
    strcpy(oscPathProgram, oscPath);
    strcat(oscPathProgram, "/program");
    lo_server_add_method(oscServer, oscPathProgram, "ii", osc_program_handler, nullptr);
#endif

    char oscPathSampleRate[oscPathSize+13];
    strcpy(oscPathSampleRate, oscPath);
    strcat(oscPathSampleRate, "/sample-rate");
    lo_server_add_method(oscServer, oscPathSampleRate, "i", osc_sample_rate_handler, nullptr);

    char oscPathShow[oscPathSize+6];
    strcpy(oscPathShow, oscPath);
    strcat(oscPathShow, "/show");
    lo_server_add_method(oscServer, oscPathShow, "", osc_show_handler, nullptr);

    char oscPathHide[oscPathSize+6];
    strcpy(oscPathHide, oscPath);
    strcat(oscPathHide, "/hide");
    lo_server_add_method(oscServer, oscPathHide, "", osc_hide_handler, nullptr);

    char oscPathQuit[oscPathSize+6];
    strcpy(oscPathQuit, oscPath);
    strcat(oscPathQuit, "/quit");
    lo_server_add_method(oscServer, oscPathQuit, "", osc_quit_handler, nullptr);

    lo_server_add_method(oscServer, nullptr, nullptr, osc_debug_handler, nullptr);

    gUiTitle = uiTitle;

    gOscData.addr   = oscAddr;
    gOscData.path   = oscPath;
    gOscData.server = oscServer;
    gOscData.send_update(pluginPath);

    // wait for init
    for (int i=0; i < 100; ++i)
    {
        lo_server_recv(oscServer);

        if (d_lastUiSampleRate != 0.0 || globalUI != nullptr)
            break;

        d_msleep(50);
    }

    int ret = 1;

    if (d_lastUiSampleRate != 0.0 || globalUI != nullptr)
    {
        initUiIfNeeded();

        globalUI->exec();

        delete globalUI;
        globalUI = nullptr;

        ret = 0;
    }

#if DISTRHO_PLUGIN_WANT_STATE
    lo_server_del_method(oscServer, oscPathConfigure, "ss");
#endif
    lo_server_del_method(oscServer, oscPathControl, "if");
#if DISTRHO_PLUGIN_WANT_PROGRAMS
    lo_server_del_method(oscServer, oscPathProgram, "ii");
#endif
    lo_server_del_method(oscServer, oscPathSampleRate, "i");
    lo_server_del_method(oscServer, oscPathShow, "");
    lo_server_del_method(oscServer, oscPathHide, "");
    lo_server_del_method(oscServer, oscPathQuit, "");
    lo_server_del_method(oscServer, nullptr, nullptr);

    std::free(oscServerPath);
    std::free(oscHost);
    std::free(oscPort);
    std::free(oscPath);

    lo_address_free(oscAddr);
    lo_server_free(oscServer);

    return ret;
}
<commit_msg>Revert DSSI UI auto-close fix, no longer needed<commit_after>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "DistrhoUIInternal.hpp"

#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# error DSSI UIs do not support direct access!
#endif

#include "../extra/d_sleep.hpp"

#include <lo/lo.h>

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------

struct OscData {
    lo_address  addr;
    const char* path;
    lo_server   server;

    OscData()
        : addr(nullptr),
          path(nullptr),
          server(nullptr) {}

    void idle() const
    {
        if (server == nullptr)
            return;

        while (lo_server_recv_noblock(server, 0) != 0) {}
    }

    void send_configure(const char* const key, const char* const value) const
    {
        char targetPath[std::strlen(path)+11];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/configure");
        lo_send(addr, targetPath, "ss", key, value);
    }

    void send_control(const int32_t index, const float value) const
    {
        char targetPath[std::strlen(path)+9];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/control");
        lo_send(addr, targetPath, "if", index, value);
    }

    void send_midi(uchar data[4]) const
    {
        char targetPath[std::strlen(path)+6];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/midi");
        lo_send(addr, targetPath, "m", data);
    }

    void send_update(const char* const url) const
    {
        char targetPath[std::strlen(path)+8];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/update");
        lo_send(addr, targetPath, "s", url);
    }

    void send_exiting() const
    {
        char targetPath[std::strlen(path)+9];
        std::strcpy(targetPath, path);
        std::strcat(targetPath, "/exiting");
        lo_send(addr, targetPath, "");
    }
};

// -----------------------------------------------------------------------

class UIDssi
{
public:
    UIDssi(const OscData& oscData, const char* const uiTitle)
        : fUI(this, 0, nullptr, setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback),
          fHostClosed(false),
          fOscData(oscData)
    {
        fUI.setTitle(uiTitle);
    }

    ~UIDssi()
    {
        if (fOscData.server != nullptr && ! fHostClosed)
            fOscData.send_exiting();
    }

    void exec()
    {
        for (;;)
        {
            fOscData.idle();

            if (fHostClosed || ! fUI.idle())
                break;

            d_msleep(30);
        }
    }

    // -------------------------------------------------------------------

#if DISTRHO_PLUGIN_WANT_STATE
    void dssiui_configure(const char* key, const char* value)
    {
        fUI.stateChanged(key, value);
    }
#endif

    void dssiui_control(ulong index, float value)
    {
        fUI.parameterChanged(index, value);
    }

#if DISTRHO_PLUGIN_WANT_PROGRAMS
    void dssiui_program(ulong bank, ulong program)
    {
        fUI.programChanged(bank * 128 + program);
    }
#endif

    void dssiui_show()
    {
        fUI.setVisible(true);
    }

    void dssiui_hide()
    {
        fUI.setVisible(false);
    }

    void dssiui_quit()
    {
        fHostClosed = true;
        fUI.quit();
    }

    // -------------------------------------------------------------------

protected:
    void setParameterValue(const uint32_t rindex, const float value)
    {
        if (fOscData.server == nullptr)
            return;

        fOscData.send_control(rindex, value);
    }

    void setState(const char* const key, const char* const value)
    {
        if (fOscData.server == nullptr)
            return;

        fOscData.send_configure(key, value);
    }

    void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
    {
        if (fOscData.server == nullptr)
            return;
        if (channel > 0xF)
            return;

        uint8_t mdata[4] = { 0, channel, note, velocity };
        mdata[1] += (velocity != 0) ? 0x90 : 0x80;

        fOscData.send_midi(mdata);
    }

    void setSize(const uint width, const uint height)
    {
        fUI.setSize(width, height);
    }

private:
    UIExporter fUI;
    bool fHostClosed;

    const OscData& fOscData;

    // -------------------------------------------------------------------
    // Callbacks

    #define uiPtr ((UIDssi*)ptr)

    static void setParameterCallback(void* ptr, uint32_t rindex, float value)
    {
        uiPtr->setParameterValue(rindex, value);
    }

    static void setStateCallback(void* ptr, const char* key, const char* value)
    {
        uiPtr->setState(key, value);
    }

    static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
    {
        uiPtr->sendNote(channel, note, velocity);
    }

    static void setSizeCallback(void* ptr, uint width, uint height)
    {
        uiPtr->setSize(width, height);
    }

    #undef uiPtr
};

// -----------------------------------------------------------------------

static OscData     gOscData;
static const char* gUiTitle = nullptr;
static UIDssi*     globalUI = nullptr;

static void initUiIfNeeded()
{
    if (globalUI != nullptr)
        return;

    if (d_lastUiSampleRate == 0.0)
        d_lastUiSampleRate = 44100.0;

    globalUI = new UIDssi(gOscData, gUiTitle);
}

// -----------------------------------------------------------------------

int osc_debug_handler(const char* path, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_debug_handler(\"%s\")", path);
    return 0;

#ifndef DEBUG
    // unused
    (void)path;
#endif
}

void osc_error_handler(int num, const char* msg, const char* path)
{
    d_stderr("osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
}

#if DISTRHO_PLUGIN_WANT_STATE
int osc_configure_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const char* const key   = &argv[0]->s;
    const char* const value = &argv[1]->s;
    d_debug("osc_configure_handler(\"%s\", \"%s\")", key, value);

    initUiIfNeeded();

    globalUI->dssiui_configure(key, value);

    return 0;
}
#endif

int osc_control_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const int32_t rindex = argv[0]->i;
    const float   value  = argv[1]->f;
    d_debug("osc_control_handler(%i, %f)", rindex, value);

    int32_t index = rindex - DISTRHO_PLUGIN_NUM_INPUTS - DISTRHO_PLUGIN_NUM_OUTPUTS;

    // latency
#if DISTRHO_PLUGIN_WANT_LATENCY
    index -= 1;
#endif

    if (index < 0)
        return 0;

    initUiIfNeeded();

    globalUI->dssiui_control(index, value);

    return 0;
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
int osc_program_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const int32_t bank    = argv[0]->i;
    const int32_t program = argv[1]->f;
    d_debug("osc_program_handler(%i, %i)", bank, program);

    initUiIfNeeded();

    globalUI->dssiui_program(bank, program);

    return 0;
}
#endif

int osc_sample_rate_handler(const char*, const char*, lo_arg** argv, int, lo_message, void*)
{
    const int32_t sampleRate = argv[0]->i;
    d_debug("osc_sample_rate_handler(%i)", sampleRate);

    d_lastUiSampleRate = sampleRate;

    return 0;
}

int osc_show_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_show_handler()");

    initUiIfNeeded();

    globalUI->dssiui_show();

    return 0;
}

int osc_hide_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_hide_handler()");

    if (globalUI != nullptr)
        globalUI->dssiui_hide();

    return 0;
}

int osc_quit_handler(const char*, const char*, lo_arg**, int, lo_message, void*)
{
    d_debug("osc_quit_handler()");

    if (globalUI != nullptr)
        globalUI->dssiui_quit();

    return 0;
}

END_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------

int main(int argc, char* argv[])
{
    USE_NAMESPACE_DISTRHO

    // dummy test mode
    if (argc == 1)
    {
        gUiTitle = "DSSI UI Test";

        initUiIfNeeded();
        globalUI->dssiui_show();
        globalUI->exec();

        delete globalUI;
        globalUI = nullptr;

        return 0;
    }

    if (argc != 5)
    {
        fprintf(stderr, "Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>\n", argv[0]);
        return 1;
    }

    const char* oscUrl  = argv[1];
    const char* uiTitle = argv[4];

    char* const oscHost = lo_url_get_hostname(oscUrl);
    char* const oscPort = lo_url_get_port(oscUrl);
    char* const oscPath = lo_url_get_path(oscUrl);
    size_t  oscPathSize = strlen(oscPath);
    lo_address  oscAddr = lo_address_new(oscHost, oscPort);
    lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, osc_error_handler);

    char* const oscServerPath = lo_server_get_url(oscServer);

    char pluginPath[strlen(oscServerPath)+oscPathSize];
    strcpy(pluginPath, oscServerPath);
    strcat(pluginPath, oscPath+1);

#if DISTRHO_PLUGIN_WANT_STATE
    char oscPathConfigure[oscPathSize+11];
    strcpy(oscPathConfigure, oscPath);
    strcat(oscPathConfigure, "/configure");
    lo_server_add_method(oscServer, oscPathConfigure, "ss", osc_configure_handler, nullptr);
#endif

    char oscPathControl[oscPathSize+9];
    strcpy(oscPathControl, oscPath);
    strcat(oscPathControl, "/control");
    lo_server_add_method(oscServer, oscPathControl, "if", osc_control_handler, nullptr);

    d_stdout("oscServerPath:  \"%s\"", oscServerPath);
    d_stdout("pluginPath:     \"%s\"", pluginPath);
    d_stdout("oscPathControl: \"%s\"", oscPathControl);

#if DISTRHO_PLUGIN_WANT_PROGRAMS
    char oscPathProgram[oscPathSize+9];
    strcpy(oscPathProgram, oscPath);
    strcat(oscPathProgram, "/program");
    lo_server_add_method(oscServer, oscPathProgram, "ii", osc_program_handler, nullptr);
#endif

    char oscPathSampleRate[oscPathSize+13];
    strcpy(oscPathSampleRate, oscPath);
    strcat(oscPathSampleRate, "/sample-rate");
    lo_server_add_method(oscServer, oscPathSampleRate, "i", osc_sample_rate_handler, nullptr);

    char oscPathShow[oscPathSize+6];
    strcpy(oscPathShow, oscPath);
    strcat(oscPathShow, "/show");
    lo_server_add_method(oscServer, oscPathShow, "", osc_show_handler, nullptr);

    char oscPathHide[oscPathSize+6];
    strcpy(oscPathHide, oscPath);
    strcat(oscPathHide, "/hide");
    lo_server_add_method(oscServer, oscPathHide, "", osc_hide_handler, nullptr);

    char oscPathQuit[oscPathSize+6];
    strcpy(oscPathQuit, oscPath);
    strcat(oscPathQuit, "/quit");
    lo_server_add_method(oscServer, oscPathQuit, "", osc_quit_handler, nullptr);

    lo_server_add_method(oscServer, nullptr, nullptr, osc_debug_handler, nullptr);

    gUiTitle = uiTitle;

    gOscData.addr   = oscAddr;
    gOscData.path   = oscPath;
    gOscData.server = oscServer;
    gOscData.send_update(pluginPath);

    // wait for init
    for (int i=0; i < 100; ++i)
    {
        lo_server_recv(oscServer);

        if (d_lastUiSampleRate != 0.0 || globalUI != nullptr)
            break;

        d_msleep(50);
    }

    int ret = 1;

    if (d_lastUiSampleRate != 0.0 || globalUI != nullptr)
    {
        initUiIfNeeded();

        globalUI->exec();

        delete globalUI;
        globalUI = nullptr;

        ret = 0;
    }

#if DISTRHO_PLUGIN_WANT_STATE
    lo_server_del_method(oscServer, oscPathConfigure, "ss");
#endif
    lo_server_del_method(oscServer, oscPathControl, "if");
#if DISTRHO_PLUGIN_WANT_PROGRAMS
    lo_server_del_method(oscServer, oscPathProgram, "ii");
#endif
    lo_server_del_method(oscServer, oscPathSampleRate, "i");
    lo_server_del_method(oscServer, oscPathShow, "");
    lo_server_del_method(oscServer, oscPathHide, "");
    lo_server_del_method(oscServer, oscPathQuit, "");
    lo_server_del_method(oscServer, nullptr, nullptr);

    std::free(oscServerPath);
    std::free(oscHost);
    std::free(oscPort);
    std::free(oscPath);

    lo_address_free(oscAddr);
    lo_server_free(oscServer);

    return ret;
}
<|endoftext|>


<commit_before>/*
 * Filter.hh
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#ifndef _LOG4CPP_FILTER_HH
#define _LOG4CPP_FILTER_HH

#include "log4cpp/LoggingEvent.hh"

namespace log4cpp {

    class Filter {
        public:

        typedef enum { DENY = -1,
                       NEUTRAL = 0,
                       ACCEPT = 1
        } Decision;

        Filter();
        virtual ~Filter();

        virtual void setChainedFilter(Filter* filter);
        virtual Filter* getChainedFilter();
        virtual Filter* getEndOfChain();
        virtual void appendChainedFilter(Filter* filter);

        virtual Decision decide(const LoggingEvent& event) = 0;

        protected:
        virtual Decision _decide(const LoggingEvent& event) = 0;

        private:
        Filter* _chainedFilter;

    };

}

#endif // _LOG4CPP_FILTER_HH
<commit_msg>Added DoxyGen comments.<commit_after>/*
 * Filter.hh
 *
 * Copyright 2001, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2001, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#ifndef _LOG4CPP_FILTER_HH
#define _LOG4CPP_FILTER_HH

#include "log4cpp/LoggingEvent.hh"

namespace log4cpp {

    /**
       Users should extend this class to implement customized logging
       event filtering. Note that {@link log4cpp::Category} and {@link
       log4cpp::Appender} have built-in filtering rules. It is suggested
       that you first use and understand the built-in rules before rushing
       to write your own custom filters.

This abstract class assumes and also imposes that filters be
       organized in a linear chain. The {@link #decide
       decide(LoggingEvent)} method of each filter is called sequentially,
       in the order of their addition to the chain.

The {@link #decide decide(LoggingEvent)} method must return a
       Decision value, either DENY, NEUTRAL or ACCCEPT.

If the value DENY is returned, then the log event is
       dropped immediately without consulting with the remaining
       filters.

If the value NEUTRAL is returned, then the next filter
       in the chain is consulted. If there are no more filters in the
       chain, then the log event is logged. Thus, in the presence of no
       filters, the default behaviour is to log all logging events.

If the value ACCEPT is returned, then the log
       event is logged without consulting the remaining filters.

The philosophy of log4j filters is largely inspired from the
       Linux ipchains.
    **/

    class Filter {
        public:

        typedef enum { DENY = -1,
                       NEUTRAL = 0,
                       ACCEPT = 1
        } Decision;

        /**
         * Default Constructor for Filter
         **/
        Filter();

        /**
         * Destructor for Filter
         **/
        virtual ~Filter();

        /**
         * Set the next Filter in the Filter chain
         * @param filter The filter to chain
         **/
        virtual void setChainedFilter(Filter* filter);

        /**
         * Get the next Filter in the Filter chain
         * @return The next Filter or NULL if the current filter is the last
         * in the chain
         **/
        virtual Filter* getChainedFilter();

        /**
         * Get the last Filter in the Filter chain
         * @return The last Filter in the Filter chain
         **/
        virtual Filter* getEndOfChain();

        /**
         * Add a Filter to the end of the Filter chain. Convience method for
         * getEndOfChain()->setChainedFilter(filter).
         * @param filter The filter to add to the end of the chain.
         **/
        virtual void appendChainedFilter(Filter* filter);

        /**
         * Decide whether to accept or deny a LoggingEvent. This method will
         * walk the entire chain until a non neutral decision has been made
         * or the end of the chain has been reached.
         * @param event The LoggingEvent to decide on.
         * @return The Decision
         **/
        virtual Decision decide(const LoggingEvent& event) = 0;

        protected:
        /**
         * Decide whether this Filter accepts or denies the given
         * LoggingEvent. Actual implementation of Filter should override this
         * method and not decide(LoggingEvent&).
         * @param event The LoggingEvent to decide on.
         * @return The Decision
         **/
        virtual Decision _decide(const LoggingEvent& event) = 0;

        private:
        Filter* _chainedFilter;

    };

}

#endif // _LOG4CPP_FILTER_HH
<|endoftext|>