<commit_before>#ifndef AMGCL_RELAXATION_ILUT_HPP
#define AMGCL_RELAXATION_ILUT_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

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 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.
*/

/**
 * \file   amgcl/relaxation/ilut.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Incomplete LU with thresholding relaxation scheme.
 */

#include <vector>
#include <queue>
#include <cmath>

#include <boost/typeof/typeof.hpp>
#include <boost/foreach.hpp>

#include <amgcl/backend/builtin.hpp>
#include <amgcl/util.hpp>
#include <amgcl/relaxation/detail/ilu_solve.hpp>

namespace amgcl {
namespace relaxation {

/// ILUT(p, tau) smoother.
/**
 * \note ILUT is a serial algorithm and is only applicable to backends that
 * support matrix row iteration (e.g. amgcl::backend::builtin or
 * amgcl::backend::eigen).
 *
 * \param Backend Backend for temporary structures allocation.
 * \ingroup relaxation
 */
template <class Backend>
struct ilut {
    typedef typename Backend::value_type      value_type;
    typedef typename Backend::matrix          matrix;
    typedef typename Backend::matrix_diagonal matrix_diagonal;
    typedef typename Backend::vector          vector;

    typedef typename math::scalar_of<value_type>::type scalar_type;

    /// Relaxation parameters.
    struct params {
        /// Maximum fill-in.
        int p;

        /// Minimum magnitude of non-zero elements relative to the current row norm.
        scalar_type tau;

        /// Damping factor.
        scalar_type damping;

        /// Number of Jacobi iterations.
        /** \note Used for approximate solution of triangular systems on parallel backends */
        unsigned jacobi_iters;

        params() : p(2), tau(1e-2f), damping(1), jacobi_iters(2) {}

        params(const boost::property_tree::ptree &p)
            : AMGCL_PARAMS_IMPORT_VALUE(p, p)
            , AMGCL_PARAMS_IMPORT_VALUE(p, tau)
            , AMGCL_PARAMS_IMPORT_VALUE(p, damping)
            , AMGCL_PARAMS_IMPORT_VALUE(p, jacobi_iters)
        {}

        void get(boost::property_tree::ptree &p, const std::string &path) const {
            AMGCL_PARAMS_EXPORT_VALUE(p, path, p);
            AMGCL_PARAMS_EXPORT_VALUE(p, path, tau);
            AMGCL_PARAMS_EXPORT_VALUE(p, path, damping);
            AMGCL_PARAMS_EXPORT_VALUE(p, path, jacobi_iters);
        }
    };

    /// \copydoc amgcl::relaxation::damped_jacobi::damped_jacobi
    template <class Matrix>
    ilut( const Matrix &A, const params &prm, const typename Backend::params &bprm)
    {
        typedef typename backend::row_iterator<Matrix>::type row_iterator;
        const size_t n = backend::rows(A);

        BOOST_AUTO(Aptr, A.ptr_data());
        BOOST_AUTO(Acol, A.col_data());

        size_t Lnz = 0, Unz = 0;

        for(ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
            ptrdiff_t row_beg = Aptr[i];
            ptrdiff_t row_end = Aptr[i + 1];

            for(ptrdiff_t j = row_beg; j < row_end; ++j) {
                ptrdiff_t c = Acol[j];
                if (c < i)
                    ++Lnz;
                else if (c > i)
                    ++Unz;
            }
        }

        boost::shared_ptr<build_matrix> L = boost::make_shared<build_matrix>();
        boost::shared_ptr<build_matrix> U = boost::make_shared<build_matrix>();

        L->nrows = L->ncols = n;
        L->ptr.reserve(n+1); L->ptr.push_back(0);
        L->col.reserve(Lnz + n * prm.p);
        L->val.reserve(Lnz + n * prm.p);

        U->nrows = U->ncols = n;
        U->ptr.reserve(n+1); U->ptr.push_back(0);
        U->col.reserve(Unz + n * prm.p);
        U->val.reserve(Unz + n * prm.p);

        std::vector<value_type> D;
        D.reserve(n);

        sparse_vector w(n);

        for(ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
            w.dia = i;

            int lenL = 0;
            int lenU = 0;

            scalar_type tol = math::zero<scalar_type>();

            for(row_iterator a = backend::row_begin(A, i); a; ++a) {
                w[a.col()] = a.value();
                tol += math::norm(a.value());

                if (a.col() <  i) ++lenL;
                if (a.col() >= i) ++lenU;
            }
            tol = prm.tau / (lenL + lenU);

            while(!w.q.empty()) {
                ptrdiff_t k = w.next_nonzero();
                w[k] = D[k] * w[k];
                value_type wk = w[k];

                if (math::norm(wk) > tol) {
                    for(ptrdiff_t j = U->ptr[k]; j < U->ptr[k+1]; ++j)
                        w[U->col[j]] -= wk * U->val[j];
                }
            }

            w.move_to(lenL + prm.p, lenU + prm.p, tol, *L, *U, D);
        }

        this->D = Backend::copy_vector(D, bprm);
        this->L = Backend::copy_matrix(L, bprm);
        this->U = Backend::copy_matrix(U, bprm);

        if (!serial_backend::value) {
            t1 = Backend::create_vector(n, bprm);
            t2 = Backend::create_vector(n, bprm);
        }
    }

    /// \copydoc amgcl::relaxation::damped_jacobi::apply_pre
    template <class Matrix, class VectorRHS, class VectorX, class VectorTMP>
    void apply_pre(
            const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp,
            const params &prm
            ) const
    {
        backend::residual(rhs, A, x, tmp);
        solve(tmp, prm, serial_backend());
        backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
    }

    /// \copydoc amgcl::relaxation::damped_jacobi::apply_post
    template <class Matrix, class VectorRHS, class VectorX, class VectorTMP>
    void apply_post(
            const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp,
            const params &prm
            ) const
    {
        backend::residual(rhs, A, x, tmp);
        solve(tmp, prm, serial_backend());
        backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
    }

    template <class Matrix, class VectorRHS, class VectorX>
    void apply(const Matrix &A, const VectorRHS &rhs, VectorX &x, const params &prm) const
    {
        backend::copy(rhs, x);
        solve(x, prm, serial_backend());
    }

    private:
        typedef typename boost::is_same<
                Backend, backend::builtin<value_type>
            >::type serial_backend;

        typedef typename backend::builtin<value_type>::matrix build_matrix;

        boost::shared_ptr<matrix> L, U;
        boost::shared_ptr<matrix_diagonal> D;
        boost::shared_ptr<vector> t1, t2;

        struct sparse_vector {
            struct nonzero {
                ptrdiff_t  col;
                value_type val;

                nonzero() : col(-1) {}

                nonzero(ptrdiff_t col, value_type val = value_type())
                    : col(col), val(val) {}
            };

            struct comp_indices {
                const std::vector<nonzero> &nz;

                comp_indices(const std::vector<nonzero> &nz) : nz(nz) {}

                bool operator()(int a, int b) const {
                    return nz[a].col > nz[b].col;
                }
            };

            typedef
                std::priority_queue<int, std::vector<int>, comp_indices>
                priority_queue;

            std::vector<nonzero>   nz;
            std::vector<ptrdiff_t> idx;
            priority_queue q;

            ptrdiff_t dia;

            sparse_vector(size_t n) : idx(n, -1), q(comp_indices(nz)), dia(0) {
                nz.reserve(16);
            }

            value_type operator[](ptrdiff_t i) const {
                if (idx[i] >= 0) return nz[idx[i]].val;
                return value_type();
            }

            value_type& operator[](ptrdiff_t i) {
                if (idx[i] == -1) {
                    int p = nz.size();
                    idx[i] = p;
                    nz.push_back(nonzero(i));
                    if (i < dia) q.push(p);
                }
                return nz[idx[i]].val;
            }

            typename std::vector<nonzero>::iterator begin() {
                return nz.begin();
            }

            typename std::vector<nonzero>::iterator end() {
                return nz.end();
            }

            ptrdiff_t next_nonzero() {
                int p = q.top();
                q.pop();
                return nz[p].col;
            }

            struct higher_than {
                scalar_type tol;
                ptrdiff_t   dia;

                higher_than(scalar_type tol, ptrdiff_t dia)
                    : tol(tol), dia(dia) {}

                bool operator()(const nonzero &v) const {
                    return v.col == dia || math::norm(v.val) > tol;
                }
            };

            struct L_first {
                ptrdiff_t dia;

                L_first(ptrdiff_t dia) : dia(dia) {}

                bool operator()(const nonzero &v) const {
                    return v.col < dia;
                }
            };

            struct by_abs_val {
                ptrdiff_t dia;

                by_abs_val(ptrdiff_t dia) : dia(dia) {}

                bool operator()(const nonzero &a, const nonzero &b) const {
                    if (a.col == dia) return true;
                    if (b.col == dia) return false;

                    return math::norm(a.val) > math::norm(b.val);
                }
            };

            struct by_col {
                bool operator()(const nonzero &a, const nonzero &b) const {
                    return a.col < b.col;
                }
            };

