<commit_before>// Copyright (c) 2013-2014 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED 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 fft3d_cpu.hpp
 *
 *  \brief Contains CPU specialization.
 */

/// CPU specialization of FFT3D class.
/** FFT convention:
 *  \f[
 *      f({\bf r}) = \sum_{{\bf G}} e^{i{\bf G}{\bf r}} f({\bf G})
 *  \f]
 *  is a \em backward transformation from a set of pw coefficients to a function.
 *
 *  \f[
 *      f({\bf G}) = \frac{1}{\Omega} \int e^{-i{\bf G}{\bf r}} f({\bf r}) d {\bf r} =
 *          \frac{1}{N} \sum_{{\bf r}_j} e^{-i{\bf G}{\bf r}_j} f({\bf r}_j)
 *  \f]
 *  is a \em forward transformation from a function to a set of coefficients.
*/
template<>
class FFT3D<CPU>
{
    private:

        /// Number of working threads inside each FFT.
        int num_fft_workers_;

        /// Number of threads doing individual FFTs.
        int num_fft_threads_;

        /// Size of each dimension.
        int grid_size_[3];

        /// reciprocal space range
        std::pair<int, int> grid_limits_[3];

        /// backward transformation plan for each thread
        std::vector<fftw_plan> plan_backward_;

        /// forward transformation plan for each thread
        std::vector<fftw_plan> plan_forward_;

        /// inout buffer for each thread
        mdarray<double_complex, 2> fftw_buffer_;

        int num_gvec_;

        mdarray<int, 2> gvec_;
        std::vector< vector3d<double> > gvec_cart_; // TODO: check if we really need to store it, or create "on the fly"

        mdarray<int, 3> gvec_index_;

        std::vector<int> index_map_;
        std::vector<int> gvec_shell_;
        std::vector<double> gvec_shell_len_;

        /// Execute backward transformation.
        inline void backward(int thread_id = 0)
        {
            fftw_execute(plan_backward_[thread_id]);
        }

        /// Execute forward transformation.
        inline void forward(int thread_id = 0)
        {
            fftw_execute(plan_forward_[thread_id]);
            double norm = 1.0 / size();
            for (int i = 0; i < size(); i++) fftw_buffer_(i, thread_id) *= norm;
        }

        /// Find smallest optimal grid size starting from n.
        int find_grid_size(int n)
        {
            while (true)
            {
                int m = n;
                for (int k = 2; k <= 5; k++)
                {
                    while (m % k == 0) m /= k;
                }
                if (m == 1)
                {
                    return n;
                }
                else
                {
                    n++;
                }
            }
        }

    public:

        FFT3D(vector3d<int> dims__,
              int num_fft_threads__,
              int num_fft_workers__)
            : num_fft_workers_(num_fft_workers__),
              num_fft_threads_(num_fft_threads__)
        {
            Timer t("sirius::FFT3D<CPU>::FFT3D");
            for (int i = 0; i < 3; i++)
            {
                grid_size_[i] = find_grid_size(dims__[i]);

                grid_limits_[i].second = grid_size_[i] / 2;
                grid_limits_[i].first = grid_limits_[i].second - grid_size_[i] + 1;
            }

            fftw_plan_with_nthreads(num_fft_workers_);

            fftw_buffer_ = mdarray<double_complex, 2>(size(), num_fft_threads_);

            plan_backward_.resize(num_fft_threads_);
            plan_forward_.resize(num_fft_threads_);

            for (int i = 0; i < num_fft_threads_; i++)
            {
                plan_backward_[i] = fftw_plan_dft_3d(size(2), size(1), size(0),
                                                     (fftw_complex*)&fftw_buffer_(0, i),
                                                     (fftw_complex*)&fftw_buffer_(0, i), 1, FFTW_MEASURE);
                plan_forward_[i] = fftw_plan_dft_3d(size(2), size(1), size(0),
                                                    (fftw_complex*)&fftw_buffer_(0, i),
                                                    (fftw_complex*)&fftw_buffer_(0, i), -1, FFTW_MEASURE);
            }
            fftw_plan_with_nthreads(1);
        }

        ~FFT3D()
        {
            for (int i = 0; i < num_fft_threads_; i++)
            {
                fftw_destroy_plan(plan_backward_[i]);
                fftw_destroy_plan(plan_forward_[i]);
            }
        }

        /// Zero the input buffer for a given thread.
        inline void zero(int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            memset(&fftw_buffer_(0, thread_id), 0, size() * sizeof(double_complex));
        }

        template<typename T>
        inline void input(int n, int* map, T* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            zero(thread_id);
            for (int i = 0; i < n; i++) fftw_buffer_(map[i], thread_id) = data[i];
        }

        inline void input(double* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < size(); i++) fftw_buffer_(i, thread_id) = data[i];
        }

        inline void input(double_complex* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            memcpy(&fftw_buffer_(0, thread_id), data, size() * sizeof(double_complex));
        }

        /// Execute the transformation for a given thread.
        inline void transform(int direction, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            switch(direction)
            {
                case 1:
                {
                    backward(thread_id);
                    break;
                }
                case -1:
                {
                    forward(thread_id);
                    break;
                }
                default:
                {
                    error_local(__FILE__, __LINE__, "wrong FFT direction");
                }
            }
        }

        inline void output(double* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < size(); i++) data[i] = real(fftw_buffer_(i, thread_id));
        }

        inline void output(double_complex* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            memcpy(data, &fftw_buffer_(0, thread_id), size() * sizeof(double_complex));
        }

        inline void output(int n, int* map, double_complex* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < n; i++) data[i] = fftw_buffer_(map[i], thread_id);
        }

        inline void output(int n, int* map, double_complex* data, int thread_id, double alpha)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < n; i++) data[i] += alpha * fftw_buffer_(map[i], thread_id);
        }

        inline const std::pair<int, int>& grid_limits(int idim)
        {
            return grid_limits_[idim];
        }

        /// Total size of the FFT grid.
        inline int size()
        {
            return grid_size_[0] * grid_size_[1] * grid_size_[2];
        }

        /// Size of a given dimension.
        inline int size(int d)
        {
            assert(d >= 0 && d < 3);
            return grid_size_[d];
        }

        /// Return linear index of a plane-wave harmonic with fractional coordinates (10, i1, i2) inside fft buffer.
        inline int index(int i0, int i1, int i2)
        {
            if (i0 < 0) i0 += grid_size_[0];
            if (i1 < 0) i1 += grid_size_[1];
            if (i2 < 0) i2 += grid_size_[2];

            return (i0 + i1 * grid_size_[0] + i2 * grid_size_[0] * grid_size_[1]);
        }

        /// Direct access to the fft buffer
        inline double_complex& buffer(int i, int thread_id = 0)
        {
            return fftw_buffer_(i, thread_id);
        }

        vector3d<int> grid_size()
        {
            return vector3d<int>(grid_size_);
        }

        void init_gvec(double Gmax__, matrix3d<double>& M__)
        {
            mdarray<int, 2> gvec_tmp(3, size());
            std::vector< std::pair<double, int> > gvec_tmp_length;

            for (int i0 = grid_limits(0).first; i0 <= grid_limits(0).second; i0++)
            {
                for (int i1 = grid_limits(1).first; i1 <= grid_limits(1).second; i1++)
                {
                    for (int i2 = grid_limits(2).first; i2 <= grid_limits(2).second; i2++)
                    {
                        int ig = (int)gvec_tmp_length.size();

                        gvec_tmp(0, ig) = i0;
                        gvec_tmp(1, ig) = i1;
                        gvec_tmp(2, ig) = i2;

                        auto vc = M__ * vector3d<double>(i0, i1, i2);

                        gvec_tmp_length.push_back(std::pair<double, int>(vc.length(), ig));
                    }
                }
            }

            /* sort G-vectors by length */
            std::sort(gvec_tmp_length.begin(), gvec_tmp_length.end());

            /* create sorted list of G-vectors */
            gvec_ = mdarray<int, 2>(3, size());
            gvec_cart_ = std::vector< vector3d<double> >(size());

            /* find number of G-vectors within the cutoff */
            num_gvec_ = 0;
            for (int i = 0; i < size(); i++)
            {
                for (int x = 0; x < 3; x++) gvec_(x, i) = gvec_tmp(x, gvec_tmp_length[i].second);

                gvec_cart_[i] = M__ * vector3d<double>(gvec_(0, i), gvec_(1, i), gvec_(2, i));

                if (gvec_tmp_length[i].first <= Gmax__) num_gvec_++;
            }

            gvec_index_ = mdarray<int, 3>(mdarray_index_descriptor(grid_limits(0).first, grid_limits(0).second),
                                          mdarray_index_descriptor(grid_limits(1).first, grid_limits(1).second),
                                          mdarray_index_descriptor(grid_limits(2).first, grid_limits(2).second));
            index_map_.resize(size());

            gvec_shell_.resize(size());
            gvec_shell_len_.clear();

            for (int ig = 0; ig < size(); ig++)
            {
                int i0 = gvec_(0, ig);
                int i1 = gvec_(1, ig);
                int i2 = gvec_(2, ig);

                /* mapping from G-vector to it's index */
                gvec_index_(i0, i1, i2) = ig;

                /* mapping of FFT buffer linear index */
                index_map_[ig] = index(i0, i1, i2);

                /* find G-shells */
                double t = gvec_tmp_length[ig].first;
                if (gvec_shell_len_.empty() || fabs(t - gvec_shell_len_.back()) > 1e-10) gvec_shell_len_.push_back(t);
                gvec_shell_[ig] = (int)gvec_shell_len_.size() - 1;
            }
        }

        /// Return number of G-vectors within the cutoff.
        inline int num_gvec()
        {
            return num_gvec_;
        }

        /// Return G-vector in fractional coordinates (this are the three Miller indices).
        inline vector3d<int> gvec(int ig__)
        {
            return vector3d<int>(gvec_(0, ig__), gvec_(1, ig__), gvec_(2, ig__));
        }

        /// Return G-vector in Cartesian coordinates.
        inline vector3d<double>gvec_cart(int ig__)
        {
            assert(ig__ >= 0 && ig__ < (int)gvec_cart_.size());
            return gvec_cart_[ig__];
        }

        /// Return length of a G-vector.
        inline double gvec_len(int ig__)
        {
            return gvec_shell_len(gvec_shell(ig__));
        }

        /// Return number of G-vector shells within the cutoff.
        /** G-vectors with the same length belong to the same shell. */
        inline int num_gvec_shells_inner()
        {
            return gvec_shell(num_gvec_);
        }

        /// Return total number of G-vector shells, including incomplete shells.
        /** Incomplete G-shells are formed by G-vectors outisde the cutoff radius (for example,
         *  by G-vectors at corners of FFT grid).
         */
        inline int num_gvec_shells_total()
        {
            return (int)gvec_shell_len_.size();
        }

        /// Return index of a G-vector shell for a given G-vector.
        inline int gvec_shell(int ig__)
        {
            assert(ig__ >= 0 && ig__ < (int)gvec_shell_.size());
            return gvec_shell_[ig__];
        }

        /// Return length of a G-vector shell.
        inline double gvec_shell_len(int igsh__)
        {
            assert(igsh__ >= 0 && igsh__ < (int)gvec_shell_len_.size());
            return gvec_shell_len_[igsh__];
        }

        inline int* index_map()
        {
            return &index_map_[0];
        }

        inline int index_map(int ig__)
        {
            assert(ig__ >= 0 && ig__ < (int)index_map_.size());
            return index_map_[ig__];
        }

        inline int num_fft_threads()
        {
            return num_fft_threads_;
        }

        inline int gvec_index(vector3d<int> gvec__)
        {
            return gvec_index_(gvec__[0], gvec__[1], gvec__[2]);
        }
};

