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

#pragma once

namespace etl {

/*!
 * \brief A binary expression
 *
 * A binary expression has a left hand side expression and a right hand side expression and for each element applies a binary opeartor to both expressions.
 */
template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
struct binary_expr final :
        dim_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>,
        value_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>,
        iterable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
{
private:
    static_assert(cpp::or_c<
                      cpp::and_c<std::is_same<LeftExpr, scalar<T>>, std::is_same<RightExpr, scalar<T>>>,
                      cpp::and_c<is_etl_expr<LeftExpr>, std::is_same<RightExpr, scalar<T>>>,
                      cpp::and_c<is_etl_expr<RightExpr>, std::is_same<LeftExpr, scalar<T>>>,
                      cpp::and_c<is_etl_expr<LeftExpr>, is_etl_expr<RightExpr>>>::value,
                  "One argument must be an ETL expression and the other one convertible to T");

    using this_type = binary_expr<T, LeftExpr, BinaryOp, RightExpr>; ///< This type

    LeftExpr lhs;  ///< The Left hand side expression
    RightExpr rhs; ///< The right hand side expression

    friend struct etl_traits<binary_expr>;
    friend struct optimizer<binary_expr>;
    friend struct optimizable<binary_expr>;
    friend struct transformer<binary_expr>;

public:
    using value_type        = T;                              ///< The Value type
    using memory_type       = void;                           ///< The memory type
    using const_memory_type = void;                           ///< The const memory type
    using iterator          = etl::iterator<const this_type>; ///< The iterator type
    using const_iterator    = etl::iterator<const this_type>; ///< The const iterator type

    /*!
     * \brief The vectorization type for V
     */
    template <typename V = default_vec>
    using vec_type       = typename V::template vec_type<T>;

    //Cannot be constructed with no args
    binary_expr() = delete;

    /*!
     * \brief Construct a new binary expression
     * \param l The left hand side of the expression
     * \param r The right hand side of the expression
     */
    binary_expr(LeftExpr l, RightExpr r)
            : lhs(std::forward<LeftExpr>(l)), rhs(std::forward<RightExpr>(r)) {
        //Nothing else to init
    }

    /*!
     * \brief Copy construct a new binary expression
     * \param e The expression from which to copy
     */
    binary_expr(const binary_expr& e) = default;

    /*!
     * \brief Move construct a new binary expression
     * \param e The expression from which to move
     */
    binary_expr(binary_expr&& e) noexcept = default;

    //Expressions are invariant
    binary_expr& operator=(const binary_expr& e) = delete;
    binary_expr& operator=(binary_expr&& e) = delete;

    /*!
     * \brief Test if this expression aliases with the given expression
     * \param rhs The other expression to test
     * \return true if the two expressions aliases, false otherwise
     */
    template <typename E>
    bool alias(const E& other) const noexcept {
        return lhs.alias(other) || rhs.alias(other);
    }

    //Apply the expression

    /*!
     * \brief Returns the element at the given index
     * \param i The index
     * \return a reference to the element at the given index.
     */
    value_type operator[](std::size_t i) const {
        return BinaryOp::apply(lhs[i], rhs[i]);
    }

    /*!
     * \brief Returns the value at the given index
     * This function never alters the state of the container.
     * \param i The index
     * \return the value at the given index.
     */
    value_type read_flat(std::size_t i) const {
        return BinaryOp::apply(lhs.read_flat(i), rhs.read_flat(i));
    }

    /*!
     * \brief Perform several operations at once.
     * \param i The index at which to perform the operation
     * \tparam V The vectorization mode to use
     * \return a vector containing several results of the expression
     */
    template <typename V = default_vec>
    ETL_STRONG_INLINE(vec_type<V>) load(std::size_t i) const {
        return BinaryOp::template load<V>(lhs.template load<V>(i), rhs.template load<V>(i));
    }

    /*!
     * \brief Perform several operations at once.
     * \param i The index at which to perform the operation
     * \tparam V The vectorization mode to use
     * \return a vector containing several results of the expression
     */
    template <typename V = default_vec>
    ETL_STRONG_INLINE(vec_type<V>) loadu(std::size_t i) const {
        return BinaryOp::template load<V>(lhs.template loadu<V>(i), rhs.template loadu<V>(i));
    }

    /*!
     * \brief Returns the value at the given position (args...)
     * \param args The position indices
     * \return The value at the given position (args...)
     */
    template <typename... S, cpp_enable_if(sizeof...(S) == safe_dimensions<this_type>::value)>
    value_type operator()(S... args) const {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return BinaryOp::apply(lhs(args...), rhs(args...));
    }

    /*!
     * \brief Creates a sub view of the expression, effectively removing the first dimension and fixing it to the given index.
     * \param i The index to use
     * \return a sub view of the expression at position i.
     */
    template <bool B = (safe_dimensions<this_type>::value > 1), cpp_enable_if(B)>
    auto operator()(std::size_t i) {
        return sub(*this, i);
    }

    /*!
     * \brief Creates a sub view of the expression, effectively removing the first dimension and fixing it to the given index.
     * \param i The index to use
     * \return a sub view of the expression at position i.
     */
    template <bool B = (safe_dimensions<this_type>::value > 1), cpp_enable_if(B)>
    auto operator()(std::size_t i) const {
        return sub(*this, i);
    }

    /*!
     * \brief Creates a slice view of the matrix, effectively reducing the first dimension.
     * \param first The first index to use
     * \param last The last index to use
     * \return a slice view of the matrix at position i.
     */
    auto slice(std::size_t first, std::size_t last) noexcept {
        return etl::slice(*this, first, last);
    }

    /*!
     * \brief Creates a slice view of the matrix, effectively reducing the first dimension.
     * \param first The first index to use
     * \param last The last index to use
     * \return a slice view of the matrix at position i.
     */
    auto slice(std::size_t first, std::size_t last) const noexcept {
        return etl::slice(*this, first, last);
    }

    // Assignment functions

    /*!
     * \brief Assign to the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_to(L&& lhs)  const {
        std_assign_evaluate(*this, lhs);
    }

    /*!
     * \brief Add to the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_add_to(L&& lhs)  const {
        std_add_evaluate(*this, lhs);
    }

    /*!
     * \brief Sub from the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_sub_to(L&& lhs)  const {
        std_sub_evaluate(*this, lhs);
    }

    /*!
     * \brief Multiply the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mul_to(L&& lhs)  const {
        std_mul_evaluate(*this, lhs);
    }

    /*!
     * \brief Divide the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_div_to(L&& lhs)  const {
        std_div_evaluate(*this, lhs);
    }

    /*!
     * \brief Modulo the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mod_to(L&& lhs)  const {
        std_mod_evaluate(*this, lhs);
    }

    // Internals

    /*!
     * \brief Apply the given visitor to this expression and its descendants.
     * \param visitor The visitor to apply
     */
    void visit(const detail::temporary_allocator_visitor& visitor) const {
        lhs.visit(visitor);
        rhs.visit(visitor);
    }

    /*!
     * \brief Apply the given visitor to this expression and its descendants.
     * \param visitor The visitor to apply
     */
    void visit(const detail::back_propagate_visitor& visitor) const {
        lhs.visit(visitor);
        rhs.visit(visitor);
    }

    /*!
     * \brief Apply the given visitor to this expression and its descendants.
     * \param visitor The visitor to apply
     */
    void visit(detail::evaluator_visitor& visitor) const {
        bool old_need_value = visitor.need_value;
        visitor.need_value = true;
        lhs.visit(visitor);
        visitor.need_value = true;
        rhs.visit(visitor);
        visitor.need_value = old_need_value;
    }

    /*!
     * \brief Prints the type of the binary expression to the stream
     * \param os The output stream
     * \param expr The expression to print
     * \return the output stream
     */
    friend std::ostream& operator<<(std::ostream& os, const binary_expr& expr) {
        if (BinaryOp::desc_func) {
            return os << BinaryOp::desc() << "(" << expr.lhs << ", " << expr.rhs << ")";
        } else {
            return os << "(" << expr.lhs << ' ' << BinaryOp::desc() << ' ' << expr.rhs << ")";
        }
    }
};

/*!
 * \brief Specialization for binary_expr.
 */
template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
struct etl_traits<etl::binary_expr<T, LeftExpr, BinaryOp, RightExpr>> {
    using expr_t       = etl::binary_expr<T, LeftExpr, BinaryOp, RightExpr>; ///< The type of the expression
    using left_expr_t  = std::decay_t<LeftExpr>;                             ///< The type of the left expression
    using right_expr_t = std::decay_t<RightExpr>;                            ///< The type of the right expression
    using value_type   = T;                                                  ///< The value type