            void move_to(
                    int lp, int up, scalar_type tol,
                    build_matrix &L, build_matrix &U, std::vector<value_type> &D
                    )
            {
                typedef typename std::vector<nonzero>::iterator ptr;

                ptr b = nz.begin();
                ptr e = nz.end();

                // Move zeros to back:
                e = std::partition(b, e, higher_than(tol, dia));

                // Split L and U:
                ptr m = std::partition(b, e, L_first(dia));

                // Get largest p elements in L and U.
                ptr lend = std::min(b + lp, m);
                ptr uend = std::min(m + up, e);

                if (lend != m) std::nth_element(b, lend, m, by_abs_val(dia));
                if (uend != e) std::nth_element(m, uend, e, by_abs_val(dia));

                // Sort entries by column number
                std::sort(b, lend, by_col());
                std::sort(m, uend, by_col());

                // copy L to the output matrix.
                for(ptr a = b; a != lend; ++a) {
                    L.col.push_back(a->col);
                    L.val.push_back(a->val);
                }
                L.ptr.push_back(L.val.size());

                // Store inverted diagonal.
                D.push_back(math::inverse(m->val));
                ++m;

                // copy U to the output matrix.
                for(ptr a = m; a != uend; ++a) {
                    U.col.push_back(a->col);
                    U.val.push_back(a->val);
                }
                U.ptr.push_back(U.val.size());

                BOOST_FOREACH(const nonzero &e, nz) idx[e.col] = -1;
                nz.clear();
            }
        };

        template <class VectorX>
        void solve(VectorX &x, const params &prm, boost::true_type) const
        {
            relaxation::detail::serial_ilu_solve(*L, *U, *D, x);
        }

        template <class VectorX>
        void solve(VectorX &x, const params &prm, boost::false_type) const
        {
            relaxation::detail::parallel_ilu_solve(
                    *L, *U, *D, x, *t1, *t2, prm.jacobi_iters
                    );
        }
};

} // namespace relaxation
} // namespace amgcl

#endif
<commit_msg>Fix an embarassing error in ILUT<commit_after>#ifndef AMGCL_RELAXATION_ILUT_HPP
#define AMGCL_RELAXATION_ILUT_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

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 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.
*/

/**
 * \file   amgcl/relaxation/ilut.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  Incomplete LU with thresholding relaxation scheme.
 */

#include <vector>
#include <queue>
#include <cmath>

#include <boost/typeof/typeof.hpp>
#include <boost/foreach.hpp>

#include <amgcl/backend/builtin.hpp>
#include <amgcl/util.hpp>
#include <amgcl/relaxation/detail/ilu_solve.hpp>

namespace amgcl {
namespace relaxation {

/// ILUT(p, tau) smoother.
/**
 * \note ILUT is a serial algorithm and is only applicable to backends that
 * support matrix row iteration (e.g. amgcl::backend::builtin or
 * amgcl::backend::eigen).
 *
 * \param Backend Backend for temporary structures allocation.
 * \ingroup relaxation
 */
template <class Backend>
struct ilut {
    typedef typename Backend::value_type      value_type;
    typedef typename Backend::matrix          matrix;
    typedef typename Backend::matrix_diagonal matrix_diagonal;
    typedef typename Backend::vector          vector;

    typedef typename math::scalar_of<value_type>::type scalar_type;

    /// Relaxation parameters.
    struct params {
        /// Maximum fill-in.
        int p;

        /// Minimum magnitude of non-zero elements relative to the current row norm.
        scalar_type tau;

        /// Damping factor.
        scalar_type damping;

        /// Number of Jacobi iterations.
        /** \note Used for approximate solution of triangular systems on parallel backends */
        unsigned jacobi_iters;

        params() : p(2), tau(1e-2f), damping(1), jacobi_iters(2) {}

        params(const boost::property_tree::ptree &p)
            : AMGCL_PARAMS_IMPORT_VALUE(p, p)
            , AMGCL_PARAMS_IMPORT_VALUE(p, tau)
            , AMGCL_PARAMS_IMPORT_VALUE(p, damping)
            , AMGCL_PARAMS_IMPORT_VALUE(p, jacobi_iters)
        {}

        void get(boost::property_tree::ptree &p, const std::string &path) const {
            AMGCL_PARAMS_EXPORT_VALUE(p, path, p);
            AMGCL_PARAMS_EXPORT_VALUE(p, path, tau);
            AMGCL_PARAMS_EXPORT_VALUE(p, path, damping);
            AMGCL_PARAMS_EXPORT_VALUE(p, path, jacobi_iters);
        }
    };

    /// \copydoc amgcl::relaxation::damped_jacobi::damped_jacobi
    template <class Matrix>
    ilut( const Matrix &A, const params &prm, const typename Backend::params &bprm)
    {
        typedef typename backend::row_iterator<Matrix>::type row_iterator;
        const size_t n = backend::rows(A);

        BOOST_AUTO(Aptr, A.ptr_data());
        BOOST_AUTO(Acol, A.col_data());

        size_t Lnz = 0, Unz = 0;

        for(ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
            ptrdiff_t row_beg = Aptr[i];
            ptrdiff_t row_end = Aptr[i + 1];

            for(ptrdiff_t j = row_beg; j < row_end; ++j) {
                ptrdiff_t c = Acol[j];
                if (c < i)
                    ++Lnz;
                else if (c > i)
                    ++Unz;
            }
        }

        boost::shared_ptr<build_matrix> L = boost::make_shared<build_matrix>();
        boost::shared_ptr<build_matrix> U = boost::make_shared<build_matrix>();

        L->nrows = L->ncols = n;
        L->ptr.reserve(n+1); L->ptr.push_back(0);
        L->col.reserve(Lnz + n * prm.p);
        L->val.reserve(Lnz + n * prm.p);

        U->nrows = U->ncols = n;
        U->ptr.reserve(n+1); U->ptr.push_back(0);
        U->col.reserve(Unz + n * prm.p);
        U->val.reserve(Unz + n * prm.p);

        std::vector<value_type> D;
        D.reserve(n);

        sparse_vector w(n);

        for(ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(n); ++i) {
            w.dia = i;

            int lenL = 0;
            int lenU = 0;

            scalar_type tol = math::zero<scalar_type>();

            for(row_iterator a = backend::row_begin(A, i); a; ++a) {
                w[a.col()] = a.value();
                tol += math::norm(a.value());

                if (a.col() <  i) ++lenL;
                if (a.col() >= i) ++lenU;
            }
            tol *= prm.tau / (lenL + lenU);

            while(!w.q.empty()) {
                ptrdiff_t k = w.next_nonzero();
                w[k] = D[k] * w[k];
                value_type wk = w[k];

                if (math::norm(wk) > tol) {
                    for(ptrdiff_t j = U->ptr[k]; j < U->ptr[k+1]; ++j)
                        w[U->col[j]] -= wk * U->val[j];
                }
            }

            w.move_to(lenL + prm.p, lenU + prm.p, tol, *L, *U, D);
        }

        this->D = Backend::copy_vector(D, bprm);
        this->L = Backend::copy_matrix(L, bprm);
        this->U = Backend::copy_matrix(U, bprm);

        if (!serial_backend::value) {
            t1 = Backend::create_vector(n, bprm);
            t2 = Backend::create_vector(n, bprm);
        }
    }

    /// \copydoc amgcl::relaxation::damped_jacobi::apply_pre
    template <class Matrix, class VectorRHS, class VectorX, class VectorTMP>
    void apply_pre(
            const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp,
            const params &prm
            ) const
    {
        backend::residual(rhs, A, x, tmp);
        solve(tmp, prm, serial_backend());
        backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
    }

    /// \copydoc amgcl::relaxation::damped_jacobi::apply_post
    template <class Matrix, class VectorRHS, class VectorX, class VectorTMP>
    void apply_post(
            const Matrix &A, const VectorRHS &rhs, VectorX &x, VectorTMP &tmp,
            const params &prm
            ) const
    {
        backend::residual(rhs, A, x, tmp);
        solve(tmp, prm, serial_backend());
        backend::axpby(prm.damping, tmp, math::identity<scalar_type>(), x);
    }

    template <class Matrix, class VectorRHS, class VectorX>
    void apply(const Matrix &A, const VectorRHS &rhs, VectorX &x, const params &prm) const
    {
        backend::copy(rhs, x);
        solve(x, prm, serial_backend());
    }

    private:
        typedef typename boost::is_same<
                Backend, backend::builtin<value_type>
            >::type serial_backend;

        typedef typename backend::builtin<value_type>::matrix build_matrix;

        boost::shared_ptr<matrix> L, U;
        boost::shared_ptr<matrix_diagonal> D;
        boost::shared_ptr<vector> t1, t2;

        struct sparse_vector {
            struct nonzero {
                ptrdiff_t  col;
                value_type val;

                nonzero() : col(-1) {}

                nonzero(ptrdiff_t col, value_type val = value_type())
                    : col(col), val(val) {}
            };

            struct comp_indices {
                const std::vector<nonzero> &nz;

                comp_indices(const std::vector<nonzero> &nz) : nz(nz) {}

                bool operator()(int a, int b) const {
                    return nz[a].col > nz[b].col;
                }
            };

            typedef
                std::priority_queue<int, std::vector<int>, comp_indices>
                priority_queue;

            std::vector<nonzero>   nz;
            std::vector<ptrdiff_t> idx;
            priority_queue q;

            ptrdiff_t dia;

            sparse_vector(size_t n) : idx(n, -1), q(comp_indices(nz)), dia(0) {
                nz.reserve(16);
            }

            value_type operator[](ptrdiff_t i) const {
                if (idx[i] >= 0) return nz[idx[i]].val;
                return value_type();
            }