<commit_msg>FFTW_MEASURE is not reproducible; changed to FFTW_ESTIMATE<commit_after>// Copyright (c) 2013-2014 Anton Kozhevnikov, Thomas Schulthess
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
// the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
//    following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
//    and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED 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 fft3d_cpu.hpp
 *
 *  \brief Contains CPU specialization.
 */

/// CPU specialization of FFT3D class.
/** FFT convention:
 *  \f[
 *      f({\bf r}) = \sum_{{\bf G}} e^{i{\bf G}{\bf r}} f({\bf G})
 *  \f]
 *  is a \em backward transformation from a set of pw coefficients to a function.
 *
 *  \f[
 *      f({\bf G}) = \frac{1}{\Omega} \int e^{-i{\bf G}{\bf r}} f({\bf r}) d {\bf r} =
 *          \frac{1}{N} \sum_{{\bf r}_j} e^{-i{\bf G}{\bf r}_j} f({\bf r}_j)
 *  \f]
 *  is a \em forward transformation from a function to a set of coefficients.
*/
template<>
class FFT3D<CPU>
{
    private:

        /// Number of working threads inside each FFT.
        int num_fft_workers_;

        /// Number of threads doing individual FFTs.
        int num_fft_threads_;

        /// Size of each dimension.
        int grid_size_[3];

        /// reciprocal space range
        std::pair<int, int> grid_limits_[3];

        /// backward transformation plan for each thread
        std::vector<fftw_plan> plan_backward_;

        /// forward transformation plan for each thread
        std::vector<fftw_plan> plan_forward_;

        /// inout buffer for each thread
        mdarray<double_complex, 2> fftw_buffer_;

        int num_gvec_;

        mdarray<int, 2> gvec_;
        std::vector< vector3d<double> > gvec_cart_; // TODO: check if we really need to store it, or create "on the fly"

        mdarray<int, 3> gvec_index_;

        std::vector<int> index_map_;
        std::vector<int> gvec_shell_;
        std::vector<double> gvec_shell_len_;

        /// Execute backward transformation.
        inline void backward(int thread_id = 0)
        {
            fftw_execute(plan_backward_[thread_id]);
        }

        /// Execute forward transformation.
        inline void forward(int thread_id = 0)
        {
            fftw_execute(plan_forward_[thread_id]);
            double norm = 1.0 / size();
            for (int i = 0; i < size(); i++) fftw_buffer_(i, thread_id) *= norm;
        }

        /// Find smallest optimal grid size starting from n.
        int find_grid_size(int n)
        {
            while (true)
            {
                int m = n;
                for (int k = 2; k <= 5; k++)
                {
                    while (m % k == 0) m /= k;
                }
                if (m == 1)
                {
                    return n;
                }
                else
                {
                    n++;
                }
            }
        }

    public:

        FFT3D(vector3d<int> dims__,
              int num_fft_threads__,
              int num_fft_workers__)
            : num_fft_workers_(num_fft_workers__),
              num_fft_threads_(num_fft_threads__)
        {
            Timer t("sirius::FFT3D<CPU>::FFT3D");
            for (int i = 0; i < 3; i++)
            {
                grid_size_[i] = find_grid_size(dims__[i]);

                grid_limits_[i].second = grid_size_[i] / 2;
                grid_limits_[i].first = grid_limits_[i].second - grid_size_[i] + 1;
            }

            fftw_plan_with_nthreads(num_fft_workers_);

            fftw_buffer_ = mdarray<double_complex, 2>(size(), num_fft_threads_);

            plan_backward_.resize(num_fft_threads_);
            plan_forward_.resize(num_fft_threads_);

            for (int i = 0; i < num_fft_threads_; i++)
            {
                plan_backward_[i] = fftw_plan_dft_3d(size(2), size(1), size(0),
                                                     (fftw_complex*)&fftw_buffer_(0, i),
                                                     (fftw_complex*)&fftw_buffer_(0, i), 1, FFTW_ESTIMATE);
                plan_forward_[i] = fftw_plan_dft_3d(size(2), size(1), size(0),
                                                    (fftw_complex*)&fftw_buffer_(0, i),
                                                    (fftw_complex*)&fftw_buffer_(0, i), -1, FFTW_ESTIMATE);
            }
            fftw_plan_with_nthreads(1);
        }

        ~FFT3D()
        {
            for (int i = 0; i < num_fft_threads_; i++)
            {
                fftw_destroy_plan(plan_backward_[i]);
                fftw_destroy_plan(plan_forward_[i]);
            }
        }

        /// Zero the input buffer for a given thread.
        inline void zero(int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            memset(&fftw_buffer_(0, thread_id), 0, size() * sizeof(double_complex));
        }

        template<typename T>
        inline void input(int n, int* map, T* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            zero(thread_id);
            for (int i = 0; i < n; i++) fftw_buffer_(map[i], thread_id) = data[i];
        }