    static constexpr bool left_directed = cpp::not_u<etl_traits<left_expr_t>::is_generator>::value; ///< True if directed by the left expression, false otherwise

    using sub_expr_t = std::conditional_t<left_directed, left_expr_t, right_expr_t>; ///< The type of sub expression

    static constexpr bool is_etl                  = true;                                                                                ///< Indicates if the type is an ETL expression
    static constexpr bool is_transformer          = false;                                                                                ///< Indicates if the type is a transformer
    static constexpr bool is_view                 = false;                                                                                ///< Indicates if the type is a view
    static constexpr bool is_magic_view           = false;                                                                                ///< Indicates if the type is a magic view
    static constexpr bool is_fast                 = etl_traits<sub_expr_t>::is_fast;                                                                                ///< Indicates if the expression is fast
    static constexpr bool is_linear               = etl_traits<left_expr_t>::is_linear && etl_traits<right_expr_t>::is_linear && BinaryOp::linear;                            ///< Indicates if the expression is linear
    static constexpr bool is_thread_safe           = etl_traits<left_expr_t>::is_thread_safe && etl_traits<right_expr_t>::is_thread_safe && BinaryOp::thread_safe;             ///< Indicates if the expression is linear
    static constexpr bool is_value                = false;                                                                                ///< Indicates if the expression is of value type
    static constexpr bool is_direct                = false;                                                                                ///< Indicates if the expression has direct memory access
    static constexpr bool is_generator            = etl_traits<left_expr_t>::is_generator && etl_traits<right_expr_t>::is_generator;                                          ///< Indicates if the expression is a generator expression
    static constexpr bool needs_evaluator_visitor = etl_traits<left_expr_t>::needs_evaluator_visitor || etl_traits<right_expr_t>::needs_evaluator_visitor;                    ///< Indicaes if the expression needs an evaluator visitor
    static constexpr bool is_padded               = is_linear && etl_traits<left_expr_t>::is_padded && etl_traits<right_expr_t>::is_padded;                          ///< Indicates if the expression is padded
    static constexpr bool is_aligned               = is_linear && etl_traits<left_expr_t>::is_aligned && etl_traits<right_expr_t>::is_aligned;                          ///< Indicates if the expression is padded
    static constexpr order storage_order          = etl_traits<left_expr_t>::is_generator ? etl_traits<right_expr_t>::storage_order : etl_traits<left_expr_t>::storage_order; ///< The expression storage order

    /*!
     * \brief Indicates if the expression is vectorizable using the
     * given vector mode
     * \tparam V The vector mode
     */
    template <vector_mode_t V>
    using vectorizable = cpp::bool_constant<
        etl_traits<left_expr_t>::template vectorizable<V>::value && etl_traits<right_expr_t>::template vectorizable<V>::value && BinaryOp::template vectorizable<V>::value>;

    /*!
     * \brief Get reference to the main sub expression
     * \param v The binary expr
     * \return a refernece to the main sub expression
     */
    template <bool B = left_directed, cpp_enable_if(B)>
    static constexpr auto& get(const expr_t& v) {
        return v.lhs;
    }

    /*!
     * \brief Get reference to the main sub expression
     * \param v The binary expr
     * \return a refernece to the main sub expression
     */
    template <bool B = left_directed, cpp_disable_if(B)>
    static constexpr auto& get(const expr_t& v) {
        return v.rhs;
    }

    /*!
     * \brief Returns the size of the given expression
     * \param v The expression to get the size for
     * \returns the size of the given expression
     */
    static std::size_t size(const expr_t& v) {
        return etl_traits<sub_expr_t>::size(get(v));
    }

    /*!
     * \brief Returns the dth dimension of the given expression
     * \param v The expression
     * \param d The dimension to get
     * \return The dth dimension of the given expression
     */
    static std::size_t dim(const expr_t& v, std::size_t d) {
        return etl_traits<sub_expr_t>::dim(get(v), d);
    }

    /*!
     * \brief Returns the size of an expression of this fast type.
     * \returns the size of an expression of this fast type.
     */
    static constexpr std::size_t size() {
        return etl_traits<sub_expr_t>::size();
    }

    /*!
     * \brief Returns the Dth dimension of an expression of this type
     * \tparam D The dimension to get
     * \return the Dth dimension of an expression of this type
     */
    template <std::size_t D>
    static constexpr std::size_t dim() {
        return etl_traits<sub_expr_t>::template dim<D>();
    }