            value_type& operator[](ptrdiff_t i) {
                if (idx[i] == -1) {
                    int p = nz.size();
                    idx[i] = p;
                    nz.push_back(nonzero(i));
                    if (i < dia) q.push(p);
                }
                return nz[idx[i]].val;
            }

            typename std::vector<nonzero>::iterator begin() {
                return nz.begin();
            }

            typename std::vector<nonzero>::iterator end() {
                return nz.end();
            }

            ptrdiff_t next_nonzero() {
                int p = q.top();
                q.pop();
                return nz[p].col;
            }

            struct higher_than {
                scalar_type tol;
                ptrdiff_t   dia;

                higher_than(scalar_type tol, ptrdiff_t dia)
                    : tol(tol), dia(dia) {}

                bool operator()(const nonzero &v) const {
                    return v.col == dia || math::norm(v.val) > tol;
                }
            };

            struct L_first {
                ptrdiff_t dia;

                L_first(ptrdiff_t dia) : dia(dia) {}

                bool operator()(const nonzero &v) const {
                    return v.col < dia;
                }
            };

            struct by_abs_val {
                ptrdiff_t dia;

                by_abs_val(ptrdiff_t dia) : dia(dia) {}

                bool operator()(const nonzero &a, const nonzero &b) const {
                    if (a.col == dia) return true;
                    if (b.col == dia) return false;

                    return math::norm(a.val) > math::norm(b.val);
                }
            };

            struct by_col {
                bool operator()(const nonzero &a, const nonzero &b) const {
                    return a.col < b.col;
                }
            };

            void move_to(
                    int lp, int up, scalar_type tol,
                    build_matrix &L, build_matrix &U, std::vector<value_type> &D
                    )
            {
                typedef typename std::vector<nonzero>::iterator ptr;

                ptr b = nz.begin();
                ptr e = nz.end();

                // Move zeros to back:
                e = std::partition(b, e, higher_than(tol, dia));

                // Split L and U:
                ptr m = std::partition(b, e, L_first(dia));

                // Get largest p elements in L and U.
                ptr lend = std::min(b + lp, m);
                ptr uend = std::min(m + up, e);

                if (lend != m) std::nth_element(b, lend, m, by_abs_val(dia));
                if (uend != e) std::nth_element(m, uend, e, by_abs_val(dia));

                // Sort entries by column number
                std::sort(b, lend, by_col());
                std::sort(m, uend, by_col());

                // copy L to the output matrix.
                for(ptr a = b; a != lend; ++a) {
                    L.col.push_back(a->col);
                    L.val.push_back(a->val);
                }
                L.ptr.push_back(L.val.size());

                // Store inverted diagonal.
                D.push_back(math::inverse(m->val));
                ++m;

                // copy U to the output matrix.
                for(ptr a = m; a != uend; ++a) {
                    U.col.push_back(a->col);
                    U.val.push_back(a->val);
                }
                U.ptr.push_back(U.val.size());

                BOOST_FOREACH(const nonzero &e, nz) idx[e.col] = -1;
                nz.clear();
            }
        };

        template <class VectorX>
        void solve(VectorX &x, const params &prm, boost::true_type) const
        {
            relaxation::detail::serial_ilu_solve(*L, *U, *D, x);
        }

        template <class VectorX>
        void solve(VectorX &x, const params &prm, boost::false_type) const
        {
            relaxation::detail::parallel_ilu_solve(
                    *L, *U, *D, x, *t1, *t2, prm.jacobi_iters
                    );
        }
};

} // namespace relaxation
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>// RUN: %clangxx -O0 %s -o %t
// RUN: %env_tool_opts=strip_path_prefix=/TestCases/ %run %t 2>&1 | FileCheck %s
// UNSUPPORTED: i386-darwin
//
// Tests __sanitizer_symbolize_pc.
#include <stdio.h>
#include <sanitizer/common_interface_defs.h>

int GLOBAL_VAR_ABC;

void SymbolizeCaller() {
  char data[100];
  __sanitizer_symbolize_pc(__builtin_return_address(0), "%p %F %L", data,
                           sizeof(data));
  printf("FIRST_FORMAT %s\n", data);
  __sanitizer_symbolize_pc(__builtin_return_address(0),
                           "FUNC:%f LINE:%l FILE:%s", data, sizeof(data));
  printf("SECOND_FORMAT %s\n", data);
  __sanitizer_symbolize_pc(__builtin_return_address(0),
                          "LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG"
                          "FUNC:%f LINE:%l FILE:%s", data, sizeof(data));
  printf("LONG_FORMAT %s\n", data);
}

void SymbolizeData() {
  char data[100];
  __sanitizer_symbolize_global(&GLOBAL_VAR_ABC, "%g %s:%l", data, sizeof(data));
  printf("GLOBAL: %s\n", data);
}

// CHECK: FIRST_FORMAT 0x{{.*}} in main symbolize_pc.cc:[[@LINE+3]]
// CHECK: SECOND_FORMAT FUNC:main LINE:[[@LINE+2]] FILE:symbolize_pc.cc
int main() {
  SymbolizeCaller();
  SymbolizeData();
}
// CHECK: GLOBAL: GLOBAL_VAR_ABC
<commit_msg>[asan] Re-enable a test on i386-darwin.<commit_after>// RUN: %clangxx -O0 %s -o %t
// RUN: %env_tool_opts=strip_path_prefix=/TestCases/ %run %t 2>&1 | FileCheck %s
//
// Tests __sanitizer_symbolize_pc.
#include <stdio.h>
#include <sanitizer/common_interface_defs.h>

int GLOBAL_VAR_ABC;

void SymbolizeCaller() {
  char data[100];
  __sanitizer_symbolize_pc(__builtin_return_address(0), "%p %F %L", data,
                           sizeof(data));
  printf("FIRST_FORMAT %s\n", data);
  __sanitizer_symbolize_pc(__builtin_return_address(0),
                           "FUNC:%f LINE:%l FILE:%s", data, sizeof(data));
  printf("SECOND_FORMAT %s\n", data);
  __sanitizer_symbolize_pc(__builtin_return_address(0),
                          "LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
                          "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG"
                          "FUNC:%f LINE:%l FILE:%s", data, sizeof(data));
  printf("LONG_FORMAT %s\n", data);
}

void SymbolizeData() {
  char data[100];
  __sanitizer_symbolize_global(&GLOBAL_VAR_ABC, "%g %s:%l", data, sizeof(data));
  printf("GLOBAL: %s\n", data);
}

// CHECK: FIRST_FORMAT 0x{{.*}} in main symbolize_pc.cc:[[@LINE+3]]
// CHECK: SECOND_FORMAT FUNC:main LINE:[[@LINE+2]] FILE:symbolize_pc.cc
int main() {
  SymbolizeCaller();
  SymbolizeData();
}
// CHECK: GLOBAL: GLOBAL_VAR_ABC
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          tool.cpp
* Purpose:       Implementation of wxExTool class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/file.h>
#include <wx/stdpaths.h>
#include <wx/textfile.h>
#include <wx/extension/tool.h>
#include <wx/extension/statistics.h>
#include <wx/extension/vcs.h>

wxExTool* wxExTool::m_Self = NULL;

wxExTool::wxExTool(int type)
  : m_Id(type)
{
}

wxExTool* wxExTool::Get(bool createOnDemand)
{
  if (m_Self == NULL && createOnDemand)
  {
    m_Self = new wxExTool(0);

    m_Self->AddInfo(ID_TOOL_REVISION_RECENT, _("Recent revision from"));
    m_Self->AddInfo(ID_TOOL_REPORT_REVISION, _("Reported %ld revisions in"), _("Report &Revision"));
    m_Self->AddInfo(ID_TOOL_REPORT_COUNT, _("Counted"), _("Report &Count"));
    m_Self->AddInfo(ID_TOOL_REPORT_FIND, _("Found %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_REPLACE, _("Replaced %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_KEYWORD, _("Reported %ld keywords in"), _("Report &Keyword"));
  }

  return m_Self;
}

const wxString wxExTool::Info() const
{
  if (m_Self == NULL)
  {
    return "No info available";
  }

  const auto it = m_Self->m_ToolInfo.find(m_Id);

  if (it != m_Self->m_ToolInfo.end())
  {
    return it->second.GetInfo();
  }

  wxFAIL;

  return wxEmptyString;
}

void wxExTool::Log(const wxExStatistics<long>* stat) const
{
  wxString logtext(Info());

  if (logtext.Contains("%ld"))
  {
    logtext = logtext.Format(logtext, stat->Get(_("Actions Completed")));
  }

  logtext << " " << stat->Get(_("Files")) << " " << _("file(s)");

  if (stat->Get(_("Files")) != 0)
  {
    if (IsCount())
    {
      wxLogMessage(stat->Get());
    }
  }

  wxLogStatus(logtext);
}

wxExTool* wxExTool::Set(wxExTool* tool)
{
  wxExTool* old = m_Self;
  m_Self = tool;
  return old;
}
<commit_msg>removed no longer needed include files<commit_after>/******************************************************************************\
* File:          tool.cpp
* Purpose:       Implementation of wxExTool class
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/tool.h>
#include <wx/extension/statistics.h>

wxExTool* wxExTool::m_Self = NULL;

wxExTool::wxExTool(int type)
  : m_Id(type)
{
}

wxExTool* wxExTool::Get(bool createOnDemand)
{
  if (m_Self == NULL && createOnDemand)
  {
    m_Self = new wxExTool(0);

    m_Self->AddInfo(ID_TOOL_REVISION_RECENT, _("Recent revision from"));
    m_Self->AddInfo(ID_TOOL_REPORT_REVISION, _("Reported %ld revisions in"), _("Report &Revision"));
    m_Self->AddInfo(ID_TOOL_REPORT_COUNT, _("Counted"), _("Report &Count"));
    m_Self->AddInfo(ID_TOOL_REPORT_FIND, _("Found %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_REPLACE, _("Replaced %ld matches in"));
    m_Self->AddInfo(ID_TOOL_REPORT_KEYWORD, _("Reported %ld keywords in"), _("Report &Keyword"));
  }

  return m_Self;
}

const wxString wxExTool::Info() const
{
  if (m_Self == NULL)
  {
    return "No info available";
  }

  const auto it = m_Self->m_ToolInfo.find(m_Id);

  if (it != m_Self->m_ToolInfo.end())
  {
    return it->second.GetInfo();
  }

  wxFAIL;

  return wxEmptyString;
}

void wxExTool::Log(const wxExStatistics<long>* stat) const
{
  wxString logtext(Info());

  if (logtext.Contains("%ld"))
  {
    logtext = logtext.Format(logtext, stat->Get(_("Actions Completed")));
  }

  logtext << " " << stat->Get(_("Files")) << " " << _("file(s)");

  if (stat->Get(_("Files")) != 0)
  {
    if (IsCount())
    {
      wxLogMessage(stat->Get());
    }
  }

  wxLogStatus(logtext);
}

wxExTool* wxExTool::Set(wxExTool* tool)
{
  wxExTool* old = m_Self;
  m_Self = tool;
  return old;
}
<|endoftext|>


<commit_before>#include "errors.hpp"
#include <boost/make_shared.hpp>

#include "buffer_cache/buffer_cache.hpp"
#include "containers/iterators.hpp"
#include "rdb_protocol/protocol.hpp"
#include "serializer/config.hpp"
#include "serializer/translator.hpp"
#include "unittest/gtest.hpp"
#include "unittest/dummy_namespace_interface.hpp"

namespace unittest {
namespace {

void run_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *)> fun) {
    /* Pick shards */
    std::vector<rdb_protocol_t::region_t> shards;
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::none,   store_key_t(""),  key_range_t::open, store_key_t("n"))));
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::closed, store_key_t("n"), key_range_t::none, store_key_t("") )));

    boost::ptr_vector<mock::temp_file_t> temp_files;
    for (int i = 0; i < (int)shards.size(); i++) {
        temp_files.push_back(new mock::temp_file_t("/tmp/rdb_unittest.XXXXXX"));
    }

    boost::ptr_vector<rdb_protocol_t::store_t> underlying_stores;
    scoped_ptr_t<io_backender_t> io_backender;
    make_io_backender(aio_default, &io_backender);

    for (int i = 0; i < (int)shards.size(); i++) {
        underlying_stores.push_back(new rdb_protocol_t::store_t(io_backender.get(), temp_files[i].name(), true, &get_global_perfmon_collection()));
    }

    boost::ptr_vector<store_view_t<rdb_protocol_t> > stores;
    for (int i = 0; i < (int)shards.size(); i++) {
        stores.push_back(new store_subview_t<rdb_protocol_t>(&underlying_stores[i], shards[i]));
    }

    /* Set up namespace interface */
    dummy_namespace_interface_t<rdb_protocol_t> nsi(shards, stores.c_array());

    fun(&nsi);
}