        inline void input(double* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < size(); i++) fftw_buffer_(i, thread_id) = data[i];
        }

        inline void input(double_complex* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            memcpy(&fftw_buffer_(0, thread_id), data, size() * sizeof(double_complex));
        }

        /// Execute the transformation for a given thread.
        inline void transform(int direction, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            switch(direction)
            {
                case 1:
                {
                    backward(thread_id);
                    break;
                }
                case -1:
                {
                    forward(thread_id);
                    break;
                }
                default:
                {
                    error_local(__FILE__, __LINE__, "wrong FFT direction");
                }
            }
        }

        inline void output(double* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < size(); i++) data[i] = real(fftw_buffer_(i, thread_id));
        }

        inline void output(double_complex* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            memcpy(data, &fftw_buffer_(0, thread_id), size() * sizeof(double_complex));
        }

        inline void output(int n, int* map, double_complex* data, int thread_id = 0)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < n; i++) data[i] = fftw_buffer_(map[i], thread_id);
        }

        inline void output(int n, int* map, double_complex* data, int thread_id, double alpha)
        {
            assert(thread_id < num_fft_threads());

            for (int i = 0; i < n; i++) data[i] += alpha * fftw_buffer_(map[i], thread_id);
        }

        inline const std::pair<int, int>& grid_limits(int idim)
        {
            return grid_limits_[idim];
        }

        /// Total size of the FFT grid.
        inline int size()
        {
            return grid_size_[0] * grid_size_[1] * grid_size_[2];
        }

        /// Size of a given dimension.
        inline int size(int d)
        {
            assert(d >= 0 && d < 3);
            return grid_size_[d];
        }

        /// Return linear index of a plane-wave harmonic with fractional coordinates (10, i1, i2) inside fft buffer.
        inline int index(int i0, int i1, int i2)
        {
            if (i0 < 0) i0 += grid_size_[0];
            if (i1 < 0) i1 += grid_size_[1];
            if (i2 < 0) i2 += grid_size_[2];

            return (i0 + i1 * grid_size_[0] + i2 * grid_size_[0] * grid_size_[1]);
        }

        /// Direct access to the fft buffer
        inline double_complex& buffer(int i, int thread_id = 0)
        {
            return fftw_buffer_(i, thread_id);
        }

        vector3d<int> grid_size()
        {
            return vector3d<int>(grid_size_);
        }

        void init_gvec(double Gmax__, matrix3d<double>& M__)
        {
            mdarray<int, 2> gvec_tmp(3, size());
            std::vector< std::pair<double, int> > gvec_tmp_length;

            for (int i0 = grid_limits(0).first; i0 <= grid_limits(0).second; i0++)
            {
                for (int i1 = grid_limits(1).first; i1 <= grid_limits(1).second; i1++)
                {
                    for (int i2 = grid_limits(2).first; i2 <= grid_limits(2).second; i2++)
                    {
                        int ig = (int)gvec_tmp_length.size();

                        gvec_tmp(0, ig) = i0;
                        gvec_tmp(1, ig) = i1;
                        gvec_tmp(2, ig) = i2;

                        auto vc = M__ * vector3d<double>(i0, i1, i2);

                        gvec_tmp_length.push_back(std::pair<double, int>(vc.length(), ig));
                    }
                }
            }

            /* sort G-vectors by length */
            std::sort(gvec_tmp_length.begin(), gvec_tmp_length.end());

            /* create sorted list of G-vectors */
            gvec_ = mdarray<int, 2>(3, size());
            gvec_cart_ = std::vector< vector3d<double> >(size());

            /* find number of G-vectors within the cutoff */
            num_gvec_ = 0;
            for (int i = 0; i < size(); i++)
            {
                for (int x = 0; x < 3; x++) gvec_(x, i) = gvec_tmp(x, gvec_tmp_length[i].second);

                gvec_cart_[i] = M__ * vector3d<double>(gvec_(0, i), gvec_(1, i), gvec_(2, i));

                if (gvec_tmp_length[i].first <= Gmax__) num_gvec_++;
            }

            gvec_index_ = mdarray<int, 3>(mdarray_index_descriptor(grid_limits(0).first, grid_limits(0).second),
                                          mdarray_index_descriptor(grid_limits(1).first, grid_limits(1).second),
                                          mdarray_index_descriptor(grid_limits(2).first, grid_limits(2).second));
            index_map_.resize(size());

            gvec_shell_.resize(size());
            gvec_shell_len_.clear();

            for (int ig = 0; ig < size(); ig++)
            {
                int i0 = gvec_(0, ig);
                int i1 = gvec_(1, ig);
                int i2 = gvec_(2, ig);

                /* mapping from G-vector to it's index */
                gvec_index_(i0, i1, i2) = ig;

                /* mapping of FFT buffer linear index */
                index_map_[ig] = index(i0, i1, i2);

                /* find G-shells */
                double t = gvec_tmp_length[ig].first;
                if (gvec_shell_len_.empty() || fabs(t - gvec_shell_len_.back()) > 1e-10) gvec_shell_len_.push_back(t);
                gvec_shell_[ig] = (int)gvec_shell_len_.size() - 1;
            }
        }

        /// Return number of G-vectors within the cutoff.
        inline int num_gvec()
        {
            return num_gvec_;
        }

        /// Return G-vector in fractional coordinates (this are the three Miller indices).
        inline vector3d<int> gvec(int ig__)
        {
            return vector3d<int>(gvec_(0, ig__), gvec_(1, ig__), gvec_(2, ig__));
        }

        /// Return G-vector in Cartesian coordinates.
        inline vector3d<double>gvec_cart(int ig__)
        {
            assert(ig__ >= 0 && ig__ < (int)gvec_cart_.size());
            return gvec_cart_[ig__];
        }

        /// Return length of a G-vector.
        inline double gvec_len(int ig__)
        {
            return gvec_shell_len(gvec_shell(ig__));
        }

        /// Return number of G-vector shells within the cutoff.
        /** G-vectors with the same length belong to the same shell. */
        inline int num_gvec_shells_inner()
        {
            return gvec_shell(num_gvec_);
        }

        /// Return total number of G-vector shells, including incomplete shells.
        /** Incomplete G-shells are formed by G-vectors outisde the cutoff radius (for example,
         *  by G-vectors at corners of FFT grid).
         */
        inline int num_gvec_shells_total()
        {
            return (int)gvec_shell_len_.size();
        }

        /// Return index of a G-vector shell for a given G-vector.
        inline int gvec_shell(int ig__)
        {
            assert(ig__ >= 0 && ig__ < (int)gvec_shell_.size());
            return gvec_shell_[ig__];
        }

        /// Return length of a G-vector shell.
        inline double gvec_shell_len(int igsh__)
        {
            assert(igsh__ >= 0 && igsh__ < (int)gvec_shell_len_.size());
            return gvec_shell_len_[igsh__];
        }

        inline int* index_map()
        {
            return &index_map_[0];
        }

        inline int index_map(int ig__)
        {
            assert(ig__ >= 0 && ig__ < (int)index_map_.size());
            return index_map_[ig__];
        }

        inline int num_fft_threads()
        {
            return num_fft_threads_;
        }

        inline int gvec_index(vector3d<int> gvec__)
        {
            return gvec_index_(gvec__[0], gvec__[1], gvec__[2]);
        }
};

<|endoftext|>