    /*!
     * \brief Returns the number of expressions for this type
     * \return the number of dimensions of this type
     */
    static constexpr std::size_t dimensions() {
        return etl_traits<sub_expr_t>::dimensions();
    }
};

} //end of namespace etl
<commit_msg>Fix the doc<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace etl {

/*!
 * \brief A binary expression
 *
 * A binary expression has a left hand side expression and a right hand side expression and for each element applies a binary opeartor to both expressions.
 */
template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
struct binary_expr final :
        dim_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>,
        value_testable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>,
        iterable<binary_expr<T, LeftExpr, BinaryOp, RightExpr>>
{
private:
    static_assert(cpp::or_c<
                      cpp::and_c<std::is_same<LeftExpr, scalar<T>>, std::is_same<RightExpr, scalar<T>>>,
                      cpp::and_c<is_etl_expr<LeftExpr>, std::is_same<RightExpr, scalar<T>>>,
                      cpp::and_c<is_etl_expr<RightExpr>, std::is_same<LeftExpr, scalar<T>>>,
                      cpp::and_c<is_etl_expr<LeftExpr>, is_etl_expr<RightExpr>>>::value,
                  "One argument must be an ETL expression and the other one convertible to T");

    using this_type = binary_expr<T, LeftExpr, BinaryOp, RightExpr>; ///< This type

    LeftExpr lhs;  ///< The Left hand side expression
    RightExpr rhs; ///< The right hand side expression

    friend struct etl_traits<binary_expr>;
    friend struct optimizer<binary_expr>;
    friend struct optimizable<binary_expr>;
    friend struct transformer<binary_expr>;

public:
    using value_type        = T;                              ///< The Value type
    using memory_type       = void;                           ///< The memory type
    using const_memory_type = void;                           ///< The const memory type
    using iterator          = etl::iterator<const this_type>; ///< The iterator type
    using const_iterator    = etl::iterator<const this_type>; ///< The const iterator type

    /*!
     * \brief The vectorization type for V
     */
    template <typename V = default_vec>
    using vec_type       = typename V::template vec_type<T>;

    //Cannot be constructed with no args
    binary_expr() = delete;

    /*!
     * \brief Construct a new binary expression
     * \param l The left hand side of the expression
     * \param r The right hand side of the expression
     */
    binary_expr(LeftExpr l, RightExpr r)
            : lhs(std::forward<LeftExpr>(l)), rhs(std::forward<RightExpr>(r)) {
        //Nothing else to init
    }

    /*!
     * \brief Copy construct a new binary expression
     * \param e The expression from which to copy
     */
    binary_expr(const binary_expr& e) = default;

    /*!
     * \brief Move construct a new binary expression
     * \param e The expression from which to move
     */
    binary_expr(binary_expr&& e) noexcept = default;

    //Expressions are invariant
    binary_expr& operator=(const binary_expr& e) = delete;
    binary_expr& operator=(binary_expr&& e) = delete;

    /*!
     * \brief Test if this expression aliases with the given expression
     * \param other The other expression to test
     * \return true if the two expressions aliases, false otherwise
     */
    template <typename E>
    bool alias(const E& other) const noexcept {
        return lhs.alias(other) || rhs.alias(other);
    }

    //Apply the expression

    /*!
     * \brief Returns the element at the given index
     * \param i The index
     * \return a reference to the element at the given index.
     */
    value_type operator[](std::size_t i) const {
        return BinaryOp::apply(lhs[i], rhs[i]);
    }

    /*!
     * \brief Returns the value at the given index
     * This function never alters the state of the container.
     * \param i The index
     * \return the value at the given index.
     */
    value_type read_flat(std::size_t i) const {
        return BinaryOp::apply(lhs.read_flat(i), rhs.read_flat(i));
    }

    /*!
     * \brief Perform several operations at once.
     * \param i The index at which to perform the operation
     * \tparam V The vectorization mode to use
     * \return a vector containing several results of the expression
     */
    template <typename V = default_vec>
    ETL_STRONG_INLINE(vec_type<V>) load(std::size_t i) const {
        return BinaryOp::template load<V>(lhs.template load<V>(i), rhs.template load<V>(i));
    }

    /*!
     * \brief Perform several operations at once.
     * \param i The index at which to perform the operation
     * \tparam V The vectorization mode to use
     * \return a vector containing several results of the expression
     */
    template <typename V = default_vec>
    ETL_STRONG_INLINE(vec_type<V>) loadu(std::size_t i) const {
        return BinaryOp::template load<V>(lhs.template loadu<V>(i), rhs.template loadu<V>(i));
    }

    /*!
     * \brief Returns the value at the given position (args...)
     * \param args The position indices
     * \return The value at the given position (args...)
     */
    template <typename... S, cpp_enable_if(sizeof...(S) == safe_dimensions<this_type>::value)>
    value_type operator()(S... args) const {
        static_assert(cpp::all_convertible_to<std::size_t, S...>::value, "Invalid size types");

        return BinaryOp::apply(lhs(args...), rhs(args...));
    }

    /*!
     * \brief Creates a sub view of the expression, effectively removing the first dimension and fixing it to the given index.
     * \param i The index to use
     * \return a sub view of the expression at position i.
     */
    template <bool B = (safe_dimensions<this_type>::value > 1), cpp_enable_if(B)>
    auto operator()(std::size_t i) {
        return sub(*this, i);
    }

    /*!
     * \brief Creates a sub view of the expression, effectively removing the first dimension and fixing it to the given index.
     * \param i The index to use
     * \return a sub view of the expression at position i.
     */
    template <bool B = (safe_dimensions<this_type>::value > 1), cpp_enable_if(B)>
    auto operator()(std::size_t i) const {
        return sub(*this, i);
    }

    /*!
     * \brief Creates a slice view of the matrix, effectively reducing the first dimension.
     * \param first The first index to use
     * \param last The last index to use
     * \return a slice view of the matrix at position i.
     */
    auto slice(std::size_t first, std::size_t last) noexcept {
        return etl::slice(*this, first, last);
    }

    /*!
     * \brief Creates a slice view of the matrix, effectively reducing the first dimension.
     * \param first The first index to use
     * \param last The last index to use
     * \return a slice view of the matrix at position i.
     */
    auto slice(std::size_t first, std::size_t last) const noexcept {
        return etl::slice(*this, first, last);
    }

    // Assignment functions

    /*!
     * \brief Assign to the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_to(L&& lhs)  const {
        std_assign_evaluate(*this, lhs);
    }

    /*!
     * \brief Add to the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_add_to(L&& lhs)  const {
        std_add_evaluate(*this, lhs);
    }

    /*!
     * \brief Sub from the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_sub_to(L&& lhs)  const {
        std_sub_evaluate(*this, lhs);
    }

    /*!
     * \brief Multiply the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mul_to(L&& lhs)  const {
        std_mul_evaluate(*this, lhs);
    }

    /*!
     * \brief Divide the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_div_to(L&& lhs)  const {
        std_div_evaluate(*this, lhs);
    }

    /*!
     * \brief Modulo the given left-hand-side expression
     * \param lhs The expression to which assign
     */
    template<typename L>
    void assign_mod_to(L&& lhs)  const {
        std_mod_evaluate(*this, lhs);
    }

    // Internals

    /*!
     * \brief Apply the given visitor to this expression and its descendants.
     * \param visitor The visitor to apply
     */
    void visit(const detail::temporary_allocator_visitor& visitor) const {
        lhs.visit(visitor);
        rhs.visit(visitor);
    }

    /*!
     * \brief Apply the given visitor to this expression and its descendants.
     * \param visitor The visitor to apply
     */
    void visit(const detail::back_propagate_visitor& visitor) const {
        lhs.visit(visitor);
        rhs.visit(visitor);
    }

    /*!
     * \brief Apply the given visitor to this expression and its descendants.
     * \param visitor The visitor to apply
     */
    void visit(detail::evaluator_visitor& visitor) const {
        bool old_need_value = visitor.need_value;
        visitor.need_value = true;
        lhs.visit(visitor);
        visitor.need_value = true;
        rhs.visit(visitor);
        visitor.need_value = old_need_value;
    }

    /*!
     * \brief Prints the type of the binary expression to the stream
     * \param os The output stream
     * \param expr The expression to print
     * \return the output stream
     */
    friend std::ostream& operator<<(std::ostream& os, const binary_expr& expr) {
        if (BinaryOp::desc_func) {
            return os << BinaryOp::desc() << "(" << expr.lhs << ", " << expr.rhs << ")";
        } else {
            return os << "(" << expr.lhs << ' ' << BinaryOp::desc() << ' ' << expr.rhs << ")";
        }
    }
};

/*!
 * \brief Specialization for binary_expr.
 */
template <typename T, typename LeftExpr, typename BinaryOp, typename RightExpr>
struct etl_traits<etl::binary_expr<T, LeftExpr, BinaryOp, RightExpr>> {
    using expr_t       = etl::binary_expr<T, LeftExpr, BinaryOp, RightExpr>; ///< The type of the expression
    using left_expr_t  = std::decay_t<LeftExpr>;                             ///< The type of the left expression
    using right_expr_t = std::decay_t<RightExpr>;                            ///< The type of the right expression
    using value_type   = T;                                                  ///< The value type

    static constexpr bool left_directed = cpp::not_u<etl_traits<left_expr_t>::is_generator>::value; ///< True if directed by the left expression, false otherwise

    using sub_expr_t = std::conditional_t<left_directed, left_expr_t, right_expr_t>; ///< The type of sub expression

    static constexpr bool is_etl                  = true;                                                                                ///< Indicates if the type is an ETL expression
    static constexpr bool is_transformer          = false;                                                                                ///< Indicates if the type is a transformer
    static constexpr bool is_view                 = false;                                                                                ///< Indicates if the type is a view
    static constexpr bool is_magic_view           = false;                                                                                ///< Indicates if the type is a magic view
    static constexpr bool is_fast                 = etl_traits<sub_expr_t>::is_fast;                                                                                ///< Indicates if the expression is fast
    static constexpr bool is_linear               = etl_traits<left_expr_t>::is_linear && etl_traits<right_expr_t>::is_linear && BinaryOp::linear;                            ///< Indicates if the expression is linear
    static constexpr bool is_thread_safe           = etl_traits<left_expr_t>::is_thread_safe && etl_traits<right_expr_t>::is_thread_safe && BinaryOp::thread_safe;             ///< Indicates if the expression is linear
    static constexpr bool is_value                = false;                                                                                ///< Indicates if the expression is of value type
    static constexpr bool is_direct                = false;                                                                                ///< Indicates if the expression has direct memory access
    static constexpr bool is_generator            = etl_traits<left_expr_t>::is_generator && etl_traits<right_expr_t>::is_generator;                                          ///< Indicates if the expression is a generator expression
    static constexpr bool needs_evaluator_visitor = etl_traits<left_expr_t>::needs_evaluator_visitor || etl_traits<right_expr_t>::needs_evaluator_visitor;                    ///< Indicaes if the expression needs an evaluator visitor
    static constexpr bool is_padded               = is_linear && etl_traits<left_expr_t>::is_padded && etl_traits<right_expr_t>::is_padded;                          ///< Indicates if the expression is padded
    static constexpr bool is_aligned               = is_linear && etl_traits<left_expr_t>::is_aligned && etl_traits<right_expr_t>::is_aligned;                          ///< Indicates if the expression is padded
    static constexpr order storage_order          = etl_traits<left_expr_t>::is_generator ? etl_traits<right_expr_t>::storage_order : etl_traits<left_expr_t>::storage_order; ///< The expression storage order

    /*!
     * \brief Indicates if the expression is vectorizable using the
     * given vector mode
     * \tparam V The vector mode
     */
    template <vector_mode_t V>
    using vectorizable = cpp::bool_constant<
        etl_traits<left_expr_t>::template vectorizable<V>::value && etl_traits<right_expr_t>::template vectorizable<V>::value && BinaryOp::template vectorizable<V>::value>;

    /*!
     * \brief Get reference to the main sub expression
     * \param v The binary expr
     * \return a refernece to the main sub expression
     */
    template <bool B = left_directed, cpp_enable_if(B)>
    static constexpr auto& get(const expr_t& v) {
        return v.lhs;
    }

    /*!
     * \brief Get reference to the main sub expression
     * \param v The binary expr
     * \return a refernece to the main sub expression
     */
    template <bool B = left_directed, cpp_disable_if(B)>
    static constexpr auto& get(const expr_t& v) {
        return v.rhs;
    }

    /*!
     * \brief Returns the size of the given expression
     * \param v The expression to get the size for
     * \returns the size of the given expression
     */
    static std::size_t size(const expr_t& v) {
        return etl_traits<sub_expr_t>::size(get(v));
    }

    /*!
     * \brief Returns the dth dimension of the given expression
     * \param v The expression
     * \param d The dimension to get
     * \return The dth dimension of the given expression
     */
    static std::size_t dim(const expr_t& v, std::size_t d) {
        return etl_traits<sub_expr_t>::dim(get(v), d);
    }

    /*!
     * \brief Returns the size of an expression of this fast type.
     * \returns the size of an expression of this fast type.
     */
    static constexpr std::size_t size() {
        return etl_traits<sub_expr_t>::size();
    }

    /*!
     * \brief Returns the Dth dimension of an expression of this type
     * \tparam D The dimension to get
     * \return the Dth dimension of an expression of this type
     */
    template <std::size_t D>
    static constexpr std::size_t dim() {
        return etl_traits<sub_expr_t>::template dim<D>();
    }

    /*!
     * \brief Returns the number of expressions for this type
     * \return the number of dimensions of this type
     */
    static constexpr std::size_t dimensions() {
        return etl_traits<sub_expr_t>::dimensions();
    }
};

} //end of namespace etl
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **************************************************************************/