void run_in_thread_pool_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *)> fun) {
    mock::run_in_thread_pool(boost::bind(&run_with_namespace_interface, fun));
}

}   /* anonymous namespace */

/* `SetupTeardown` makes sure that it can start and stop without anything going
horribly wrong */
void run_setup_teardown_test(UNUSED namespace_interface_t<rdb_protocol_t> *nsi) {
    /* Do nothing */
}
TEST(RDBProtocol, SetupTeardown) {
    run_in_thread_pool_with_namespace_interface(&run_setup_teardown_test);
}

/* `GetSet` tests basic get and set operations */
void run_get_set_test(namespace_interface_t<rdb_protocol_t> *nsi) {
    order_source_t osource;
    boost::shared_ptr<scoped_cJSON_t> data(new scoped_cJSON_t(cJSON_CreateNull()));
    {
        rdb_protocol_t::write_t write(rdb_protocol_t::point_write_t(store_key_t("a"), data));

        cond_t interruptor;
        rdb_protocol_t::write_response_t response = nsi->write(write, osource.check_in("unittest::run_get_set_test(rdb_protocol.cc-A)"), &interruptor);

        if (rdb_protocol_t::point_write_response_t *maybe_point_write_response_t = boost::get<rdb_protocol_t::point_write_response_t>(&response.response)) {
            EXPECT_EQ(maybe_point_write_response_t->result, STORED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        rdb_protocol_t::read_t read(rdb_protocol_t::point_read_t(store_key_t("a")));

        cond_t interruptor;
        rdb_protocol_t::read_response_t response = nsi->read(read, osource.check_in("unittest::run_get_set_test(rdb_protocol.cc-B)"), &interruptor);

        if (rdb_protocol_t::point_read_response_t *maybe_point_read_response = boost::get<rdb_protocol_t::point_read_response_t>(&response.response)) {
            EXPECT_TRUE(maybe_point_read_response->data->get() != NULL);
            EXPECT_TRUE(cJSON_Equal(data->get(), maybe_point_read_response->data->get()));
        } else {
            ADD_FAILURE() << "got wrong result back";
        }
    }
}

TEST(RDBProtocol, GetSet) {
    run_in_thread_pool_with_namespace_interface(&run_get_set_test);
}

}   /* namespace unittest */

<commit_msg>Make rdb_protocol use order sources correctly.<commit_after>#include "errors.hpp"
#include <boost/make_shared.hpp>

#include "buffer_cache/buffer_cache.hpp"
#include "containers/iterators.hpp"
#include "rdb_protocol/protocol.hpp"
#include "serializer/config.hpp"
#include "serializer/translator.hpp"
#include "unittest/gtest.hpp"
#include "unittest/dummy_namespace_interface.hpp"

namespace unittest {
namespace {

void run_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *, order_source_t *)> fun) {

    order_source_t order_source;

    /* Pick shards */
    std::vector<rdb_protocol_t::region_t> shards;
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::none,   store_key_t(""),  key_range_t::open, store_key_t("n"))));
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::closed, store_key_t("n"), key_range_t::none, store_key_t("") )));

    boost::ptr_vector<mock::temp_file_t> temp_files;
    for (int i = 0; i < (int)shards.size(); i++) {
        temp_files.push_back(new mock::temp_file_t("/tmp/rdb_unittest.XXXXXX"));
    }

    boost::ptr_vector<rdb_protocol_t::store_t> underlying_stores;
    scoped_ptr_t<io_backender_t> io_backender;
    make_io_backender(aio_default, &io_backender);

    for (int i = 0; i < (int)shards.size(); i++) {
        underlying_stores.push_back(new rdb_protocol_t::store_t(io_backender.get(), temp_files[i].name(), true, &get_global_perfmon_collection()));
    }

    boost::ptr_vector<store_view_t<rdb_protocol_t> > stores;
    for (int i = 0; i < (int)shards.size(); i++) {
        stores.push_back(new store_subview_t<rdb_protocol_t>(&underlying_stores[i], shards[i]));
    }

    /* Set up namespace interface */
    dummy_namespace_interface_t<rdb_protocol_t> nsi(shards, stores.c_array(), &order_source);

    fun(&nsi, &order_source);
}

void run_in_thread_pool_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *, order_source_t*)> fun) {
    mock::run_in_thread_pool(boost::bind(&run_with_namespace_interface, fun));
}

}   /* anonymous namespace */

/* `SetupTeardown` makes sure that it can start and stop without anything going
horribly wrong */
void run_setup_teardown_test(UNUSED namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *) {
    /* Do nothing */
}
TEST(RDBProtocol, SetupTeardown) {
    run_in_thread_pool_with_namespace_interface(&run_setup_teardown_test);
}