<commit_before>/*

Copyright (c) 2006-2012, Arvid Norberg
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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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 OWNER 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.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/file_storage.hpp" // for file_entry

namespace libtorrent
{

	file_pool::file_pool(int size)
		: m_size(size)
		, m_low_prio_io(true)
#if TORRENT_CLOSE_MAY_BLOCK
		, m_stop_thread(false)
		, m_closer_thread(boost::bind(&file_pool::closer_thread_fun, this))
#endif
	{}

	file_pool::~file_pool()
	{
#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l(m_closer_mutex);
		m_stop_thread = true;
		l.unlock();
		// wait for hte closer thread to finish closing all files
		m_closer_thread.join();
#endif
	}

#if TORRENT_CLOSE_MAY_BLOCK
	void file_pool::closer_thread_fun()
	{
		for (;;)
		{
			mutex::scoped_lock l(m_closer_mutex);
			if (m_stop_thread)
			{
				l.unlock();
				m_queued_for_close.clear();
				return;
			}

			// find a file that doesn't have any other threads referencing
			// it. Since only those files can be closed in this thead
			std::vector<boost::intrusive_ptr<file> >::iterator i = std::find_if(
				m_queued_for_close.begin(), m_queued_for_close.end()
				, boost::bind(&file::refcount, boost::bind(&boost::intrusive_ptr<file>::get, _1)) == 1);

			if (i == m_queued_for_close.end())
			{
				l.unlock();
				// none of the files are ready to be closet yet
				// because they're still in use by other threads
				// hold off for a while
				sleep(1000);
			}
			else
			{
				// ok, first pull the file out of the queue, release the mutex
				// (since closing the file may block) and then close it.
				boost::intrusive_ptr<file> f = *i;
				m_queued_for_close.erase(i);
				l.unlock();
				f->close();
			}
		}
	}
#endif

#ifdef TORRENT_WINDOWS
	void set_low_priority(boost::intrusive_ptr<file> const& f)
	{
		// file prio is only supported on vista and up
		// so load the functions dynamically
		typedef enum _FILE_INFO_BY_HANDLE_CLASS {
			FileBasicInfo,
			FileStandardInfo,
			FileNameInfo,
			FileRenameInfo,
			FileDispositionInfo,
			FileAllocationInfo,
			FileEndOfFileInfo,
			FileStreamInfo,
			FileCompressionInfo,
			FileAttributeTagInfo,
			FileIdBothDirectoryInfo,
			FileIdBothDirectoryRestartInfo,
			FileIoPriorityHintInfo,
			FileRemoteProtocolInfo,
			MaximumFileInfoByHandleClass
		} FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;

		typedef enum _PRIORITY_HINT {
			IoPriorityHintVeryLow = 0,
			IoPriorityHintLow,
			IoPriorityHintNormal,
			MaximumIoPriorityHintType
		} PRIORITY_HINT;

		typedef struct _FILE_IO_PRIORITY_HINT_INFO {
			PRIORITY_HINT PriorityHint;
		} FILE_IO_PRIORITY_HINT_INFO, *PFILE_IO_PRIORITY_HINT_INFO;

		typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
		static SetFileInformationByHandle_t SetFileInformationByHandle = NULL;

		static bool failed_kernel_load = false;

		if (failed_kernel_load) return;

		if (SetFileInformationByHandle == NULL)
		{
			HMODULE kernel32 = LoadLibraryA("kernel32.dll");
			if (kernel32 == NULL)
			{
				failed_kernel_load = true;
				return;
			}

			SetFileInformationByHandle = (SetFileInformationByHandle_t)GetProcAddress(kernel32, "SetFileInformationByHandle");
			if (SetFileInformationByHandle == NULL)
			{
				failed_kernel_load = true;
				return;
			}
		}

		TORRENT_ASSERT(SetFileInformationByHandle);

		FILE_IO_PRIORITY_HINT_INFO io_hint;
		io_hint.PriorityHint = IoPriorityHintLow;
		SetFileInformationByHandle(f->native_handle(),
			FileIoPriorityHintInfo, &io_hint, sizeof(io_hint));
	}
#endif // TORRENT_WINDOWS

	boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
		, file_storage::iterator fe, file_storage const& fs, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(std::make_pair(st, fs.file_index(*fe)));
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::intrusive_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if ((((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
				|| (e.mode & file::no_buffer) != (m & file::no_buffer)
				|| (e.mode & file::random_access) != (m & file::random_access))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr->refcount() == 1);

#if TORRENT_CLOSE_MAY_BLOCK
				mutex::scoped_lock l(m_closer_mutex);
				m_queued_for_close.push_back(e.file_ptr);
				l.unlock();
				e.file_ptr = new file;
#else
				e.file_ptr->close();
#endif
				std::string full_path = combine_path(p, fs.file_path(*fe));
				if (!e.file_ptr->open(full_path, m, ec))
				{
					m_files.erase(i);
					return boost::intrusive_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
				if (m_low_prio_io)
					set_low_priority(e.file_ptr);
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		std::string full_path = combine_path(p, fs.file_path(*fe));
		if (!e.file_ptr->open(full_path, m, ec))
			return boost::intrusive_ptr<file>();
#ifdef TORRENT_WINDOWS
		if (m_low_prio_io)
			set_low_priority(e.file_ptr);
#endif
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(std::make_pair(st, fs.file_index(*fe)), e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l.unlock();
#endif
		m_files.erase(i);
	}

	void file_pool::release(void* st, int file_index)
	{
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(std::make_pair(st, file_index));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l2(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l2.unlock();
#endif
		m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}

<commit_msg>fix file_pool to support new absolute paths in file_storage<commit_after>/*

Copyright (c) 2006-2012, Arvid Norberg
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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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 OWNER 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.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/file_storage.hpp" // for file_entry

namespace libtorrent
{

	file_pool::file_pool(int size)
		: m_size(size)
		, m_low_prio_io(true)
#if TORRENT_CLOSE_MAY_BLOCK
		, m_stop_thread(false)
		, m_closer_thread(boost::bind(&file_pool::closer_thread_fun, this))
#endif
	{}

	file_pool::~file_pool()
	{
#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l(m_closer_mutex);
		m_stop_thread = true;
		l.unlock();
		// wait for hte closer thread to finish closing all files
		m_closer_thread.join();
#endif
	}

#if TORRENT_CLOSE_MAY_BLOCK
	void file_pool::closer_thread_fun()
	{
		for (;;)
		{
			mutex::scoped_lock l(m_closer_mutex);
			if (m_stop_thread)
			{
				l.unlock();
				m_queued_for_close.clear();
				return;
			}

			// find a file that doesn't have any other threads referencing
			// it. Since only those files can be closed in this thead
			std::vector<boost::intrusive_ptr<file> >::iterator i = std::find_if(
				m_queued_for_close.begin(), m_queued_for_close.end()
				, boost::bind(&file::refcount, boost::bind(&boost::intrusive_ptr<file>::get, _1)) == 1);

			if (i == m_queued_for_close.end())
			{
				l.unlock();
				// none of the files are ready to be closet yet
				// because they're still in use by other threads
				// hold off for a while
				sleep(1000);
			}
			else
			{
				// ok, first pull the file out of the queue, release the mutex
				// (since closing the file may block) and then close it.
				boost::intrusive_ptr<file> f = *i;
				m_queued_for_close.erase(i);
				l.unlock();
				f->close();
			}
		}
	}
#endif

#ifdef TORRENT_WINDOWS
	void set_low_priority(boost::intrusive_ptr<file> const& f)
	{
		// file prio is only supported on vista and up
		// so load the functions dynamically
		typedef enum _FILE_INFO_BY_HANDLE_CLASS {
			FileBasicInfo,
			FileStandardInfo,
			FileNameInfo,
			FileRenameInfo,
			FileDispositionInfo,
			FileAllocationInfo,
			FileEndOfFileInfo,
			FileStreamInfo,
			FileCompressionInfo,
			FileAttributeTagInfo,
			FileIdBothDirectoryInfo,
			FileIdBothDirectoryRestartInfo,
			FileIoPriorityHintInfo,
			FileRemoteProtocolInfo,
			MaximumFileInfoByHandleClass
		} FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;

		typedef enum _PRIORITY_HINT {
			IoPriorityHintVeryLow = 0,
			IoPriorityHintLow,
			IoPriorityHintNormal,
			MaximumIoPriorityHintType
		} PRIORITY_HINT;

		typedef struct _FILE_IO_PRIORITY_HINT_INFO {
			PRIORITY_HINT PriorityHint;
		} FILE_IO_PRIORITY_HINT_INFO, *PFILE_IO_PRIORITY_HINT_INFO;

		typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
		static SetFileInformationByHandle_t SetFileInformationByHandle = NULL;

		static bool failed_kernel_load = false;

		if (failed_kernel_load) return;

		if (SetFileInformationByHandle == NULL)
		{
			HMODULE kernel32 = LoadLibraryA("kernel32.dll");
			if (kernel32 == NULL)
			{
				failed_kernel_load = true;
				return;
			}

			SetFileInformationByHandle = (SetFileInformationByHandle_t)GetProcAddress(kernel32, "SetFileInformationByHandle");
			if (SetFileInformationByHandle == NULL)
			{
				failed_kernel_load = true;
				return;
			}
		}

		TORRENT_ASSERT(SetFileInformationByHandle);

		FILE_IO_PRIORITY_HINT_INFO io_hint;
		io_hint.PriorityHint = IoPriorityHintLow;
		SetFileInformationByHandle(f->native_handle(),
			FileIoPriorityHintInfo, &io_hint, sizeof(io_hint));
	}
#endif // TORRENT_WINDOWS

	boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
		, file_storage::iterator fe, file_storage const& fs, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(std::make_pair(st, fs.file_index(*fe)));
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::intrusive_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if ((((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
				|| (e.mode & file::no_buffer) != (m & file::no_buffer)
				|| (e.mode & file::random_access) != (m & file::random_access))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr->refcount() == 1);

#if TORRENT_CLOSE_MAY_BLOCK
				mutex::scoped_lock l(m_closer_mutex);
				m_queued_for_close.push_back(e.file_ptr);
				l.unlock();
				e.file_ptr = new file;
#else
				e.file_ptr->close();
#endif
				std::string full_path = fs.file_path(*fe, p);
				if (!e.file_ptr->open(full_path, m, ec))
				{
					m_files.erase(i);
					return boost::intrusive_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
				if (m_low_prio_io)
					set_low_priority(e.file_ptr);
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		std::string full_path = fs.file_path(*fe, p);
		if (!e.file_ptr->open(full_path, m, ec))
			return boost::intrusive_ptr<file>();
#ifdef TORRENT_WINDOWS
		if (m_low_prio_io)
			set_low_priority(e.file_ptr);
#endif
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(std::make_pair(st, fs.file_index(*fe)), e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l.unlock();
#endif
		m_files.erase(i);
	}

	void file_pool::release(void* st, int file_index)
	{
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(std::make_pair(st, file_index));
		if (i == m_files.end()) return;

#if TORRENT_CLOSE_MAY_BLOCK
		mutex::scoped_lock l2(m_closer_mutex);
		m_queued_for_close.push_back(i->second.file_ptr);
		l2.unlock();
#endif
		m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}

<|endoftext|>


<commit_before>#include "fileinput.h"
#ifdef HAVE_INOTIFY_INIT
#include <sys/inotify.h>
/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 1024 events */
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))
#endif // HAVE_INOTIFY_INIT

void FileInput::monitor_ports(action_t action, const char* isource,
        all_cfg_t *cfg, void *sp_params) {
#ifdef HAVE_INOTIFY_INIT
    int fd = inotify_init();
    if (fd < 0)
        LOG_FATAL("inotify_init failed");

    inotify_add_watch(fd, isource, IN_CREATE);
    LOG_INFO("Added inotify watch for %s", isource);

    while (1) {
        char buf[BUF_LEN];
        volatile int errno = 0;
        int len, i = 0;

        len = read (fd, buf, BUF_LEN);
        if (len < 0) {
            LOG_ERROR("Something went wrong with inotify, errno: %d", errno);
        } else if (!len) {
            LOG_ERROR("BUF_LEN is too small??");
        }
        while (i < len) {
            struct inotify_event *event;
            event = (struct inotify_event *) &buf[i];

            LOG_DEBUG("Got inotify event: wd=%d mask=%u cookie=%u len=%u",
                    event->wd, event->mask,
                    event->cookie, event->len);
            if (event->len) {
                all_cfg_t cfg_local(cfg->first, cfg->second); // Wow that's a nice hack :-)

                char *filename = (char*)malloc(strlen(isource)+strlen(event->name)+1);
                sprintf(filename, "%s%s", isource, event->name);
                LOG_INFO ("Creating new FileInput for %s", filename);
                FileInput *input = new FileInput(filename, &cfg_local);
                LOG_DEBUG("Calling new_port_created");
                new_port_created( action, filename, input, &cfg_local, sp_params );
                LOG_DEBUG("New port created callback is over");
                delete filename;
            }
            i += EVENT_SIZE + event->len;
        }
    }
#else
    (void)action;
    (void)isource;
    (void)cfg;
    (void)sp_params;

    LOG_FATAL("Not implemented!");
#endif // HAVE_INOTIFY_INIT
}
int FileInput::giveInput(buffer_t *buf_prop) {
    if (reading_over) { return 0; }

    unsigned bufferlength = (unsigned)(s->signal.rate+0.5) * BUFFERSIZE;

    sox_sample_t *buf = (sox_sample_t*)
        calloc(bufferlength, sizeof(sox_sample_t));

    size_t read_size = sox_read(s, buf, bufferlength);

    if (read_size < bufferlength) {
        LOG_INFO("EOF reached. Read_size: %d, bufferlength: %d",
                read_size, bufferlength);
        reading_over = true;
    }
	buf_prop->buf = (sample_t*) calloc(read_size, sizeof(sample_t));

	for (unsigned i = 0; i < read_size; i++) {
		buf_prop->buf[i] = (sample_t)buf[i];
	}
    buf_prop->nframes = read_size;
    buf_prop->delete_me = true;
    return 1;
}

FileInput::FileInput(const char *isource, all_cfg_t *cfg) {
    name = (char*) malloc(strlen(isource)+1);
    memcpy(name,isource,strlen(isource)+1);

    reading_over = false;
    if ((s = sox_open_read(isource, NULL, NULL, NULL)) == NULL) {
        perror("sox_open_read");
        exit(1);
    }
    LOG_DEBUG("Sox initialized. Sampling rate: %.6f, channels: %d,"
            "bitrate: %d, samples: %d",
            s->signal.rate, s->signal.channels,
            s->signal.precision, s->signal.length);
    SAMPLE_RATE = (int)s->signal.rate;

    for (vector<sVolumes>::iterator vol = cfg->second.begin();
            vol != cfg->second.end(); vol++) {
        vol->min *= 2147483648U; // 1 << 31
        vol->max *= 2147483648U;
    }
}