#ifndef REALM_COLUMN_TIMESTAMP_HPP
#define REALM_COLUMN_TIMESTAMP_HPP

#include <realm/column.hpp>
#include <realm/timestamp.hpp>

namespace realm {

// Inherits from ColumnTemplate to get a compare_values() that can be called without knowing the
// column type
class TimestampColumn : public ColumnBaseSimple {
public:
    TimestampColumn(bool nullable, Allocator& alloc, ref_type ref, size_t col_ndx = npos);

    static ref_type create(Allocator& alloc, size_t size, bool nullable);
    static size_t get_size_from_ref(ref_type root_ref, Allocator& alloc) noexcept;

    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows, bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;

    bool has_search_index() const noexcept final
    {
        return bool(m_search_index);
    }
    StringIndex* get_search_index() noexcept final
    {
        return m_search_index.get();
    }
    StringIndex* get_search_index() const noexcept final
    {
        return m_search_index.get();
    }
    void destroy_search_index() noexcept override;
    void set_search_index_ref(ref_type ref, ArrayParent* parent, size_t ndx_in_parent,
                              bool allow_duplicate_values) final;
    void populate_search_index();
    StringIndex* create_search_index() override;
    bool supports_search_index() const noexcept final
    {
        return true;
    }

    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void set_ndx_in_parent(size_t ndx) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;

    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;

    void add(const Timestamp& ts = Timestamp{});
    Timestamp get(size_t row_ndx) const noexcept;
    void set(size_t row_ndx, const Timestamp& ts);
    bool compare(const TimestampColumn& c) const noexcept;
    int compare_values(size_t row1, size_t row2) const noexcept override;

    Timestamp maximum(size_t* result_index) const;
    Timestamp minimum(size_t* result_index) const;
    size_t count(Timestamp) const;
    void erase(size_t row_ndx, bool is_last);

    template <class Condition>
    size_t find(Timestamp value, size_t begin, size_t end) const noexcept
    {
        // FIXME: Here we can do all sorts of clever optimizations. Use bithack-search on seconds, then for each match
        // check nanoseconds, etc. Lots of possibilities. Below code is naive and slow but works.

        Condition cond;
        for (size_t t = begin; t < end; t++) {
            Timestamp ts = get(t);
            if (cond(ts, value, ts.is_null(), value.is_null()))
                return t;
        }
        return npos;
    }

    typedef Timestamp value_type;

private:
    std::unique_ptr<BpTree<util::Optional<int64_t>>> m_seconds;
    std::unique_ptr<BpTree<int64_t>> m_nanoseconds;

    std::unique_ptr<StringIndex> m_search_index;
    bool m_nullable;

    template <class BT>
    class CreateHandler;

    template <class Condition>
    Timestamp minmax(size_t* result_index) const noexcept
    {
        // Condition is realm::Greater for maximum and realm::Less for minimum. Any non-null value is both larger
        // and smaller than a non-null value.
        if (size() == 0) {
            if (result_index)
                *result_index = npos;
            return Timestamp{};
        }

        Timestamp best = get(0);
        size_t best_index = 0;

        for (size_t i = 1; i < size(); ++i) {
            Timestamp candidate = get(i);
            if (best.is_null() && !candidate.is_null() || Condition()(candidate, best, candidate.is_null(), best.is_null())) {
                best = candidate;
                best_index = i;
            }
        }
        if (result_index)
            *result_index = best_index;
        return best;
    }
};

} // namespace realm

#endif // REALM_COLUMN_TIMESTAMP_HPP
<commit_msg>Jenkins warning<commit_after>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **************************************************************************/

#ifndef REALM_COLUMN_TIMESTAMP_HPP
#define REALM_COLUMN_TIMESTAMP_HPP

#include <realm/column.hpp>
#include <realm/timestamp.hpp>

namespace realm {

// Inherits from ColumnTemplate to get a compare_values() that can be called without knowing the
// column type
class TimestampColumn : public ColumnBaseSimple {
public:
    TimestampColumn(bool nullable, Allocator& alloc, ref_type ref, size_t col_ndx = npos);

    static ref_type create(Allocator& alloc, size_t size, bool nullable);
    static size_t get_size_from_ref(ref_type root_ref, Allocator& alloc) noexcept;

    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows, bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;

    bool has_search_index() const noexcept final
    {
        return bool(m_search_index);
    }
    StringIndex* get_search_index() noexcept final
    {
        return m_search_index.get();
    }
    StringIndex* get_search_index() const noexcept final
    {
        return m_search_index.get();
    }
    void destroy_search_index() noexcept override;
    void set_search_index_ref(ref_type ref, ArrayParent* parent, size_t ndx_in_parent,
                              bool allow_duplicate_values) final;
    void populate_search_index();
    StringIndex* create_search_index() override;
    bool supports_search_index() const noexcept final
    {
        return true;
    }

    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void set_ndx_in_parent(size_t ndx) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;

    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;