/* `GetSet` tests basic get and set operations */
void run_get_set_test(namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *osource) {
    boost::shared_ptr<scoped_cJSON_t> data(new scoped_cJSON_t(cJSON_CreateNull()));
    {
        rdb_protocol_t::write_t write(rdb_protocol_t::point_write_t(store_key_t("a"), data));

        cond_t interruptor;
        rdb_protocol_t::write_response_t response = nsi->write(write, osource->check_in("unittest::run_get_set_test(rdb_protocol.cc-A)"), &interruptor);

        if (rdb_protocol_t::point_write_response_t *maybe_point_write_response_t = boost::get<rdb_protocol_t::point_write_response_t>(&response.response)) {
            EXPECT_EQ(maybe_point_write_response_t->result, STORED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        rdb_protocol_t::read_t read(rdb_protocol_t::point_read_t(store_key_t("a")));

        cond_t interruptor;
        rdb_protocol_t::read_response_t response = nsi->read(read, osource->check_in("unittest::run_get_set_test(rdb_protocol.cc-B)"), &interruptor);

        if (rdb_protocol_t::point_read_response_t *maybe_point_read_response = boost::get<rdb_protocol_t::point_read_response_t>(&response.response)) {
            EXPECT_TRUE(maybe_point_read_response->data->get() != NULL);
            EXPECT_TRUE(cJSON_Equal(data->get(), maybe_point_read_response->data->get()));
        } else {
            ADD_FAILURE() << "got wrong result back";
        }
    }
}

TEST(RDBProtocol, GetSet) {
    run_in_thread_pool_with_namespace_interface(&run_get_set_test);
}

}   /* namespace unittest */

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: accessibleselectionhelper.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: hr $ $Date: 2003-03-19 15:58:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_ACCESSIBLE_SELECTION_HELPER_HXX
#include <comphelper/accessibleselectionhelper.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::lang;
    using namespace ::drafts::com::sun::star::accessibility;

    //=====================================================================
    //= OCommonAccessibleSelection
    //=====================================================================
    //---------------------------------------------------------------------
    OCommonAccessibleSelection::OCommonAccessibleSelection( )
    {
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        implSelect( nChildIndex, sal_True );
    }

    //--------------------------------------------------------------------
    sal_Bool SAL_CALL OCommonAccessibleSelection::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        return( implIsSelected( nChildIndex ) );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::clearAccessibleSelection(  ) throw (RuntimeException)
    {
        implSelect( ACCESSIBLE_SELECTION_CHILD_ALL, sal_False );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::selectAllAccessible(  ) throw (RuntimeException)
    {
        implSelect( ACCESSIBLE_SELECTION_CHILD_ALL, sal_True );
    }

    //--------------------------------------------------------------------
    sal_Int32 SAL_CALL OCommonAccessibleSelection::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
    {
        sal_Int32                       nRet = 0;
        Reference< XAccessibleContext > xParentContext( implGetAccessibleContext() );

        OSL_ENSURE( xParentContext.is(), "OCommonAccessibleSelection::getSelectedAccessibleChildCount: no parent context!" );

        if( xParentContext.is() )
        {
            for( sal_Int32 i = 0, nChildCount = xParentContext->getAccessibleChildCount(); i < nChildCount; i++ )
                if( implIsSelected( i ) )
                    ++nRet;
        }

        return( nRet );
    }

    //--------------------------------------------------------------------
    Reference< XAccessible > SAL_CALL OCommonAccessibleSelection::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        Reference< XAccessible >        xRet;
        Reference< XAccessibleContext > xParentContext( implGetAccessibleContext() );

        OSL_ENSURE( xParentContext.is(), "OCommonAccessibleSelection::getSelectedAccessibleChildCount: no parent context!" );

        if( xParentContext.is() )
        {
            for( sal_Int32 i = 0, nChildCount = xParentContext->getAccessibleChildCount(), nPos = 0; ( i < nChildCount ) && !xRet.is(); i++ )
                if( implIsSelected( i ) && ( nPos++ == nSelectedChildIndex ) )
                    xRet = xParentContext->getAccessibleChild( i );
        }

        return( xRet );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::deselectSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        implSelect( nSelectedChildIndex, sal_False );
    }

    //=====================================================================
    //= OAccessibleSelectionHelper
    //=====================================================================
    //---------------------------------------------------------------------
    OAccessibleSelectionHelper::OAccessibleSelectionHelper( )
    {
    }

    //--------------------------------------------------------------------
    OAccessibleSelectionHelper::OAccessibleSelectionHelper( IMutex* _pExternalLock ) : OAccessibleComponentHelper(_pExternalLock)
    {
    }

    //--------------------------------------------------------------------
    IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleSelectionHelper, OAccessibleComponentHelper, OAccessibleSelectionHelper_Base )
    IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleSelectionHelper, OAccessibleComponentHelper, OAccessibleSelectionHelper_Base )
    // (order matters: the first is the class name, the second is the class doing the ref counting)

    //--------------------------------------------------------------------
    Reference< XAccessibleContext > OAccessibleSelectionHelper::implGetAccessibleContext() throw ( RuntimeException )
    {
        return( this );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::selectAccessibleChild( nChildIndex );
    }

    //--------------------------------------------------------------------
    sal_Bool SAL_CALL OAccessibleSelectionHelper::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        return( OCommonAccessibleSelection::isAccessibleChildSelected( nChildIndex ) );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::clearAccessibleSelection(  ) throw (RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::clearAccessibleSelection();
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::selectAllAccessible(  ) throw (RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::selectAllAccessible();
    }

    //--------------------------------------------------------------------
    sal_Int32 SAL_CALL OAccessibleSelectionHelper::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        return( OCommonAccessibleSelection::getSelectedAccessibleChildCount() );
    }

    //--------------------------------------------------------------------
    Reference< XAccessible > SAL_CALL OAccessibleSelectionHelper::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        return( OCommonAccessibleSelection::getSelectedAccessibleChild( nSelectedChildIndex ) );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::deselectSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::deselectSelectedAccessibleChild( nSelectedChildIndex );
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

<commit_msg>INTEGRATION: CWS uaa02 (1.3.8); FILE MERGED 2003/04/11 15:39:16 mt 1.3.8.2: #108656# Moved accessibility from drafts to final 2003/04/10 11:59:41 mt 1.3.8.1: #108656# Moved Accessibility module from drafts to final<commit_after>/*************************************************************************
 *
 *  $RCSfile: accessibleselectionhelper.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: vg $ $Date: 2003-04-24 17:27:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_ACCESSIBLE_SELECTION_HELPER_HXX