FileInput::~FileInput() {
    LOG_INFO("Closing sox instance");
    sox_close(s);
}
<commit_msg>HAVE_INOTIFY_INIT -> HAVE_INOTIFY<commit_after>#include "fileinput.h"
#ifdef HAVE_INOTIFY
#include <sys/inotify.h>
/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 1024 events */
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))
#endif // HAVE_INOTIFY

void FileInput::monitor_ports(action_t action, const char* isource,
        all_cfg_t *cfg, void *sp_params) {
#ifdef HAVE_INOTIFY
    int fd = inotify_init();
    if (fd < 0)
        LOG_FATAL("inotify_init failed");

    inotify_add_watch(fd, isource, IN_CREATE);
    LOG_INFO("Added inotify watch for %s", isource);

    while (1) {
        char buf[BUF_LEN];
        volatile int errno = 0;
        int len, i = 0;

        len = read (fd, buf, BUF_LEN);
        if (len < 0) {
            LOG_ERROR("Something went wrong with inotify, errno: %d", errno);
        } else if (!len) {
            LOG_ERROR("BUF_LEN is too small??");
        }
        while (i < len) {
            struct inotify_event *event;
            event = (struct inotify_event *) &buf[i];

            LOG_DEBUG("Got inotify event: wd=%d mask=%u cookie=%u len=%u",
                    event->wd, event->mask,
                    event->cookie, event->len);
            if (event->len) {
                all_cfg_t cfg_local(cfg->first, cfg->second); // Wow that's a nice hack :-)

                char *filename = (char*)malloc(strlen(isource)+strlen(event->name)+1);
                sprintf(filename, "%s%s", isource, event->name);
                LOG_INFO ("Creating new FileInput for %s", filename);
                FileInput *input = new FileInput(filename, &cfg_local);
                LOG_DEBUG("Calling new_port_created");
                new_port_created( action, filename, input, &cfg_local, sp_params );
                LOG_DEBUG("New port created callback is over");
                delete filename;
            }
            i += EVENT_SIZE + event->len;
        }
    }
#else
    (void)action;
    (void)isource;
    (void)cfg;
    (void)sp_params;

    LOG_FATAL("Not implemented!");
#endif // HAVE_INOTIFY
}
int FileInput::giveInput(buffer_t *buf_prop) {
    if (reading_over) { return 0; }

    unsigned bufferlength = (unsigned)(s->signal.rate+0.5) * BUFFERSIZE;

    sox_sample_t *buf = (sox_sample_t*)
        calloc(bufferlength, sizeof(sox_sample_t));

    size_t read_size = sox_read(s, buf, bufferlength);

    if (read_size < bufferlength) {
        LOG_INFO("EOF reached. Read_size: %d, bufferlength: %d",
                read_size, bufferlength);
        reading_over = true;
    }
	buf_prop->buf = (sample_t*) calloc(read_size, sizeof(sample_t));

	for (unsigned i = 0; i < read_size; i++) {
		buf_prop->buf[i] = (sample_t)buf[i];
	}
    buf_prop->nframes = read_size;
    buf_prop->delete_me = true;
    return 1;
}

FileInput::FileInput(const char *isource, all_cfg_t *cfg) {
    name = (char*) malloc(strlen(isource)+1);
    memcpy(name,isource,strlen(isource)+1);

    reading_over = false;
    if ((s = sox_open_read(isource, NULL, NULL, NULL)) == NULL) {
        perror("sox_open_read");
        exit(1);
    }
    LOG_DEBUG("Sox initialized. Sampling rate: %.6f, channels: %d,"
            "bitrate: %d, samples: %d",
            s->signal.rate, s->signal.channels,
            s->signal.precision, s->signal.length);
    SAMPLE_RATE = (int)s->signal.rate;

    for (vector<sVolumes>::iterator vol = cfg->second.begin();
            vol != cfg->second.end(); vol++) {
        vol->min *= 2147483648U; // 1 << 31
        vol->max *= 2147483648U;
    }
}

FileInput::~FileInput() {
    LOG_INFO("Closing sox instance");
    sox_close(s);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DataPoint.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: ihi $ $Date: 2008-01-14 14:00:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "DataPoint.hxx"
#include "DataPointProperties.hxx"
#include "CharacterProperties.hxx"
#include "UserDefinedProperties.hxx"
#include "PropertyHelper.hxx"
#include "macros.hxx"
#include "ContainerHelper.hxx"

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_STYLE_XSTYLE_HPP_
#include <com/sun/star/style/XStyle.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

#include <algorithm>

using namespace ::com::sun::star;

using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::beans::Property;
using ::osl::MutexGuard;
using ::rtl::OUString;

// ____________________________________________________________

namespace
{
const Sequence< Property > & lcl_GetPropertySequence()
{
    static Sequence< Property > aPropSeq;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aPropSeq.getLength() )
    {
        // get properties
        ::std::vector< ::com::sun::star::beans::Property > aProperties;
        ::chart::DataPointProperties::AddPropertiesToVector( aProperties );
        ::chart::CharacterProperties::AddPropertiesToVector( aProperties );
        ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties );

        // and sort them for access via bsearch
        ::std::sort( aProperties.begin(), aProperties.end(),
                     ::chart::PropertyNameLess() );

        // transfer result to static Sequence
        aPropSeq = ::chart::ContainerHelper::ContainerToSequence( aProperties );
    }

    return aPropSeq;
}
} // anonymous namespace

// ____________________________________________________________

namespace chart
{

DataPoint::DataPoint() :
        ::property::OPropertySet( m_aMutex ),
        m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder())
{}

DataPoint::DataPoint( const uno::Reference< beans::XPropertySet > & rParentProperties ) :
        ::property::OPropertySet( m_aMutex ),
        m_xParentProperties( rParentProperties ),
        m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder())
{}

DataPoint::DataPoint( const DataPoint & rOther ) :
        MutexContainer(),
        impl::DataPoint_Base(),
        ::property::OPropertySet( rOther, m_aMutex ),
        m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder())
{
    // m_xParentProperties has to be set from outside, like in the method
    // DataSeries::createClone

    // add as listener to XPropertySet properties
    Reference< beans::XPropertySet > xPropertySet;
    uno::Any aValue;

    getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X );
    if( ( aValue >>= xPropertySet )
        && xPropertySet.is())
        ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder );

    getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y );
    if( ( aValue >>= xPropertySet )
        && xPropertySet.is())
        ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder );
}

DataPoint::~DataPoint()
{
    try
    {
        // remove listener from XPropertySet properties
        Reference< beans::XPropertySet > xPropertySet;
        uno::Any aValue;

        getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X );
        if( ( aValue >>= xPropertySet )
            && xPropertySet.is())
            ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder );

        getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y );
        if( ( aValue >>= xPropertySet )
            && xPropertySet.is())
            ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

// ____ XCloneable ____
uno::Reference< util::XCloneable > SAL_CALL DataPoint::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new DataPoint( *this ));
}

// ____ XChild ____
Reference< uno::XInterface > SAL_CALL DataPoint::getParent()
    throw (uno::RuntimeException)
{
    return Reference< uno::XInterface >( m_xParentProperties, uno::UNO_QUERY );
}

void SAL_CALL DataPoint::setParent(
    const Reference< uno::XInterface >& Parent )
    throw (lang::NoSupportException,
           uno::RuntimeException)
{
    m_xParentProperties.set( Parent, uno::UNO_QUERY );
}

// ____ OPropertySet ____
uno::Any DataPoint::GetDefaultValue( sal_Int32 nHandle ) const
    throw(beans::UnknownPropertyException)
{
    // the value set at the data series is the default
    uno::Reference< beans::XFastPropertySet > xFast( m_xParentProperties, uno::UNO_QUERY );
    if( !xFast.is())
    {
        OSL_ENSURE( false, "data point needs a parent property set to provide values correctly" );
        return uno::Any();
    }

    return xFast->getFastPropertyValue( nHandle );
}

void SAL_CALL DataPoint::setFastPropertyValue_NoBroadcast(
    sal_Int32 nHandle, const uno::Any& rValue )
    throw (uno::Exception)
{
    if(    nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y
        || nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X )
    {
        uno::Any aOldValue;
        Reference< util::XModifyBroadcaster > xBroadcaster;
        this->getFastPropertyValue( aOldValue, nHandle );
        if( aOldValue.hasValue() &&
            (aOldValue >>= xBroadcaster) &&
            xBroadcaster.is())
        {
            ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder );
        }

        OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE );
        if( rValue.hasValue() &&
            (rValue >>= xBroadcaster) &&
            xBroadcaster.is())
        {
            ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder );
        }
    }

    ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue );
}

::cppu::IPropertyArrayHelper & SAL_CALL DataPoint::getInfoHelper()
{
    return getInfoHelperConst();
}

::cppu::IPropertyArrayHelper & SAL_CALL DataPoint::getInfoHelperConst() const
{
    static ::cppu::OPropertyArrayHelper aArrayHelper(
        lcl_GetPropertySequence(),
        /* bSorted = */ sal_True );

    return aArrayHelper;
}

// ____ XPropertySet ____
Reference< beans::XPropertySetInfo > SAL_CALL
    DataPoint::getPropertySetInfo()
    throw (uno::RuntimeException)
{
    static Reference< beans::XPropertySetInfo > xInfo;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( !xInfo.is())
    {
        xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo(
            getInfoHelper());
    }

    return xInfo;
    // \--
}

// ____ XModifyBroadcaster ____
void SAL_CALL DataPoint::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->addModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

void SAL_CALL DataPoint::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->removeModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

// ____ XModifyListener ____
void SAL_CALL DataPoint::modified( const lang::EventObject& aEvent )
    throw (uno::RuntimeException)
{
    m_xModifyEventForwarder->modified( aEvent );
}

// ____ XEventListener (base of XModifyListener) ____
void SAL_CALL DataPoint::disposing( const lang::EventObject& )
    throw (uno::RuntimeException)
{
    // nothing
}