    void add(const Timestamp& ts = Timestamp{});
    Timestamp get(size_t row_ndx) const noexcept;
    void set(size_t row_ndx, const Timestamp& ts);
    bool compare(const TimestampColumn& c) const noexcept;
    int compare_values(size_t row1, size_t row2) const noexcept override;

    Timestamp maximum(size_t* result_index) const;
    Timestamp minimum(size_t* result_index) const;
    size_t count(Timestamp) const;
    void erase(size_t row_ndx, bool is_last);

    template <class Condition>
    size_t find(Timestamp value, size_t begin, size_t end) const noexcept
    {
        // FIXME: Here we can do all sorts of clever optimizations. Use bithack-search on seconds, then for each match
        // check nanoseconds, etc. Lots of possibilities. Below code is naive and slow but works.

        Condition cond;
        for (size_t t = begin; t < end; t++) {
            Timestamp ts = get(t);
            if (cond(ts, value, ts.is_null(), value.is_null()))
                return t;
        }
        return npos;
    }

    typedef Timestamp value_type;

private:
    std::unique_ptr<BpTree<util::Optional<int64_t>>> m_seconds;
    std::unique_ptr<BpTree<int64_t>> m_nanoseconds;

    std::unique_ptr<StringIndex> m_search_index;
    bool m_nullable;

    template <class BT>
    class CreateHandler;

    template <class Condition>
    Timestamp minmax(size_t* result_index) const noexcept
    {
        // Condition is realm::Greater for maximum and realm::Less for minimum. Any non-null value is both larger
        // and smaller than a non-null value.
        if (size() == 0) {
            if (result_index)
                *result_index = npos;
            return Timestamp{};
        }

        Timestamp best = get(0);
        size_t best_index = 0;

        for (size_t i = 1; i < size(); ++i) {
            Timestamp candidate = get(i);
            if ((best.is_null() && !candidate.is_null()) || Condition()(candidate, best, candidate.is_null(), best.is_null())) {
                best = candidate;
                best_index = i;
            }
        }
        if (result_index)
            *result_index = best_index;
        return best;
    }
};

} // namespace realm

#endif // REALM_COLUMN_TIMESTAMP_HPP
<|endoftext|>


<commit_before>#ifndef LIBPORT_SINGLETON_PTR_HH
# define LIBPORT_SINGLETON_PTR_HH

# include <libport/export.hh>

# define STATIC_INSTANCE_(Cl, Name)					\
  class Cl ## Name;							\
  libport::SingletonPtr<Cl ## Name> Name;				\
  template<> Cl ## Name* libport::SingletonPtr<Cl ## Name>::ptr = 0

# define STATIC_INSTANCE_DECL_(Cl, Name)				\
  class Cl ## Name							\
    : public Cl								\
  {};									\
  STATIC_INSTANCE_(Cl, Name)

# define EXTERN_STATIC_INSTANCE_EX(Cl, Name, Api)			\
  class Api Cl ## Name							\
    : public Cl								\
  {};									\
  Api extern libport::SingletonPtr<Cl ## Name> Name;

# define EXTERN_STATIC_INSTANCE(Cl, Name)				\
  EXTERN_STATIC_INSTANCE_EX(Cl, Name, /* No API. */)

// These _NS version are made to bypass vcxx error C2888
// cf: http://msdn.microsoft.com/en-us/library/27zksbks(VS.80).aspx
// Symbol in libport cannot be defined inside urbi. This appeared
// after changes done for liburbi Java.
// Use them "outside" of any namespace.

# define STATIC_INSTANCE_NS_EX(Cl, Name, NS, Api)			\
  namespace NS {							\
    Api libport::SingletonPtr<Cl ## Name> Name;				\
  }									\
  template<> Api NS::Cl ## Name*					\
  libport::SingletonPtr<NS::Cl ## Name>::ptr = 0

# define STATIC_INSTANCE_NS(Cl, Name, NS)				\
  STATIC_INSTANCE_NS_EX(Cl, Name, NS, /* No API */)

# define STATIC_INSTANCE_DECL_NS(Cl, Name, NS)				\
  namespace NS {							\
    class Cl ## Name							\
      : public Cl							\
    {};									\
  }									\
  STATIC_INSTANCE_NS(Cl, Name, NS)

namespace libport
{
  /// Singleton smart pointer that creates the object on demand.
  template<typename T>
  class SingletonPtr
  {
  public:
    operator T* ();
    operator T& ();
    T* operator ->();

  private:
    static T* instance();
    LIBPORT_API static T* ptr;
  };

}  // namespace libport

# include <libport/singleton-ptr.hxx>

#endif // !LIBPORT_SINGLETON_PTR_HH
<commit_msg>Put the export declaration onto the class, not the static member.<commit_after>#ifndef LIBPORT_SINGLETON_PTR_HH
# define LIBPORT_SINGLETON_PTR_HH

# include <libport/export.hh>

# define STATIC_INSTANCE_(Cl, Name)					\
  class Cl ## Name;							\
  libport::SingletonPtr<Cl ## Name> Name;				\
  template<> Cl ## Name* libport::SingletonPtr<Cl ## Name>::ptr = 0

# define STATIC_INSTANCE_DECL_(Cl, Name)				\
  class Cl ## Name							\
    : public Cl								\
  {};									\
  STATIC_INSTANCE_(Cl, Name)

# define EXTERN_STATIC_INSTANCE_EX(Cl, Name, Api)			\
  class Api Cl ## Name							\
    : public Cl								\
  {};									\
  Api extern libport::SingletonPtr<Cl ## Name> Name;

# define EXTERN_STATIC_INSTANCE(Cl, Name)				\
  EXTERN_STATIC_INSTANCE_EX(Cl, Name, /* No API. */)

// These _NS version are made to bypass vcxx error C2888
// cf: http://msdn.microsoft.com/en-us/library/27zksbks(VS.80).aspx
// Symbol in libport cannot be defined inside urbi. This appeared
// after changes done for liburbi Java.
// Use them "outside" of any namespace.

# define STATIC_INSTANCE_NS_EX(Cl, Name, NS, Api)			\
  namespace NS {							\
    Api libport::SingletonPtr<Cl ## Name> Name;				\
  }									\
  template<> Api NS::Cl ## Name*					\
  libport::SingletonPtr<NS::Cl ## Name>::ptr = 0

# define STATIC_INSTANCE_NS(Cl, Name, NS)				\
  STATIC_INSTANCE_NS_EX(Cl, Name, NS, /* No API */)

# define STATIC_INSTANCE_DECL_NS(Cl, Name, NS)				\
  namespace NS {							\
    class Cl ## Name							\
      : public Cl							\
    {};									\
  }									\
  STATIC_INSTANCE_NS(Cl, Name, NS)

namespace libport
{
  /// Singleton smart pointer that creates the object on demand.
  template<typename T>
  class LIBPORT_API SingletonPtr
  {
  public:
    operator T* ();
    operator T& ();
    T* operator ->();

  private:
    static T* instance();
    static T* ptr;
  };

}  // namespace libport

# include <libport/singleton-ptr.hxx>

#endif // !LIBPORT_SINGLETON_PTR_HH
<|endoftext|>


<commit_before>#pragma once

#include <math.h>

namespace lda_util {

    inline bool
    valid_probability_vector(const std::vector<float> &p){
        float sum = 0;
        for(auto x: p){
            if(std::isfinite(x) == false) return false;
            if(x < 0) return false;
            sum+=x;
        }
        return (std::abs(1 - sum) < 0.01);
    }

    template<typename T>
    std::set<T>
    unique_members(std::vector<std::vector<T>> nested_list){
        std::set<T> unique_values;
        for(std::vector<T> list: nested_list){
            for(T val: list){
                unique_values.insert(val);
            }
        }
        return unique_values;
    }

    template<typename T>
    T
    max_element(std::vector<std::vector<T>> nested_list){
        std::set<T> unique_values;
        for(std::vector<T> list: nested_list){
            for(T val: list){
                unique_values.insert(val);
            }
        }
        return *std::max_element(unique_values.begin(), unique_values.end());
    }