#include <comphelper/accessibleselectionhelper.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::awt;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::accessibility;

    //=====================================================================
    //= OCommonAccessibleSelection
    //=====================================================================
    //---------------------------------------------------------------------
    OCommonAccessibleSelection::OCommonAccessibleSelection( )
    {
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        implSelect( nChildIndex, sal_True );
    }

    //--------------------------------------------------------------------
    sal_Bool SAL_CALL OCommonAccessibleSelection::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        return( implIsSelected( nChildIndex ) );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::clearAccessibleSelection(  ) throw (RuntimeException)
    {
        implSelect( ACCESSIBLE_SELECTION_CHILD_ALL, sal_False );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::selectAllAccessible(  ) throw (RuntimeException)
    {
        implSelect( ACCESSIBLE_SELECTION_CHILD_ALL, sal_True );
    }

    //--------------------------------------------------------------------
    sal_Int32 SAL_CALL OCommonAccessibleSelection::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
    {
        sal_Int32                       nRet = 0;
        Reference< XAccessibleContext > xParentContext( implGetAccessibleContext() );

        OSL_ENSURE( xParentContext.is(), "OCommonAccessibleSelection::getSelectedAccessibleChildCount: no parent context!" );

        if( xParentContext.is() )
        {
            for( sal_Int32 i = 0, nChildCount = xParentContext->getAccessibleChildCount(); i < nChildCount; i++ )
                if( implIsSelected( i ) )
                    ++nRet;
        }

        return( nRet );
    }

    //--------------------------------------------------------------------
    Reference< XAccessible > SAL_CALL OCommonAccessibleSelection::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        Reference< XAccessible >        xRet;
        Reference< XAccessibleContext > xParentContext( implGetAccessibleContext() );

        OSL_ENSURE( xParentContext.is(), "OCommonAccessibleSelection::getSelectedAccessibleChildCount: no parent context!" );

        if( xParentContext.is() )
        {
            for( sal_Int32 i = 0, nChildCount = xParentContext->getAccessibleChildCount(), nPos = 0; ( i < nChildCount ) && !xRet.is(); i++ )
                if( implIsSelected( i ) && ( nPos++ == nSelectedChildIndex ) )
                    xRet = xParentContext->getAccessibleChild( i );
        }

        return( xRet );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OCommonAccessibleSelection::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        implSelect( nSelectedChildIndex, sal_False );
    }

    //=====================================================================
    //= OAccessibleSelectionHelper
    //=====================================================================
    //---------------------------------------------------------------------
    OAccessibleSelectionHelper::OAccessibleSelectionHelper( )
    {
    }

    //--------------------------------------------------------------------
    OAccessibleSelectionHelper::OAccessibleSelectionHelper( IMutex* _pExternalLock ) : OAccessibleComponentHelper(_pExternalLock)
    {
    }

    //--------------------------------------------------------------------
    IMPLEMENT_FORWARD_XINTERFACE2( OAccessibleSelectionHelper, OAccessibleComponentHelper, OAccessibleSelectionHelper_Base )
    IMPLEMENT_FORWARD_XTYPEPROVIDER2( OAccessibleSelectionHelper, OAccessibleComponentHelper, OAccessibleSelectionHelper_Base )
    // (order matters: the first is the class name, the second is the class doing the ref counting)

    //--------------------------------------------------------------------
    Reference< XAccessibleContext > OAccessibleSelectionHelper::implGetAccessibleContext() throw ( RuntimeException )
    {
        return( this );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::selectAccessibleChild( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::selectAccessibleChild( nChildIndex );
    }

    //--------------------------------------------------------------------
    sal_Bool SAL_CALL OAccessibleSelectionHelper::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        return( OCommonAccessibleSelection::isAccessibleChildSelected( nChildIndex ) );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::clearAccessibleSelection(  ) throw (RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::clearAccessibleSelection();
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::selectAllAccessible(  ) throw (RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::selectAllAccessible();
    }

    //--------------------------------------------------------------------
    sal_Int32 SAL_CALL OAccessibleSelectionHelper::getSelectedAccessibleChildCount(  ) throw (RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        return( OCommonAccessibleSelection::getSelectedAccessibleChildCount() );
    }

    //--------------------------------------------------------------------
    Reference< XAccessible > SAL_CALL OAccessibleSelectionHelper::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        return( OCommonAccessibleSelection::getSelectedAccessibleChild( nSelectedChildIndex ) );
    }

    //--------------------------------------------------------------------
    void SAL_CALL OAccessibleSelectionHelper::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (IndexOutOfBoundsException, RuntimeException)
    {
        OExternalLockGuard aGuard( this );
        OCommonAccessibleSelection::deselectAccessibleChild( nSelectedChildIndex );
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <tntdb/librarymanager.h>
#include <cxxtools/log.h>
#include <cxxtools/systemerror.h>
#include <cxxtools/directory.h>

#ifndef DRIVERDIR
#define DRIVERDIR "tntdb"
#endif

#define TNTDB_STRINGIFY(x) #x
#define TNTDB_TOSTRING(x) TNTDB_STRINGIFY(x)

log_define("tntdb.librarymanager")

namespace tntdb
{
  static const std::string libraryPrefix = "tntdb" ABI_CURRENT "-";

  LibraryManager::LibraryManager(const std::string& driverName)
  {
    try
    {
      log_debug("loading library \"" << libraryPrefix << driverName << '"');
      lib = cxxtools::Library(libraryPrefix + driverName);
    }
    catch (const cxxtools::FileNotFound& e)
    {
      log_debug("library \"" << libraryPrefix << driverName << "\" not found: " << e.what());
    }
    catch (const cxxtools::OpenLibraryFailed& e)
    {
      log_debug("opening library \"" << libraryPrefix << driverName << "\" failed: " << e.what());
    }

    if (!lib)
    {
      std::string d = DRIVERDIR + cxxtools::Directory::sep() + libraryPrefix + driverName;
      log_debug("loading library \"" << d << '"');
      lib = cxxtools::Library(d);
    }

    std::string symbolName = TNTDB_TOSTRING(TNTDB_DRIVER_PRAEFIX) + driverName;
    void* sym = lib.getSymbol(symbolName.c_str());
    connectionManager = static_cast<IConnectionManager*>(sym);

    log_debug("driver " << driverName << " successfully loaded");
  }

}
<commit_msg>better error message when loading driver library fails<commit_after>/*
 * Copyright (C) 2006 Tommi Maekitalo
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <tntdb/librarymanager.h>
#include <tntdb/error.h>
#include <cxxtools/log.h>
#include <cxxtools/systemerror.h>
#include <cxxtools/directory.h>

#ifndef DRIVERDIR
#define DRIVERDIR "tntdb"
#endif

#define TNTDB_STRINGIFY(x) #x
#define TNTDB_TOSTRING(x) TNTDB_STRINGIFY(x)

log_define("tntdb.librarymanager")

namespace tntdb
{
  static const std::string libraryPrefix = "tntdb" ABI_CURRENT "-";

  LibraryManager::LibraryManager(const std::string& driverName)
  {
    try
    {
      log_debug("loading library \"" << libraryPrefix << driverName << '"');
      lib = cxxtools::Library(libraryPrefix + driverName);
    }
    catch (const cxxtools::FileNotFound& e)
    {
      log_debug("library \"" << libraryPrefix << driverName << "\" not found: " << e.what());
    }
    catch (const cxxtools::OpenLibraryFailed& e)
    {
      log_debug("opening library \"" << libraryPrefix << driverName << "\" failed: " << e.what());
    }

    try
    {
      if (!lib)
      {
        std::string d = DRIVERDIR + cxxtools::Directory::sep() + libraryPrefix + driverName;
        log_debug("loading library \"" << d << '"');
        lib = cxxtools::Library(d);
      }
    }
    catch (const std::exception& e)
    {
      std::ostringstream msg;
      msg << "failed to load driver \"" << libraryPrefix << driverName << '"';
      log_warn(msg.str() << ": " << e.what());
      throw Error(msg.str());
    }

    std::string symbolName = TNTDB_TOSTRING(TNTDB_DRIVER_PRAEFIX) + driverName;
    void* sym = lib.getSymbol(symbolName.c_str());
    connectionManager = static_cast<IConnectionManager*>(sym);

    log_debug("driver " << driverName << " successfully loaded");
  }

}
<|endoftext|>


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

//#define LOGLEVEL VERBOSE

#include "utils/GridConnectHub.hxx"

#include "executor/StateFlow.hxx"
#include "can_frame.h"
#include "utils/Buffer.hxx"
#include "utils/HubDevice.hxx"
#include "utils/Hub.hxx"
#include "utils/gc_format.h"

/// Actual implementation for the gridconnect bridge between a string-typed Hub
/// and a CAN-frame-typed Hub.
class GCAdapter : public GCAdapterBase
{
public:
    GCAdapter(HubFlow *gc_side, CanHubFlow *can_side, bool double_bytes)
        : parser_(can_side->service(), can_side, &formatter_)
        , formatter_(can_side->service(), gc_side, &parser_, double_bytes)
    {
        gc_side->register_port(&parser_);
        can_side->register_port(&formatter_);
        isRegistered_ = 1;
    }

    GCAdapter(HubFlow *gc_side_read, HubFlow *gc_side_write,
              CanHubFlow *can_side, bool double_bytes)
        : parser_(can_side->service(), can_side, &formatter_)
        , formatter_(can_side->service(), gc_side_write, &parser_, double_bytes)
    {
        gc_side_read->register_port(&parser_);
        can_side->register_port(&formatter_);
        isRegistered_ = 1;
    }

    virtual ~GCAdapter()
    {
        unregister();
    }

    void unregister()
    {
        if (isRegistered_)
        {
            parser_.destination()->unregister_port(&formatter_);
            /// @TODO(balazs.racz) This is incorrect if the 3-pipe constructor
            /// is
            /// used.
            formatter_.destination()->unregister_port(&parser_);
            isRegistered_ = 0;
        }
    }

    bool shutdown() OVERRIDE
    {
        unregister();
        return parser_.is_waiting() && formatter_.is_waiting();
    }

    /// HubPort (on a CAN-typed hub) that turns a binary CAN packet into a
    /// string-formatted CAN packet, and sends it off to the HubFlow (of type
    /// string).
    class BinaryToGCMember : public CanHubPort
    {
    public:
        BinaryToGCMember(Service *service, HubFlow *destination,
                         HubPort *skip_member, int double_bytes)
            : CanHubPort(service)
            , destination_(destination)
            , skipMember_(skip_member)
            , double_bytes_(double_bytes)
        {
        }

        HubFlow *destination()
        {
            return destination_;
        }

        Action entry()
        {
            LOG(VERBOSE, "can packet arrived: %" PRIx32,
                GET_CAN_FRAME_ID_EFF(*message()->data()));
            char *end =
                gc_format_generate(message()->data(), dbuf_, double_bytes_);
            size_t size = (end - dbuf_);
            if (size)
            {
                Buffer<HubData> *target_buffer;
                /// @todo(balazs.racz) switch to asynchronous allocation here.
                mainBufferPool->alloc(&target_buffer);
                target_buffer->data()->skipMember_ = skipMember_;
                /// @todo(balazs.racz) try to use an assign function for better
                /// performance.
                target_buffer->data()->resize(size);
                memcpy((char *)target_buffer->data()->data(), dbuf_, size);
                destination_->send(target_buffer, 0);
            }
            else
            {
                LOG(INFO, "gc generate failed.");
            }
            return release_and_exit();
        }

    private:
        /// Destination buffer (characters).
        char dbuf_[56];
        /// Pipe to send data to.
        HubFlow *destination_;
        /// The pipe member that should be sent as "source".
        HubPort *skipMember_;
        /// Non-zero if doubling was requested.
        int double_bytes_;
    };

    /// HubPort (on a string hub) that turns a gridconnect-formatted CAN packet
    /// into a binary CAN packet, and sends them off to the HubFlow (of CAN
    /// frame).
    class GCToBinaryMember : public HubPort
    {
    public:
        GCToBinaryMember(Service *service, CanHubFlow *destination,
                         CanHubPort *skip_member)
            : HubPort(service)
            , offset_(-1)
            , destination_(destination)
            , skipMember_(skip_member)
        {
        }

        CanHubFlow *destination()
        {
            return destination_;
        }

        /** Takes more characters from the pending incoming buffer. */
        Action entry()
        {
            inBuf_ = message()->data()->data();
            inBufSize_ = message()->data()->size();
            return call_immediately(STATE(parse_more_data));
        }

        Action parse_more_data()
        {
            while (inBufSize_--)
            {
                char c = *inBuf_++;
                if (consume_byte(c))
                {
                    // End of frame. Allocate an output buffer and parse the
                    // frame.
                    /// @todo(balazs.racz) use a configurable buffer pool
                    mainBufferPool->alloc(&outBuf_);
                    return call_immediately(STATE(parse_to_output_frame));
                }
            }
            // Will notify the caller.
            return release_and_exit();
        }

        /** Takes the completed frame in cbuf_, parses it into the allocation
         * result (a can pipe buffer) and sends off frame. Then comes back to
         * process buffer. */
        Action parse_to_output_frame()
        {
            // CanPipeBuffer *pbuf = GetTypedAllocationResult(&g_can_alloc);
            // pbuf->Reset();
            LOG(VERBOSE, "gc packet arrived: %s", cbuf_);
            int ret = gc_format_parse(cbuf_, outBuf_->data());
            if (!ret)
            {
                outBuf_->data()->skipMember_ = skipMember_;
                destination_->send(outBuf_);
            }
            else
            {
                // Releases the buffer.
                outBuf_->unref();
            }
            return call_immediately(STATE(parse_more_data));
        }

        /** Adds the next character from the source stream. Returns true if
         * cbuf_ contains a complete frame. */
        bool consume_byte(char c)
        {
            if (c == ':')
            {
                // Frame is starting here.
                offset_ = 0;
                return false;
            }
            if (c == ';')
            {
                if (offset_ < 0)
                {
                    return false;
                }
                // Frame ends here.
                cbuf_[offset_] = 0;
                offset_ = -1;
                return true;
            }
            if (offset_ >= static_cast<int>(sizeof(cbuf_) - 1))
            {
                // We overran the buffer, so this can't be a valid frame.
                // Reset and look for sync byte again.
                offset_ = -1;
                return false;
            }
            if (offset_ >= 0)
            {
                cbuf_[offset_++] = c;
            }
            else
            {
                // Drop byte to the floor -- we're not in the middle of a
                // packet.
            }
            return false;
        }

    private:
        /// Collects data from a partial GC packet.
        char cbuf_[32];
        /// offset of next byte in cbuf to write.
        int offset_;

        /// The incoming characters.
        const char *inBuf_;
        /// The remaining number of characters in inBuf_.
        size_t inBufSize_;

        /// The buffer to send to the destination hub.
        Buffer<CanHubData> *outBuf_;

        // ==== static data ====

        /// Pipe to send data to.
        CanHubFlow *destination_;
        /// The pipe member that should be sent as "source".
        CanHubPortInterface *skipMember_;
    };

private:
    /// PipeMember doing the parsing.
    GCToBinaryMember parser_;
    /// PipeMember doing the formatting.
    BinaryToGCMember formatter_;
    unsigned isRegistered_ : 1; //< 1 if the flows are registered.
};