// ____ OPropertySet ____
void DataPoint::firePropertyChangeEvent()
{
    fireModifyEvent();
}

void DataPoint::fireModifyEvent()
{
    m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this )));
}

Sequence< OUString > DataPoint::getSupportedServiceNames_Static()
{
    Sequence< OUString > aServices( 3 );
    aServices[ 0 ] = C2U( "com.sun.star.chart2.DataPoint" );
    aServices[ 1 ] = C2U( "com.sun.star.chart2.DataPointProperties" );
    aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" );
    return aServices;
}

// needed by MSC compiler
using impl::DataPoint_Base;

IMPLEMENT_FORWARD_XINTERFACE2( DataPoint, DataPoint_Base, ::property::OPropertySet )

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( DataPoint, C2U( "com.sun.star.comp.chart.DataPoint" ));

} //  namespace chart
<commit_msg>INTEGRATION: CWS chart20_DEV300 (1.7.28); FILE MERGED 2008/02/21 15:59:28 bm 1.7.28.1: #i366# error bars from ranges<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DataPoint.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2008-03-06 17:22:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_chart2.hxx"
#include "DataPoint.hxx"
#include "DataPointProperties.hxx"
#include "CharacterProperties.hxx"
#include "UserDefinedProperties.hxx"
#include "PropertyHelper.hxx"
#include "macros.hxx"
#include "ContainerHelper.hxx"

#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#ifndef _COM_SUN_STAR_STYLE_XSTYLE_HPP_
#include <com/sun/star/style/XStyle.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

#include <algorithm>

using namespace ::com::sun::star;

using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::beans::Property;
using ::osl::MutexGuard;
using ::rtl::OUString;

// ____________________________________________________________

namespace
{
const Sequence< Property > & lcl_GetPropertySequence()
{
    static Sequence< Property > aPropSeq;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( 0 == aPropSeq.getLength() )
    {
        // get properties
        ::std::vector< ::com::sun::star::beans::Property > aProperties;
        ::chart::DataPointProperties::AddPropertiesToVector( aProperties );
        ::chart::CharacterProperties::AddPropertiesToVector( aProperties );
        ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties );

        // and sort them for access via bsearch
        ::std::sort( aProperties.begin(), aProperties.end(),
                     ::chart::PropertyNameLess() );

        // transfer result to static Sequence
        aPropSeq = ::chart::ContainerHelper::ContainerToSequence( aProperties );
    }

    return aPropSeq;
}
} // anonymous namespace

// ____________________________________________________________

namespace chart
{

DataPoint::DataPoint() :
        ::property::OPropertySet( m_aMutex ),
        m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder()),
        m_bNoParentPropAllowed( false )
{}

DataPoint::DataPoint( const uno::Reference< beans::XPropertySet > & rParentProperties ) :
        ::property::OPropertySet( m_aMutex ),
        m_xParentProperties( rParentProperties ),
        m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder()),
        m_bNoParentPropAllowed( false )
{}

DataPoint::DataPoint( const DataPoint & rOther ) :
        MutexContainer(),
        impl::DataPoint_Base(),
        ::property::OPropertySet( rOther, m_aMutex ),
        m_xModifyEventForwarder( new ModifyListenerHelper::ModifyEventForwarder()),
        m_bNoParentPropAllowed( true )
{
    // m_xParentProperties has to be set from outside, like in the method
    // DataSeries::createClone

    // add as listener to XPropertySet properties
    Reference< beans::XPropertySet > xPropertySet;
    uno::Any aValue;

    getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X );
    if( ( aValue >>= xPropertySet )
        && xPropertySet.is())
        ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder );

    getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y );
    if( ( aValue >>= xPropertySet )
        && xPropertySet.is())
        ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder );

    m_bNoParentPropAllowed = false;
}

DataPoint::~DataPoint()
{
    try
    {
        // remove listener from XPropertySet properties
        Reference< beans::XPropertySet > xPropertySet;
        uno::Any aValue;

        getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X );
        if( ( aValue >>= xPropertySet )
            && xPropertySet.is())
            ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder );

        getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y );
        if( ( aValue >>= xPropertySet )
            && xPropertySet.is())
            ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

// ____ XCloneable ____
uno::Reference< util::XCloneable > SAL_CALL DataPoint::createClone()
    throw (uno::RuntimeException)
{
    return uno::Reference< util::XCloneable >( new DataPoint( *this ));
}

// ____ XChild ____
Reference< uno::XInterface > SAL_CALL DataPoint::getParent()
    throw (uno::RuntimeException)
{
    return Reference< uno::XInterface >( m_xParentProperties, uno::UNO_QUERY );
}

void SAL_CALL DataPoint::setParent(
    const Reference< uno::XInterface >& Parent )
    throw (lang::NoSupportException,
           uno::RuntimeException)
{
    m_xParentProperties.set( Parent, uno::UNO_QUERY );
}

// ____ OPropertySet ____
uno::Any DataPoint::GetDefaultValue( sal_Int32 nHandle ) const
    throw(beans::UnknownPropertyException)
{
    // the value set at the data series is the default
    uno::Reference< beans::XFastPropertySet > xFast( m_xParentProperties, uno::UNO_QUERY );
    if( !xFast.is())
    {
        OSL_ENSURE( m_bNoParentPropAllowed, "data point needs a parent property set to provide values correctly" );
        return uno::Any();
    }

    return xFast->getFastPropertyValue( nHandle );
}

void SAL_CALL DataPoint::setFastPropertyValue_NoBroadcast(
    sal_Int32 nHandle, const uno::Any& rValue )
    throw (uno::Exception)
{
    if(    nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y
        || nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X )
    {
        uno::Any aOldValue;
        Reference< util::XModifyBroadcaster > xBroadcaster;
        this->getFastPropertyValue( aOldValue, nHandle );
        if( aOldValue.hasValue() &&
            (aOldValue >>= xBroadcaster) &&
            xBroadcaster.is())
        {
            ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder );
        }

        OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE );
        if( rValue.hasValue() &&
            (rValue >>= xBroadcaster) &&
            xBroadcaster.is())
        {
            ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder );
        }
    }

    ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue );
}

::cppu::IPropertyArrayHelper & SAL_CALL DataPoint::getInfoHelper()
{
    return getInfoHelperConst();
}

::cppu::IPropertyArrayHelper & SAL_CALL DataPoint::getInfoHelperConst() const
{
    static ::cppu::OPropertyArrayHelper aArrayHelper(
        lcl_GetPropertySequence(),
        /* bSorted = */ sal_True );

    return aArrayHelper;
}

// ____ XPropertySet ____
Reference< beans::XPropertySetInfo > SAL_CALL
    DataPoint::getPropertySetInfo()
    throw (uno::RuntimeException)
{
    static Reference< beans::XPropertySetInfo > xInfo;

    // /--
    ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
    if( !xInfo.is())
    {
        xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo(
            getInfoHelper());
    }

    return xInfo;
    // \--
}

// ____ XModifyBroadcaster ____
void SAL_CALL DataPoint::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->addModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

void SAL_CALL DataPoint::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
    throw (uno::RuntimeException)
{
    try
    {
        uno::Reference< util::XModifyBroadcaster > xBroadcaster( m_xModifyEventForwarder, uno::UNO_QUERY_THROW );
        xBroadcaster->removeModifyListener( aListener );
    }
    catch( const uno::Exception & ex )
    {
        ASSERT_EXCEPTION( ex );
    }
}

// ____ XModifyListener ____
void SAL_CALL DataPoint::modified( const lang::EventObject& aEvent )
    throw (uno::RuntimeException)
{
    m_xModifyEventForwarder->modified( aEvent );
}

// ____ XEventListener (base of XModifyListener) ____
void SAL_CALL DataPoint::disposing( const lang::EventObject& )
    throw (uno::RuntimeException)
{
    // nothing
}

// ____ OPropertySet ____
void DataPoint::firePropertyChangeEvent()
{
    fireModifyEvent();
}

void DataPoint::fireModifyEvent()
{
    m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this )));
}

Sequence< OUString > DataPoint::getSupportedServiceNames_Static()
{
    Sequence< OUString > aServices( 3 );
    aServices[ 0 ] = C2U( "com.sun.star.chart2.DataPoint" );
    aServices[ 1 ] = C2U( "com.sun.star.chart2.DataPointProperties" );
    aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" );
    return aServices;
}

// needed by MSC compiler
using impl::DataPoint_Base;

IMPLEMENT_FORWARD_XINTERFACE2( DataPoint, DataPoint_Base, ::property::OPropertySet )

// implement XServiceInfo methods basing upon getSupportedServiceNames_Static
APPHELPER_XSERVICEINFO_IMPL( DataPoint, C2U( "com.sun.star.comp.chart.DataPoint" ));

} //  namespace chart
<|endoftext|>


<commit_before>

/**
 * Copyright (c) 2017 blueback
 * Released under the MIT License
 * https://github.com/bluebackblue/brownie/blob/master/LICENSE
 * http://bbbproject.sakura.ne.jp/wordpress/mitlicense
 * @brief デバッグメニュー。
*/

/** include
*/
#include <bsys_pch.h>

/** include
*/
#include "../types/types.h"

/** include
*/
#include "./windowmenu.h"

/** NBsys::NWindowMenu
*/
#if(BSYS_WINDOWMENU_ENABLE)
namespace NBsys{namespace NWindowMenu
{
	/** s_windowmenu
	*/
	sharedptr<WindowMenu> s_windowmenu;

	/** constructor
	*/
	WindowMenu::WindowMenu(sharedptr<WindowMenu_Callback_Base>& a_callback)
		:
		callback(a_callback)
	{
	}

	/** destructor
	*/
	WindowMenu::~WindowMenu()
	{
	}