    template<typename T> void
    removeFirst(std::vector<T> &v, T element){
        auto it = std::find(v.begin(),v.end(), element);
        if (it != v.end()) {
          v.erase(it);
        }
    }

    // http://stackoverflow.com/a/1267878/982745
    template< class T >
    std::vector<T>
    selectByIndex(const std::vector<T> &v, const std::vector<size_t> &index )  {
        std::vector<T> new_v;
        new_v.reserve(index.size());
        for(size_t i: index){
            new_v.push_back(v[i]);
        }

        return new_v;
    }

    template<class T>
    void
    normalize(std::vector<T> &v){
        Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>> vec(v.data(), v.size());
        vec /= vec.sum();
    }

    template<class T, class J>
    class defaultdict{
        J default_value;
        std::map<T, J> map;
    public:
        defaultdict(J val){
            default_value = val;
            map = std::map<T, J>();
        }

        J get(T t) {
            if(map.count(t) > 0){
                return map[t];
            }
            else{
                return default_value;
            }
        }

        void
        set(T t, J j){
            map[t] = j;
        }

        void
        incr(T t, J by){
            if(map.count(t) > 0){
                map[t] += by;
            }
            else{
                map[t] = by + default_value;
            }
        }

        void
        decr(T t, J by){
            if(map.count(t) > 0){
                map[t] -= by;
            }
            else{
                map[t] = default_value - by;
            }
        }

        bool
        contains(T t){
            return map.count(t) > 0;
        }
    };
}<commit_msg>Add includes for stl<commit_after>#pragma once

#include <math.h>
#include <vector>
#include <set>

namespace lda_util {

    inline bool
    valid_probability_vector(const std::vector<float> &p){
        float sum = 0;
        for(auto x: p){
            if(std::isfinite(x) == false) return false;
            if(x < 0) return false;
            sum+=x;
        }
        return (std::abs(1 - sum) < 0.01);
    }

    template<typename T>
    std::set<T>
    unique_members(std::vector<std::vector<T>> nested_list){
        std::set<T> unique_values;
        for(std::vector<T> list: nested_list){
            for(T val: list){
                unique_values.insert(val);
            }
        }
        return unique_values;
    }

    template<typename T>
    T
    max_element(std::vector<std::vector<T>> nested_list){
        std::set<T> unique_values;
        for(std::vector<T> list: nested_list){
            for(T val: list){
                unique_values.insert(val);
            }
        }
        return *std::max_element(unique_values.begin(), unique_values.end());
    }

    template<typename T> void
    removeFirst(std::vector<T> &v, T element){
        auto it = std::find(v.begin(),v.end(), element);
        if (it != v.end()) {
          v.erase(it);
        }
    }

    // http://stackoverflow.com/a/1267878/982745
    template< class T >
    std::vector<T>
    selectByIndex(const std::vector<T> &v, const std::vector<size_t> &index )  {
        std::vector<T> new_v;
        new_v.reserve(index.size());
        for(size_t i: index){
            new_v.push_back(v[i]);
        }

        return new_v;
    }

    template<class T>
    void
    normalize(std::vector<T> &v){
        Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1>> vec(v.data(), v.size());
        vec /= vec.sum();
    }

    template<class T, class J>
    class defaultdict{
        J default_value;
        std::map<T, J> map;
    public:
        defaultdict(J val){
            default_value = val;
            map = std::map<T, J>();
        }

        J get(T t) {
            if(map.count(t) > 0){
                return map[t];
            }
            else{
                return default_value;
            }
        }

        void
        set(T t, J j){
            map[t] = j;
        }

        void
        incr(T t, J by){
            if(map.count(t) > 0){
                map[t] += by;
            }
            else{
                map[t] = by + default_value;
            }
        }

        void
        decr(T t, J by){
            if(map.count(t) > 0){
                map[t] -= by;
            }
            else{
                map[t] = default_value - by;
            }
        }

        bool
        contains(T t){
            return map.count(t) > 0;
        }
    };
}<|endoftext|>


<commit_before>/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "brw_vec4.h"
#include "brw_vec4_live_variables.h"
#include "brw_cfg.h"

/** @file brw_vec4_dead_code_eliminate.cpp
 *
 * Dataflow-aware dead code elimination.
 *
 * Walks the instruction list from the bottom, removing instructions that
 * have results that both aren't used in later blocks and haven't been read
 * yet in the tail end of this block.
 */

using namespace brw;

bool
vec4_visitor::dead_code_eliminate()
{
   bool progress = false;

   calculate_live_intervals();

   int num_vars = live_intervals->num_vars;
   BITSET_WORD *live = ralloc_array(NULL, BITSET_WORD, BITSET_WORDS(num_vars));
   BITSET_WORD *flag_live = ralloc_array(NULL, BITSET_WORD, 1);

   foreach_block_reverse_safe(block, cfg) {
      memcpy(live, live_intervals->block_data[block->num].liveout,
             sizeof(BITSET_WORD) * BITSET_WORDS(num_vars));
      memcpy(flag_live, live_intervals->block_data[block->num].flag_liveout,
             sizeof(BITSET_WORD));

      foreach_inst_in_block_reverse_safe(vec4_instruction, inst, block) {
         if ((inst->dst.file == VGRF && !inst->has_side_effects()) ||
             (inst->dst.is_null() && inst->writes_flag())){
            bool result_live[4] = { false };

            if (inst->dst.file == VGRF) {
               for (unsigned i = 0; i < regs_written(inst); i++) {
                  for (int c = 0; c < 4; c++)
                     result_live[c] |= BITSET_TEST(live,
                        var_from_reg(alloc,
                                     byte_offset(inst->dst, i * REG_SIZE), c));
               }
            } else {
               for (unsigned c = 0; c < 4; c++)
                  result_live[c] = BITSET_TEST(flag_live, c);
            }

            /* If the instruction can't do writemasking, then it's all or
             * nothing.
             */
            if (!inst->can_do_writemask(devinfo)) {
               bool result = result_live[0] | result_live[1] |
                             result_live[2] | result_live[3];
               result_live[0] = result;
               result_live[1] = result;
               result_live[2] = result;
               result_live[3] = result;
            }

            for (int c = 0; c < 4; c++) {
               if (!result_live[c] && inst->dst.writemask & (1 << c)) {
                  inst->dst.writemask &= ~(1 << c);
                  progress = true;

                  if (inst->dst.writemask == 0) {
                     if (inst->writes_accumulator || inst->writes_flag()) {
                        inst->dst = dst_reg(retype(brw_null_reg(), inst->dst.type));
                     } else {
                        inst->opcode = BRW_OPCODE_NOP;
                        break;
                     }
                  }
               }
            }
         }

         if (inst->dst.is_null() && inst->writes_flag()) {
            bool combined_live = false;
            for (unsigned c = 0; c < 4; c++)
               combined_live |= BITSET_TEST(flag_live, c);

            if (!combined_live) {
               inst->opcode = BRW_OPCODE_NOP;
               progress = true;
            }
         }

         if (inst->dst.file == VGRF && !inst->predicate) {
            for (unsigned i = 0; i < regs_written(inst); i++) {
               for (int c = 0; c < 4; c++) {
                  if (inst->dst.writemask & (1 << c)) {
                     BITSET_CLEAR(live,
                                  var_from_reg(alloc,
                                               byte_offset(inst->dst,
                                                           i * REG_SIZE),
                                               c));
                  }
               }
            }
         }

         if (inst->writes_flag() && !inst->predicate) {
            for (unsigned c = 0; c < 4; c++)
               BITSET_CLEAR(flag_live, c);
         }

         if (inst->opcode == BRW_OPCODE_NOP) {
            inst->remove(block);
            continue;
         }

         for (int i = 0; i < 3; i++) {
            if (inst->src[i].file == VGRF) {
               for (unsigned j = 0; j < regs_read(inst, i); j++) {
                  for (int c = 0; c < 4; c++) {
                     BITSET_SET(live, var_from_reg(alloc,
                                                   byte_offset(inst->src[i],
                                                               j * REG_SIZE),
                                                   c));
                  }
               }
            }
         }

         for (unsigned c = 0; c < 4; c++) {
            if (inst->reads_flag(c)) {
               BITSET_SET(flag_live, c);
            }
         }
      }
   }

   ralloc_free(live);
   ralloc_free(flag_live);

   if (progress)
      invalidate_live_intervals();

   return progress;
}
<commit_msg>i965/vec4: zero allocated memory where needed<commit_after>/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "brw_vec4.h"
#include "brw_vec4_live_variables.h"
#include "brw_cfg.h"