GCAdapterBase *GCAdapterBase::CreateGridConnectAdapter(HubFlow *gc_side,
                                                       CanHubFlow *can_side,
                                                       bool double_bytes)
{
    return new GCAdapter(gc_side, can_side, double_bytes);
}

GCAdapterBase *GCAdapterBase::CreateGridConnectAdapter(HubFlow *gc_side_read,
                                                       HubFlow *gc_side_write,
                                                       CanHubFlow *can_side,
                                                       bool double_bytes)
{
    return new GCAdapter(gc_side_read, gc_side_write, can_side, double_bytes);
}

/// Implementation for the gridconnect bridge. Owns all necessary structures,
/// and is responsible for the initialization, registering, unregistering and
/// destruction of these structures.
struct GcPacketPrinter::Impl
{
    Impl(CanHubFlow *can_hub, bool timestamped)
        : canHub_(can_hub)
        , gcHub_(canHub_->service())
        , displayPort_(canHub_->service(), timestamped)
        , formatter_(canHub_->service(), &gcHub_, nullptr, false)
    {
        gcHub_.register_port(&displayPort_);
        canHub_->register_port(&formatter_);
    }

    ~Impl()
    {
        canHub_->unregister_port(&formatter_);
        gcHub_.unregister_port(&displayPort_);
    }

    CanHubFlow *canHub_;
    HubFlow gcHub_;
    DisplayPort displayPort_;
    GCAdapter::BinaryToGCMember formatter_;
};

GcPacketPrinter::GcPacketPrinter(CanHubFlow *can_hub, bool timestamped) : impl_(new Impl(can_hub, timestamped))
{
}

GcPacketPrinter::~GcPacketPrinter()
{
}

/// Implementation class that adds a device to a CAN hub with dynamic
/// translation of the packets to/from GridConnect format.
///
/// Sends a notification to the application level when there is an error on the
/// device and the connection is closed.
struct GcHubPort : public Executable
{
    GcHubPort(CanHubFlow *can_hub, int fd, Notifiable *on_exit)
        : gcHub_(can_hub->service())
        , bridge_(
              GCAdapterBase::CreateGridConnectAdapter(&gcHub_, can_hub, false))
        , gcWrite_(&gcHub_, fd, this)
        , onExit_(on_exit)
    {
        LOG(VERBOSE, "gchub port %p", (Executable *)this);
    }
    virtual ~GcHubPort()
    {
    }

    /** This hub sees the character-based representation of the packets. The
     * members of it are: the bridge and the physical device (fd).
     *
     * Destruction requirement: HubFlow should be empty. This means after the
     * disconnection of the bridge (write side) and the FdHubport (read side)
     * we need to wait for the executor until this flow drains. */
    HubFlow gcHub_;
    /** Translates packets between the can-hub of the device and the char-hub
     * of this port.
     *
     * Destruction requirement: Call shutdown() on the can-side executor (and
     * yield) until it returns true. */
    std::unique_ptr<GCAdapterBase> bridge_;
    /** Reads the characters from the char-hub and sends them to the
     * fd. Similarly, listens to the fd and sends the read charcters to the
     * char-hub. */
    FdHubPort<HubFlow> gcWrite_;
    /** If not null, this notifiable will be called when the device is
     * closed. */
    Notifiable* onExit_;

    /** Callback in case the connection is closed due to error. */
    void notify() OVERRIDE
    {
        /* We would like to delete *this but we cannot do that in this
         * callback, because we don't know what executor we are running
         * on. Deleting on the write executor would cause a deadlock for
         * example. */
        gcHub_.service()->executor()->add(this);
    }

    void run() OVERRIDE
    {
        if (!bridge_->shutdown() || !gcHub_.is_waiting())
        {
            // Yield.
            gcHub_.service()->executor()->add(this);
            return;
        }
        LOG(INFO, "GCHubPort: Shutting down gridconnect port %d. (%p)",
            gcWrite_.fd(), bridge_.get());
        if (onExit_) {
            onExit_->notify();
            onExit_ = nullptr;
        }
        /* We get this call when something is wrong with the FDs and we need to
         * close the connection. It is guaranteed that by the time we got this
         * call the device is unregistered from the char bridge, and the
         * service thread is ready to be stopped. */
        delete this;
    }
};

void create_gc_port_for_can_hub(CanHubFlow *can_hub, int fd, Notifiable* on_exit)
{
    new GcHubPort(can_hub, fd, on_exit);
}
<commit_msg>Makes timestamped printing of HUB traffic be more user-friendly: - timestamps are printed in human readable form - also prints the skipMember_ field which allows determining where the packet came from.<commit_after>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file GridConnectHub.cxx
 * Gridconnect parser/renderer pipe components.
 *
 * @author Balazs Racz
 * @date 20 May 2013
 */

//#define LOGLEVEL VERBOSE

#include "utils/GridConnectHub.hxx"

#include "executor/StateFlow.hxx"
#include "can_frame.h"
#include "utils/Buffer.hxx"
#include "utils/HubDevice.hxx"
#include "utils/Hub.hxx"
#include "utils/gc_format.h"

/// Actual implementation for the gridconnect bridge between a string-typed Hub
/// and a CAN-frame-typed Hub.
class GCAdapter : public GCAdapterBase
{
public:
    GCAdapter(HubFlow *gc_side, CanHubFlow *can_side, bool double_bytes)
        : parser_(can_side->service(), can_side, &formatter_)
        , formatter_(can_side->service(), gc_side, &parser_, double_bytes)
    {
        gc_side->register_port(&parser_);
        can_side->register_port(&formatter_);
        isRegistered_ = 1;
    }

    GCAdapter(HubFlow *gc_side_read, HubFlow *gc_side_write,
              CanHubFlow *can_side, bool double_bytes)
        : parser_(can_side->service(), can_side, &formatter_)
        , formatter_(can_side->service(), gc_side_write, &parser_, double_bytes)
    {
        gc_side_read->register_port(&parser_);
        can_side->register_port(&formatter_);
        isRegistered_ = 1;
    }

    virtual ~GCAdapter()
    {
        unregister();
    }

    void unregister()
    {
        if (isRegistered_)
        {
            parser_.destination()->unregister_port(&formatter_);
            /// @TODO(balazs.racz) This is incorrect if the 3-pipe constructor
            /// is
            /// used.
            formatter_.destination()->unregister_port(&parser_);
            isRegistered_ = 0;
        }
    }

    bool shutdown() OVERRIDE
    {
        unregister();
        return parser_.is_waiting() && formatter_.is_waiting();
    }

    /// HubPort (on a CAN-typed hub) that turns a binary CAN packet into a
    /// string-formatted CAN packet, and sends it off to the HubFlow (of type
    /// string).
    class BinaryToGCMember : public CanHubPort
    {
    public:
        BinaryToGCMember(Service *service, HubFlow *destination,
                         HubPort *skip_member, int double_bytes)
            : CanHubPort(service)
            , destination_(destination)
            , skipMember_(skip_member)
            , double_bytes_(double_bytes)
        {
        }

        HubFlow *destination()
        {
            return destination_;
        }