	/** Update
	*/
	void WindowMenu::Update()
	{
		//削除リクエスト。
		{
			STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();
			while(t_it != this->list.end()){
				if((*t_it)->GetDeleteRequest() == true){
					t_it = this->list.erase(t_it);
				}else{
					t_it++;
				}
			}
		}

		{
			STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_end = this->list.end();

			//表示位置計算。
			{
				for(STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();t_it != t_it_end;++t_it){
					(*t_it)->CalcRect(0.0f,0.0f);
				}
			}

			//マウス更新。
			{
				GetSystemInstance()->callback->GetMouse_Callback(this->mouse.x,this->mouse.y,this->mouse.on_l,this->mouse.on_r,this->mouse.down_l,this->mouse.down_r,this->mouse.up_l,this->mouse.up_r);

				STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_begin = this->list.begin();
				STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.end();
				if(t_it_begin != t_it_end){
					for(;;){
						t_it--;
						bool t_ret = (*t_it)->System_MouseUpdate(this->mouse);
						if(t_ret == true){
							//範囲内。
							break;
						}else if(t_it == t_it_begin){
							break;
						}
					}
				}
			}

			//更新。
			{
				for(STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();t_it != t_it_end;++t_it){
					(*t_it)->System_Update();
				}
			}
		}
	}

	/** Draw
	*/
	void WindowMenu::Draw()
	{
		STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_end = this->list.end();
		for(STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();t_it != t_it_end;++t_it){
			(*t_it)->System_Draw();
		}
	}

	/** Add
	*/
	void WindowMenu::Add(const sharedptr<WindowMenu_Window_Base>& a_window)
	{
		this->list.push_back(a_window);
	}

	/** GetList
	*/
	STLList<sharedptr<WindowMenu_Window_Base>>::Type& WindowMenu::GetList()
	{
		return this->list;
	}

	/** GetMouse
	*/
	WindowMenu_Mouse& WindowMenu::GetMouse()
	{
		return this->mouse;
	}

	/** GetCallback
	*/
	sharedptr<WindowMenu_Callback_Base>& WindowMenu::GetCallback()
	{
		return this->callback;
	}

	/** システムの開始。
	*/
	void StartSystem(sharedptr<WindowMenu_Callback_Base>& a_callback)
	{
		s_windowmenu.reset(new WindowMenu(a_callback));
	}

	/** システムの終了。
	*/
	void EndSystem()
	{
		ASSERT(s_windowmenu.use_count() == 1);
		s_windowmenu.reset();
	}

	/** システムのインスタンス取得。
	*/
	sharedptr<WindowMenu>& GetSystemInstance()
	{
		return s_windowmenu;
	}
}}
#endif

<commit_msg>windowmenu<commit_after>

/**
 * Copyright (c) 2017 blueback
 * Released under the MIT License
 * https://github.com/bluebackblue/brownie/blob/master/LICENSE
 * http://bbbproject.sakura.ne.jp/wordpress/mitlicense
 * @brief デバッグメニュー。
*/

/** include
*/
#include <bsys_pch.h>

/** include
*/
#include "../types/types.h"

/** include
*/
#include "./windowmenu.h"

/** NBsys::NWindowMenu
*/
#if(BSYS_WINDOWMENU_ENABLE)
namespace NBsys{namespace NWindowMenu
{
	/** s_windowmenu
	*/
	sharedptr<WindowMenu> s_windowmenu;

	/** constructor
	*/
	WindowMenu::WindowMenu(sharedptr<WindowMenu_Callback_Base>& a_callback)
		:
		callback(a_callback)
	{
	}

	/** destructor
	*/
	WindowMenu::~WindowMenu()
	{
	}

	/** Update
	*/
	void WindowMenu::Update()
	{
		//削除リクエスト。
		{
			STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();
			while(t_it != this->list.end()){
				if((*t_it)->GetDeleteRequest() == true){
					t_it = this->list.erase(t_it);
				}else{
					t_it++;
				}
			}
		}

		{
			STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_end = this->list.end();
			STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_begin = this->list.begin();
			if(t_it_begin != t_it_end){

				//表示位置計算。
				{
					for(STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();t_it != t_it_end;++t_it){
						(*t_it)->CalcRect(0.0f,0.0f);
					}
				}

				//マウス更新。
				{
					GetSystemInstance()->callback->GetMouse_Callback(this->mouse.x,this->mouse.y,this->mouse.on_l,this->mouse.on_r,this->mouse.down_l,this->mouse.down_r,this->mouse.up_l,this->mouse.up_r);

					STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_movetolast = t_it_end;

					STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = t_it_end;

					for(;;){
						t_it--;
						bool t_ret = (*t_it)->System_MouseUpdate(this->mouse);
						if(t_ret == true){
							//範囲内。

							//最後尾へ移動。
							if(this->mouse.on_l || this->mouse.on_r){
								STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_last = t_it_end;
								t_it_last--;
								if(t_it != t_it_last){
									t_it_movetolast = t_it;
								}
							}

							break;
						}else if(t_it == t_it_begin){
							break;
						}
					}

					//最後尾へ移動。
					if(t_it_movetolast != t_it_end){
						sharedptr<WindowMenu_Window_Base> t_active = *t_it_movetolast;
						this->list.erase(t_it_movetolast);
						this->list.push_back(t_active);
					}
				}

				//更新。
				{
					for(STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();t_it != t_it_end;++t_it){
						(*t_it)->System_Update();
					}
				}
			}
		}
	}

	/** Draw
	*/
	void WindowMenu::Draw()
	{
		STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it_end = this->list.end();
		for(STLList<sharedptr<WindowMenu_Window_Base>>::iterator t_it = this->list.begin();t_it != t_it_end;++t_it){
			(*t_it)->System_Draw();
		}
	}

	/** Add
	*/
	void WindowMenu::Add(const sharedptr<WindowMenu_Window_Base>& a_window)
	{
		this->list.push_back(a_window);
	}

	/** GetList
	*/
	STLList<sharedptr<WindowMenu_Window_Base>>::Type& WindowMenu::GetList()
	{
		return this->list;
	}

	/** GetMouse
	*/
	WindowMenu_Mouse& WindowMenu::GetMouse()
	{
		return this->mouse;
	}

	/** GetCallback
	*/
	sharedptr<WindowMenu_Callback_Base>& WindowMenu::GetCallback()
	{
		return this->callback;
	}

	/** システムの開始。
	*/
	void StartSystem(sharedptr<WindowMenu_Callback_Base>& a_callback)
	{
		s_windowmenu.reset(new WindowMenu(a_callback));
	}

	/** システムの終了。
	*/
	void EndSystem()
	{
		ASSERT(s_windowmenu.use_count() == 1);
		s_windowmenu.reset();
	}

	/** システムのインスタンス取得。
	*/
	sharedptr<WindowMenu>& GetSystemInstance()
	{
		return s_windowmenu;
	}
}}
#endif

<|endoftext|>


<commit_before>#include "keilo_application.hpp"
#include "keilo_database.hpp"

#include <experimental/filesystem>
#include <sstream>
#include <fstream>
#include <mutex>
#include <exception>

std::string keilo_application::create_database(std::string _name)
{
	std::lock_guard<std::mutex> mutex_guard(m_mutex);

	for (const auto& database : m_databases) {
		if (database.get_name() == _name)
			return "Database that was named \"" + _name + "\" already exist in application.";
		//throw std::exception(("Database \"" + _name + "\" already exist in application.").c_str());
	}

	m_databases.push_back(keilo_database(_name));
	return "Successfully create database that was named \"" + _name + "\".";
}

keilo_database* keilo_application::select_database(std::string _name)
{
	std::lock_guard<std::mutex> mutex_guard(m_mutex);

	for (auto& database : m_databases)
	{
		if (database.get_name() != _name)
			continue;

		return &database;
	}

	return nullptr;
}

std::string keilo_application::import_file(std::string file_name)
{
	if (file_name.find(".klo") == std::string::npos)
		return "This program support only *.klo files.";
	//throw std::exception("This program support only *.klo files.");

	std::stringstream file_path;

	file_path << std::experimental::filesystem::current_path().generic_string() << "/database/" << file_name;

	if (std::ifstream file(file_path.str()); file) {
		m_databases.clear();
		m_mutex.lock();
		m_databases.push_back(keilo_database(file));
		m_mutex.unlock();

		return "Sucessfully impotred file that was named \"" + file_name + "\".";
	}
	else
		return "File that was named \"" + file_name + "\" does not exist.";
}

std::string keilo_application::export_database(std::string database_name, std::string file_name)
{
	auto database = select_database(database_name);
	try {
		std::stringstream file_path;

		file_path << std::experimental::filesystem::current_path().generic_string() << "/database/" << file_name;

		std::ofstream file(file_path.str());

		file << database->get_name() << std::endl;
		file << "[" << std::endl;
		for (auto table : database->get_tables())
		{
			file << "	" << table.get_name() << std::endl;
			file << "	{" << std::endl;
			for (const auto& record : table.get_records())
			{
				file << "		(" << std::endl;
				for (const auto& instance : record)
					file << "		" << instance.first << ":" << instance.second << ";" << std::endl;
				file << "		)" << std::endl;
			}
			file << "	}" << std::endl;
		}
		file << "]";

		file.flush();
		file.close();
	}
	catch (std::exception& e) {
		return e.what();
	}
	return "Successfully exported database that was named \"" + database_name + "\".";
}

std::list<keilo_database> keilo_application::get_databases()
{
	std::lock_guard<std::mutex> mutex_guard(m_mutex);
	return m_databases;
}
<commit_msg>오탈자<commit_after>#include "keilo_application.hpp"
#include "keilo_database.hpp"