/** @file brw_vec4_dead_code_eliminate.cpp
 *
 * Dataflow-aware dead code elimination.
 *
 * Walks the instruction list from the bottom, removing instructions that
 * have results that both aren't used in later blocks and haven't been read
 * yet in the tail end of this block.
 */

using namespace brw;

bool
vec4_visitor::dead_code_eliminate()
{
   bool progress = false;

   calculate_live_intervals();

   int num_vars = live_intervals->num_vars;
   BITSET_WORD *live = rzalloc_array(NULL, BITSET_WORD, BITSET_WORDS(num_vars));
   BITSET_WORD *flag_live = rzalloc_array(NULL, BITSET_WORD, 1);

   foreach_block_reverse_safe(block, cfg) {
      memcpy(live, live_intervals->block_data[block->num].liveout,
             sizeof(BITSET_WORD) * BITSET_WORDS(num_vars));
      memcpy(flag_live, live_intervals->block_data[block->num].flag_liveout,
             sizeof(BITSET_WORD));

      foreach_inst_in_block_reverse_safe(vec4_instruction, inst, block) {
         if ((inst->dst.file == VGRF && !inst->has_side_effects()) ||
             (inst->dst.is_null() && inst->writes_flag())){
            bool result_live[4] = { false };

            if (inst->dst.file == VGRF) {
               for (unsigned i = 0; i < regs_written(inst); i++) {
                  for (int c = 0; c < 4; c++)
                     result_live[c] |= BITSET_TEST(live,
                        var_from_reg(alloc,
                                     byte_offset(inst->dst, i * REG_SIZE), c));
               }
            } else {
               for (unsigned c = 0; c < 4; c++)
                  result_live[c] = BITSET_TEST(flag_live, c);
            }

            /* If the instruction can't do writemasking, then it's all or
             * nothing.
             */
            if (!inst->can_do_writemask(devinfo)) {
               bool result = result_live[0] | result_live[1] |
                             result_live[2] | result_live[3];
               result_live[0] = result;
               result_live[1] = result;
               result_live[2] = result;
               result_live[3] = result;
            }

            for (int c = 0; c < 4; c++) {
               if (!result_live[c] && inst->dst.writemask & (1 << c)) {
                  inst->dst.writemask &= ~(1 << c);
                  progress = true;

                  if (inst->dst.writemask == 0) {
                     if (inst->writes_accumulator || inst->writes_flag()) {
                        inst->dst = dst_reg(retype(brw_null_reg(), inst->dst.type));
                     } else {
                        inst->opcode = BRW_OPCODE_NOP;
                        break;
                     }
                  }
               }
            }
         }

         if (inst->dst.is_null() && inst->writes_flag()) {
            bool combined_live = false;
            for (unsigned c = 0; c < 4; c++)
               combined_live |= BITSET_TEST(flag_live, c);

            if (!combined_live) {
               inst->opcode = BRW_OPCODE_NOP;
               progress = true;
            }
         }

         if (inst->dst.file == VGRF && !inst->predicate) {
            for (unsigned i = 0; i < regs_written(inst); i++) {
               for (int c = 0; c < 4; c++) {
                  if (inst->dst.writemask & (1 << c)) {
                     BITSET_CLEAR(live,
                                  var_from_reg(alloc,
                                               byte_offset(inst->dst,
                                                           i * REG_SIZE),
                                               c));
                  }
               }
            }
         }

         if (inst->writes_flag() && !inst->predicate) {
            for (unsigned c = 0; c < 4; c++)
               BITSET_CLEAR(flag_live, c);
         }

         if (inst->opcode == BRW_OPCODE_NOP) {
            inst->remove(block);
            continue;
         }

         for (int i = 0; i < 3; i++) {
            if (inst->src[i].file == VGRF) {
               for (unsigned j = 0; j < regs_read(inst, i); j++) {
                  for (int c = 0; c < 4; c++) {
                     BITSET_SET(live, var_from_reg(alloc,
                                                   byte_offset(inst->src[i],
                                                               j * REG_SIZE),
                                                   c));
                  }
               }
            }
         }

         for (unsigned c = 0; c < 4; c++) {
            if (inst->reads_flag(c)) {
               BITSET_SET(flag_live, c);
            }
         }
      }
   }

   ralloc_free(live);
   ralloc_free(flag_live);

   if (progress)
      invalidate_live_intervals();

   return progress;
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "test/scenario/network_node.h"

#include <algorithm>
#include <vector>

#include <memory>
#include "rtc_base/numerics/safe_minmax.h"

namespace webrtc {
namespace test {
namespace {
constexpr char kDummyTransportName[] = "dummy";
SimulatedNetwork::Config CreateSimulationConfig(
    NetworkSimulationConfig config) {
  SimulatedNetwork::Config sim_config;
  sim_config.link_capacity_kbps = config.bandwidth.kbps_or(0);
  sim_config.loss_percent = config.loss_rate * 100;
  sim_config.queue_delay_ms = config.delay.ms();
  sim_config.delay_standard_deviation_ms = config.delay_std_dev.ms();
  sim_config.packet_overhead = config.packet_overhead.bytes<int>();
  sim_config.codel_active_queue_management =
      config.codel_active_queue_management;
  sim_config.queue_length_packets =
      config.packet_queue_length_limit.value_or(0);
  return sim_config;
}
}  // namespace

SimulationNode::SimulationNode(NetworkSimulationConfig config,
                               SimulatedNetwork* behavior,
                               EmulatedNetworkNode* network_node)
    : config_(config), simulation_(behavior), network_node_(network_node) {}

std::unique_ptr<SimulatedNetwork> SimulationNode::CreateBehavior(
    NetworkSimulationConfig config) {
  SimulatedNetwork::Config sim_config = CreateSimulationConfig(config);
  return std::make_unique<SimulatedNetwork>(sim_config);
}

void SimulationNode::UpdateConfig(
    std::function<void(NetworkSimulationConfig*)> modifier) {
  modifier(&config_);
  SimulatedNetwork::Config sim_config = CreateSimulationConfig(config_);
  simulation_->SetConfig(sim_config);
}

void SimulationNode::PauseTransmissionUntil(Timestamp until) {
  simulation_->PauseTransmissionUntil(until.us());
}

ColumnPrinter SimulationNode::ConfigPrinter() const {
  return ColumnPrinter::Lambda(
      "propagation_delay capacity loss_rate",
      [this](rtc::SimpleStringBuilder& sb) {
        sb.AppendFormat("%.3lf %.0lf %.2lf", config_.delay.seconds<double>(),
                        config_.bandwidth.bps() / 8.0, config_.loss_rate);
      });
}

NetworkNodeTransport::NetworkNodeTransport(Clock* sender_clock,
                                           Call* sender_call)
    : sender_clock_(sender_clock), sender_call_(sender_call) {}

NetworkNodeTransport::~NetworkNodeTransport() = default;

bool NetworkNodeTransport::SendRtp(const uint8_t* packet,
                                   size_t length,
                                   const PacketOptions& options) {
  int64_t send_time_ms = sender_clock_->TimeInMilliseconds();
  rtc::SentPacket sent_packet;
  sent_packet.packet_id = options.packet_id;
  sent_packet.info.included_in_feedback = options.included_in_feedback;
  sent_packet.info.included_in_allocation = options.included_in_allocation;
  sent_packet.send_time_ms = send_time_ms;
  sent_packet.info.packet_size_bytes = length;
  sent_packet.info.packet_type = rtc::PacketType::kData;
  sender_call_->OnSentPacket(sent_packet);

  rtc::CritScope crit(&crit_sect_);
  if (!endpoint_)
    return false;
  rtc::CopyOnWriteBuffer buffer(packet, length);
  endpoint_->SendPacket(local_address_, remote_address_, buffer,
                        packet_overhead_.bytes());
  return true;
}

bool NetworkNodeTransport::SendRtcp(const uint8_t* packet, size_t length) {
  rtc::CopyOnWriteBuffer buffer(packet, length);
  rtc::CritScope crit(&crit_sect_);
  if (!endpoint_)
    return false;
  endpoint_->SendPacket(local_address_, remote_address_, buffer,
                        packet_overhead_.bytes());
  return true;
}

void NetworkNodeTransport::Connect(EmulatedEndpoint* endpoint,
                                   const rtc::SocketAddress& receiver_address,
                                   DataSize packet_overhead) {
  rtc::NetworkRoute route;
  route.connected = true;
  // We assume that the address will be unique in the lower bytes.
  route.local_network_id = static_cast<uint16_t>(
      receiver_address.ipaddr().v4AddressAsHostOrderInteger());
  route.remote_network_id = static_cast<uint16_t>(
      receiver_address.ipaddr().v4AddressAsHostOrderInteger());
  {
    // Only IPv4 address is supported.
    RTC_CHECK_EQ(receiver_address.family(), AF_INET);
    rtc::CritScope crit(&crit_sect_);
    endpoint_ = endpoint;
    local_address_ = rtc::SocketAddress(endpoint_->GetPeerLocalAddress(), 0);
    remote_address_ = receiver_address;
    packet_overhead_ = packet_overhead;
    current_network_route_ = route;
  }

  sender_call_->GetTransportControllerSend()->OnNetworkRouteChanged(
      kDummyTransportName, route);
}

void NetworkNodeTransport::Disconnect() {
  rtc::CritScope crit(&crit_sect_);
  current_network_route_.connected = false;
  sender_call_->GetTransportControllerSend()->OnNetworkRouteChanged(
      kDummyTransportName, current_network_route_);
  current_network_route_ = {};
  endpoint_ = nullptr;
}

}  // namespace test
}  // namespace webrtc
<commit_msg>Adds transport overhead to route changes in scenario tests.<commit_after>/*
 *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "test/scenario/network_node.h"

#include <algorithm>
#include <vector>

#include <memory>
#include "rtc_base/net_helper.h"
#include "rtc_base/numerics/safe_minmax.h"

namespace webrtc {
namespace test {
namespace {
constexpr char kDummyTransportName[] = "dummy";
SimulatedNetwork::Config CreateSimulationConfig(
    NetworkSimulationConfig config) {
  SimulatedNetwork::Config sim_config;
  sim_config.link_capacity_kbps = config.bandwidth.kbps_or(0);
  sim_config.loss_percent = config.loss_rate * 100;
  sim_config.queue_delay_ms = config.delay.ms();
  sim_config.delay_standard_deviation_ms = config.delay_std_dev.ms();
  sim_config.packet_overhead = config.packet_overhead.bytes<int>();
  sim_config.codel_active_queue_management =
      config.codel_active_queue_management;
  sim_config.queue_length_packets =
      config.packet_queue_length_limit.value_or(0);
  return sim_config;
}
}  // namespace

SimulationNode::SimulationNode(NetworkSimulationConfig config,
                               SimulatedNetwork* behavior,
                               EmulatedNetworkNode* network_node)
    : config_(config), simulation_(behavior), network_node_(network_node) {}

std::unique_ptr<SimulatedNetwork> SimulationNode::CreateBehavior(
    NetworkSimulationConfig config) {
  SimulatedNetwork::Config sim_config = CreateSimulationConfig(config);
  return std::make_unique<SimulatedNetwork>(sim_config);
}

void SimulationNode::UpdateConfig(
    std::function<void(NetworkSimulationConfig*)> modifier) {
  modifier(&config_);
  SimulatedNetwork::Config sim_config = CreateSimulationConfig(config_);
  simulation_->SetConfig(sim_config);
}

void SimulationNode::PauseTransmissionUntil(Timestamp until) {
  simulation_->PauseTransmissionUntil(until.us());
}

ColumnPrinter SimulationNode::ConfigPrinter() const {
  return ColumnPrinter::Lambda(
      "propagation_delay capacity loss_rate",
      [this](rtc::SimpleStringBuilder& sb) {
        sb.AppendFormat("%.3lf %.0lf %.2lf", config_.delay.seconds<double>(),
                        config_.bandwidth.bps() / 8.0, config_.loss_rate);
      });
}

NetworkNodeTransport::NetworkNodeTransport(Clock* sender_clock,
                                           Call* sender_call)
    : sender_clock_(sender_clock), sender_call_(sender_call) {}

NetworkNodeTransport::~NetworkNodeTransport() = default;

bool NetworkNodeTransport::SendRtp(const uint8_t* packet,
                                   size_t length,
                                   const PacketOptions& options) {
  int64_t send_time_ms = sender_clock_->TimeInMilliseconds();
  rtc::SentPacket sent_packet;
  sent_packet.packet_id = options.packet_id;
  sent_packet.info.included_in_feedback = options.included_in_feedback;
  sent_packet.info.included_in_allocation = options.included_in_allocation;
  sent_packet.send_time_ms = send_time_ms;
  sent_packet.info.packet_size_bytes = length;
  sent_packet.info.packet_type = rtc::PacketType::kData;
  sender_call_->OnSentPacket(sent_packet);

  rtc::CritScope crit(&crit_sect_);
  if (!endpoint_)
    return false;
  rtc::CopyOnWriteBuffer buffer(packet, length);
  endpoint_->SendPacket(local_address_, remote_address_, buffer,
                        packet_overhead_.bytes());
  return true;
}

bool NetworkNodeTransport::SendRtcp(const uint8_t* packet, size_t length) {
  rtc::CopyOnWriteBuffer buffer(packet, length);
  rtc::CritScope crit(&crit_sect_);
  if (!endpoint_)
    return false;
  endpoint_->SendPacket(local_address_, remote_address_, buffer,
                        packet_overhead_.bytes());
  return true;
}

void NetworkNodeTransport::Connect(EmulatedEndpoint* endpoint,
                                   const rtc::SocketAddress& receiver_address,
                                   DataSize packet_overhead) {
  rtc::NetworkRoute route;
  route.connected = true;
  // We assume that the address will be unique in the lower bytes.
  route.local_network_id = static_cast<uint16_t>(
      receiver_address.ipaddr().v4AddressAsHostOrderInteger());
  route.remote_network_id = static_cast<uint16_t>(
      receiver_address.ipaddr().v4AddressAsHostOrderInteger());
  route.packet_overhead = packet_overhead.bytes() +
                          receiver_address.ipaddr().overhead() +
                          cricket::kUdpHeaderSize;
  {
    // Only IPv4 address is supported.
    RTC_CHECK_EQ(receiver_address.family(), AF_INET);
    rtc::CritScope crit(&crit_sect_);
    endpoint_ = endpoint;
    local_address_ = rtc::SocketAddress(endpoint_->GetPeerLocalAddress(), 0);
    remote_address_ = receiver_address;
    packet_overhead_ = packet_overhead;
    current_network_route_ = route;
  }

  sender_call_->GetTransportControllerSend()->OnNetworkRouteChanged(
      kDummyTransportName, route);
}

void NetworkNodeTransport::Disconnect() {
  rtc::CritScope crit(&crit_sect_);
  current_network_route_.connected = false;
  sender_call_->GetTransportControllerSend()->OnNetworkRouteChanged(
      kDummyTransportName, current_network_route_);
  current_network_route_ = {};
  endpoint_ = nullptr;
}

}  // namespace test
}  // namespace webrtc
<|endoftext|>