        Action entry()
        {
            LOG(VERBOSE, "can packet arrived: %" PRIx32,
                GET_CAN_FRAME_ID_EFF(*message()->data()));
            char *end =
                gc_format_generate(message()->data(), dbuf_, double_bytes_);
            size_t size = (end - dbuf_);
            if (size)
            {
                Buffer<HubData> *target_buffer;
                /// @todo(balazs.racz) switch to asynchronous allocation here.
                mainBufferPool->alloc(&target_buffer);
                target_buffer->data()->skipMember_ = skipMember_;
                /// @todo(balazs.racz) try to use an assign function for better
                /// performance.
                target_buffer->data()->resize(size);
                memcpy((char *)target_buffer->data()->data(), dbuf_, size);
                destination_->send(target_buffer, 0);
            }
            else
            {
                LOG(INFO, "gc generate failed.");
            }
            return release_and_exit();
        }

    private:
        /// Destination buffer (characters).
        char dbuf_[56];
        /// Pipe to send data to.
        HubFlow *destination_;
        /// The pipe member that should be sent as "source".
        HubPort *skipMember_;
        /// Non-zero if doubling was requested.
        int double_bytes_;
    };

    /// HubPort (on a string hub) that turns a gridconnect-formatted CAN packet
    /// into a binary CAN packet, and sends them off to the HubFlow (of CAN
    /// frame).
    class GCToBinaryMember : public HubPort
    {
    public:
        GCToBinaryMember(Service *service, CanHubFlow *destination,
                         CanHubPort *skip_member)
            : HubPort(service)
            , offset_(-1)
            , destination_(destination)
            , skipMember_(skip_member)
        {
        }

        CanHubFlow *destination()
        {
            return destination_;
        }

        /** Takes more characters from the pending incoming buffer. */
        Action entry()
        {
            inBuf_ = message()->data()->data();
            inBufSize_ = message()->data()->size();
            return call_immediately(STATE(parse_more_data));
        }

        Action parse_more_data()
        {
            while (inBufSize_--)
            {
                char c = *inBuf_++;
                if (consume_byte(c))
                {
                    // End of frame. Allocate an output buffer and parse the
                    // frame.
                    /// @todo(balazs.racz) use a configurable buffer pool
                    mainBufferPool->alloc(&outBuf_);
                    return call_immediately(STATE(parse_to_output_frame));
                }
            }
            // Will notify the caller.
            return release_and_exit();
        }

        /** Takes the completed frame in cbuf_, parses it into the allocation
         * result (a can pipe buffer) and sends off frame. Then comes back to
         * process buffer. */
        Action parse_to_output_frame()
        {
            // CanPipeBuffer *pbuf = GetTypedAllocationResult(&g_can_alloc);
            // pbuf->Reset();
            LOG(VERBOSE, "gc packet arrived: %s", cbuf_);
            int ret = gc_format_parse(cbuf_, outBuf_->data());
            if (!ret)
            {
                outBuf_->data()->skipMember_ = skipMember_;
                destination_->send(outBuf_);
            }
            else
            {
                // Releases the buffer.
                outBuf_->unref();
            }
            return call_immediately(STATE(parse_more_data));
        }

        /** Adds the next character from the source stream. Returns true if
         * cbuf_ contains a complete frame. */
        bool consume_byte(char c)
        {
            if (c == ':')
            {
                // Frame is starting here.
                offset_ = 0;
                return false;
            }
            if (c == ';')
            {
                if (offset_ < 0)
                {
                    return false;
                }
                // Frame ends here.
                cbuf_[offset_] = 0;
                offset_ = -1;
                return true;
            }
            if (offset_ >= static_cast<int>(sizeof(cbuf_) - 1))
            {
                // We overran the buffer, so this can't be a valid frame.
                // Reset and look for sync byte again.
                offset_ = -1;
                return false;
            }
            if (offset_ >= 0)
            {
                cbuf_[offset_++] = c;
            }
            else
            {
                // Drop byte to the floor -- we're not in the middle of a
                // packet.
            }
            return false;
        }

    private:
        /// Collects data from a partial GC packet.
        char cbuf_[32];
        /// offset of next byte in cbuf to write.
        int offset_;

        /// The incoming characters.
        const char *inBuf_;
        /// The remaining number of characters in inBuf_.
        size_t inBufSize_;

        /// The buffer to send to the destination hub.
        Buffer<CanHubData> *outBuf_;

        // ==== static data ====

        /// Pipe to send data to.
        CanHubFlow *destination_;
        /// The pipe member that should be sent as "source".
        CanHubPortInterface *skipMember_;
    };

private:
    /// PipeMember doing the parsing.
    GCToBinaryMember parser_;
    /// PipeMember doing the formatting.
    BinaryToGCMember formatter_;
    unsigned isRegistered_ : 1; //< 1 if the flows are registered.
};

GCAdapterBase *GCAdapterBase::CreateGridConnectAdapter(HubFlow *gc_side,
                                                       CanHubFlow *can_side,
                                                       bool double_bytes)
{
    return new GCAdapter(gc_side, can_side, double_bytes);
}

GCAdapterBase *GCAdapterBase::CreateGridConnectAdapter(HubFlow *gc_side_read,
                                                       HubFlow *gc_side_write,
                                                       CanHubFlow *can_side,
                                                       bool double_bytes)
{
    return new GCAdapter(gc_side_read, gc_side_write, can_side, double_bytes);
}

/// Implementation for the gridconnect bridge. Owns all necessary structures,
/// and is responsible for the initialization, registering, unregistering and
/// destruction of these structures.
struct GcPacketPrinter::Impl : public CanHubPortInterface
{
    Impl(CanHubFlow *can_hub, bool timestamped)
        : canHub_(can_hub)
        , timestamped_(timestamped)
    {
        canHub_->register_port(this);
    }

    ~Impl()
    {
        canHub_->unregister_port(this);
    }

    void send(Buffer<CanHubData> *message, unsigned priority) OVERRIDE
    {
        AutoReleaseBuffer<CanHubData> b(message);
        char str[40];
        char* p = gc_format_generate(message->data(), str, false);
        *p = 0;
        if (timestamped_)
        {
#if defined(__linux__) || defined(__MACH__)
            struct timeval tv;
            gettimeofday(&tv, nullptr);
            struct tm t;
            localtime_r(&tv.tv_sec, &t);
            printf("%04d-%02d-%02d %02d:%02d:%02d:%06ld [%p] ",
                t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min,
                t.tm_sec, tv.tv_usec, message->data()->skipMember_);
#endif
        }
        printf("%s\n", str);
    }

    CanHubFlow* canHub_;
    bool timestamped_;
};

GcPacketPrinter::GcPacketPrinter(CanHubFlow *can_hub, bool timestamped) : impl_(new Impl(can_hub, timestamped))
{
}

GcPacketPrinter::~GcPacketPrinter()
{
}

/// Implementation class that adds a device to a CAN hub with dynamic
/// translation of the packets to/from GridConnect format.
///
/// Sends a notification to the application level when there is an error on the
/// device and the connection is closed.
struct GcHubPort : public Executable
{
    GcHubPort(CanHubFlow *can_hub, int fd, Notifiable *on_exit)
        : gcHub_(can_hub->service())
        , bridge_(
              GCAdapterBase::CreateGridConnectAdapter(&gcHub_, can_hub, false))
        , gcWrite_(&gcHub_, fd, this)
        , onExit_(on_exit)
    {
        LOG(VERBOSE, "gchub port %p", (Executable *)this);
    }
    virtual ~GcHubPort()
    {
    }

    /** This hub sees the character-based representation of the packets. The
     * members of it are: the bridge and the physical device (fd).
     *
     * Destruction requirement: HubFlow should be empty. This means after the
     * disconnection of the bridge (write side) and the FdHubport (read side)
     * we need to wait for the executor until this flow drains. */
    HubFlow gcHub_;
    /** Translates packets between the can-hub of the device and the char-hub
     * of this port.
     *
     * Destruction requirement: Call shutdown() on the can-side executor (and
     * yield) until it returns true. */
    std::unique_ptr<GCAdapterBase> bridge_;
    /** Reads the characters from the char-hub and sends them to the
     * fd. Similarly, listens to the fd and sends the read charcters to the
     * char-hub. */
    FdHubPort<HubFlow> gcWrite_;
    /** If not null, this notifiable will be called when the device is
     * closed. */
    Notifiable* onExit_;

    /** Callback in case the connection is closed due to error. */
    void notify() OVERRIDE
    {
        /* We would like to delete *this but we cannot do that in this
         * callback, because we don't know what executor we are running
         * on. Deleting on the write executor would cause a deadlock for
         * example. */
        gcHub_.service()->executor()->add(this);
    }

    void run() OVERRIDE
    {
        if (!bridge_->shutdown() || !gcHub_.is_waiting())
        {
            // Yield.
            gcHub_.service()->executor()->add(this);
            return;
        }
        LOG(INFO, "GCHubPort: Shutting down gridconnect port %d. (%p)",
            gcWrite_.fd(), bridge_.get());
        if (onExit_) {
            onExit_->notify();
            onExit_ = nullptr;
        }
        /* We get this call when something is wrong with the FDs and we need to
         * close the connection. It is guaranteed that by the time we got this
         * call the device is unregistered from the char bridge, and the
         * service thread is ready to be stopped. */
        delete this;
    }
};

void create_gc_port_for_can_hub(CanHubFlow *can_hub, int fd, Notifiable* on_exit)
{
    new GcHubPort(can_hub, fd, on_exit);
}
<|endoftext|>