#include <experimental/filesystem>
#include <sstream>
#include <fstream>
#include <mutex>
#include <exception>

std::string keilo_application::create_database(std::string _name)
{
	std::lock_guard<std::mutex> mutex_guard(m_mutex);

	for (const auto& database : m_databases) {
		if (database.get_name() == _name)
			return "Database that was named \"" + _name + "\" already exist in application.";
		//throw std::exception(("Database \"" + _name + "\" already exist in application.").c_str());
	}

	m_databases.push_back(keilo_database(_name));
	return "Successfully create database that was named \"" + _name + "\".";
}

keilo_database* keilo_application::select_database(std::string _name)
{
	std::lock_guard<std::mutex> mutex_guard(m_mutex);

	for (auto& database : m_databases)
	{
		if (database.get_name() != _name)
			continue;

		return &database;
	}

	return nullptr;
}

std::string keilo_application::import_file(std::string file_name)
{
	if (file_name.find(".klo") == std::string::npos)
		return "This program support only *.klo files.";
	//throw std::exception("This program support only *.klo files.");

	std::stringstream file_path;

	file_path << std::experimental::filesystem::current_path().generic_string() << "/database/" << file_name;

	if (std::ifstream file(file_path.str()); file) {
		m_databases.clear();
		m_mutex.lock();
		m_databases.push_back(keilo_database(file));
		m_mutex.unlock();

		return "Successfully impotred file that was named \"" + file_name + "\".";
	}
	else
		return "File that was named \"" + file_name + "\" does not exist.";
}

std::string keilo_application::export_database(std::string database_name, std::string file_name)
{
	auto database = select_database(database_name);
	try {
		std::stringstream file_path;

		file_path << std::experimental::filesystem::current_path().generic_string() << "/database/" << file_name;

		std::ofstream file(file_path.str());

		file << database->get_name() << std::endl;
		file << "[" << std::endl;
		for (auto table : database->get_tables())
		{
			file << "	" << table.get_name() << std::endl;
			file << "	{" << std::endl;
			for (const auto& record : table.get_records())
			{
				file << "		(" << std::endl;
				for (const auto& instance : record)
					file << "		" << instance.first << ":" << instance.second << ";" << std::endl;
				file << "		)" << std::endl;
			}
			file << "	}" << std::endl;
		}
		file << "]";

		file.flush();
		file.close();
	}
	catch (std::exception& e) {
		return e.what();
	}
	return "Successfully exported database that was named \"" + database_name + "\".";
}

std::list<keilo_database> keilo_application::get_databases()
{
	std::lock_guard<std::mutex> mutex_guard(m_mutex);
	return m_databases;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>

#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/test/chromedriver/logging.h"

namespace {

// Truncates the given string to 200 characters, adding an ellipsis if
// truncation was necessary.
void TruncateString(std::string* data) {
  const size_t kMaxLength = 200;
  if (data->length() > kMaxLength) {
    data->resize(kMaxLength);
    data->replace(kMaxLength - 3, 3, "...");
  }
}

// Truncates all strings contained in the given value.
void TruncateContainedStrings(base::Value* value) {
  base::ListValue* list = NULL;
  base::DictionaryValue* dict = NULL;
  if (value->GetAsDictionary(&dict)) {
    for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
         it.Advance()) {
      std::string data;
      if (it.value().GetAsString(&data)) {
        TruncateString(&data);
        dict->SetWithoutPathExpansion(it.key(), new base::StringValue(data));
      } else {
        base::Value* child = NULL;
        dict->GetWithoutPathExpansion(it.key(), &child);
        TruncateContainedStrings(child);
      }
    }
  } else if (value->GetAsList(&list)) {
    for (size_t i = 0; i < list->GetSize(); ++i) {
      base::Value* child = NULL;
      if (!list->Get(i, &child))
        continue;
      std::string data;
      if (child->GetAsString(&data)) {
        TruncateString(&data);
        list->Set(i, new base::StringValue(data));
      } else {
        TruncateContainedStrings(child);
      }
    }
  }
}

std::string ConvertForDisplayInternal(const std::string& input) {
  size_t left = input.find("{");
  size_t right = input.rfind("}");
  if (left == std::string::npos || right == std::string::npos)
    return input.substr(0, 10 << 10);

  scoped_ptr<base::Value> value(
      base::JSONReader::Read(input.substr(left, right - left + 1)));
  if (!value)
    return input.substr(0, 10 << 10);
  TruncateContainedStrings(value.get());
  std::string json;
  base::JSONWriter::WriteWithOptions(
      value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
  std::string display = input.substr(0, left) + json;
  if (input.length() > right)
    display += input.substr(right + 1);
  return display;
}

// Pretty prints encapsulated JSON and truncates long strings for display.
std::string ConvertForDisplay(const std::string& input) {
  std::string display = ConvertForDisplayInternal(input);
  char remove_chars[] = {'\r'};
  RemoveChars(display, remove_chars, &display);
  return display;
}

}  // namespace

void Log::AddEntry(Level level, const std::string& message) {
 AddEntryTimestamped(base::Time::Now(), level, message);
}

Logger::Logger() : min_log_level_(kLog), start_(base::Time::Now()) {}

Logger::Logger(Level min_log_level)
    : min_log_level_(min_log_level), start_(base::Time::Now()) {}

Logger::~Logger() {}

void Logger::AddEntryTimestamped(const base::Time& timestamp,
                                 Level level,
                                 const std::string& message) {
  if (level < min_log_level_)
    return;

  const char* level_name = "UNKNOWN";
  switch (level) {
    case kDebug:
      level_name = "DEBUG";
      break;
    case kLog:
      level_name = "INFO";
      break;
    case kWarning:
      level_name = "WARNING";
      break;
    case kError:
      level_name = "ERROR";
      break;
    default:
      break;
  }
  std::string entry =
      base::StringPrintf("[%.3lf][%s]: %s",
                         base::TimeDelta(timestamp - start_).InSecondsF(),
                         level_name,
                         ConvertForDisplay(message).c_str());
  const char* format = "%s\n";
  if (entry[entry.length() - 1] == '\n')
    format = "%s";
  fprintf(stderr, format, entry.c_str());
  fflush(stderr);
}
<commit_msg>[chromedriver] Fix stack-buffer-overflow error in mac_asan.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>

#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/test/chromedriver/logging.h"

namespace {

// Truncates the given string to 200 characters, adding an ellipsis if
// truncation was necessary.
void TruncateString(std::string* data) {
  const size_t kMaxLength = 200;
  if (data->length() > kMaxLength) {
    data->resize(kMaxLength);
    data->replace(kMaxLength - 3, 3, "...");
  }
}

// Truncates all strings contained in the given value.
void TruncateContainedStrings(base::Value* value) {
  base::ListValue* list = NULL;
  base::DictionaryValue* dict = NULL;
  if (value->GetAsDictionary(&dict)) {
    for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
         it.Advance()) {
      std::string data;
      if (it.value().GetAsString(&data)) {
        TruncateString(&data);
        dict->SetWithoutPathExpansion(it.key(), new base::StringValue(data));
      } else {
        base::Value* child = NULL;
        dict->GetWithoutPathExpansion(it.key(), &child);
        TruncateContainedStrings(child);
      }
    }
  } else if (value->GetAsList(&list)) {
    for (size_t i = 0; i < list->GetSize(); ++i) {
      base::Value* child = NULL;
      if (!list->Get(i, &child))
        continue;
      std::string data;
      if (child->GetAsString(&data)) {
        TruncateString(&data);
        list->Set(i, new base::StringValue(data));
      } else {
        TruncateContainedStrings(child);
      }
    }
  }
}

std::string ConvertForDisplayInternal(const std::string& input) {
  size_t left = input.find("{");
  size_t right = input.rfind("}");
  if (left == std::string::npos || right == std::string::npos)
    return input.substr(0, 10 << 10);

  scoped_ptr<base::Value> value(
      base::JSONReader::Read(input.substr(left, right - left + 1)));
  if (!value)
    return input.substr(0, 10 << 10);
  TruncateContainedStrings(value.get());
  std::string json;
  base::JSONWriter::WriteWithOptions(
      value.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
  std::string display = input.substr(0, left) + json;
  if (input.length() > right)
    display += input.substr(right + 1);
  return display;
}

// Pretty prints encapsulated JSON and truncates long strings for display.
std::string ConvertForDisplay(const std::string& input) {
  std::string display = ConvertForDisplayInternal(input);
  char remove_chars[] = {'\r', '\0'};
  RemoveChars(display, remove_chars, &display);
  return display;
}

}  // namespace

void Log::AddEntry(Level level, const std::string& message) {
 AddEntryTimestamped(base::Time::Now(), level, message);
}

Logger::Logger() : min_log_level_(kLog), start_(base::Time::Now()) {}

Logger::Logger(Level min_log_level)
    : min_log_level_(min_log_level), start_(base::Time::Now()) {}

Logger::~Logger() {}

void Logger::AddEntryTimestamped(const base::Time& timestamp,
                                 Level level,
                                 const std::string& message) {
  if (level < min_log_level_)
    return;

  const char* level_name = "UNKNOWN";
  switch (level) {
    case kDebug:
      level_name = "DEBUG";
      break;
    case kLog:
      level_name = "INFO";
      break;
    case kWarning:
      level_name = "WARNING";
      break;
    case kError:
      level_name = "ERROR";
      break;
    default:
      break;
  }
  std::string entry =
      base::StringPrintf("[%.3lf][%s]: %s",
                         base::TimeDelta(timestamp - start_).InSecondsF(),
                         level_name,
                         ConvertForDisplay(message).c_str());
  const char* format = "%s\n";
  if (entry[entry.length() - 1] == '\n')
    format = "%s";
  fprintf(stderr, format, entry.c_str());
  fflush(stderr);
}
<|endoftext|>