<commit_before>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_IO_HPP_INCLUDED
#define TORRENT_IO_HPP_INCLUDED

namespace libtorrent
{
	namespace detail
	{
		template <class T> struct type {};

		// reads an integer from a byte stream
		// in big endian byte order and converts
		// it to native endianess
		template <class T, class InIt>
		inline T read_impl(InIt& start, type<T>)
		{
			T ret = 0;
			for (int i = 0; i < (int)sizeof(T); ++i)
			{
				ret <<= 8;
				ret |= static_cast<unsigned char>(*start);
				++start;
			}
			return ret;
		}

		template <class T, class OutIt>
		inline void write_impl(T val, OutIt& start)
		{
			for (int i = (int)sizeof(T)-1; i >= 0; --i)
			{
				*start = static_cast<unsigned char>((val >> (i * 8)) & 0xff);
				++start;
			}
		}

		// -- adaptors

		template <class InIt>
		boost::int64_t read_int64(InIt& start)
		{ return read_impl(start, type<boost::int64_t>()); }

		template <class InIt>
		boost::uint64_t read_uint64(InIt& start)
		{ return read_impl(start, type<boost::uint64_t>()); }

		template <class InIt>
		boost::uint32_t read_uint32(InIt& start)
		{ return read_impl(start, type<boost::uint32_t>()); }

		template <class InIt>
		boost::int32_t read_int32(InIt& start)
		{ return read_impl(start, type<boost::int32_t>()); }

		template <class InIt>
		boost::int16_t read_int16(InIt& start)
		{ return read_impl(start, type<boost::int16_t>()); }

		template <class InIt>
		boost::uint16_t read_uint16(InIt& start)
		{ return read_impl(start, type<boost::uint16_t>()); }

		template <class InIt>
		boost::int8_t read_int8(InIt& start)
		{ return read_impl(start, type<boost::int8_t>()); }

		template <class InIt>
		boost::uint8_t read_uint8(InIt& start)
		{ return read_impl(start, type<boost::uint8_t>()); }

		template <class OutIt>
		void write_uint64(boost::uint64_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int64(boost::int64_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_uint32(boost::uint32_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int32(boost::int32_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_uint16(boost::uint16_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int16(boost::int16_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_uint8(boost::uint8_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int8(boost::int8_t val, OutIt& start)
		{ write_impl(val, start); }

	}
}

#endif // TORRENT_IO_HPP_INCLUDED
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_IO_HPP_INCLUDED
#define TORRENT_IO_HPP_INCLUDED

#include <boost/cstdint.hpp>

namespace libtorrent
{
	namespace detail
	{
		template <class T> struct type {};

		// reads an integer from a byte stream
		// in big endian byte order and converts
		// it to native endianess
		template <class T, class InIt>
		inline T read_impl(InIt& start, type<T>)
		{
			T ret = 0;
			for (int i = 0; i < (int)sizeof(T); ++i)
			{
				ret <<= 8;
				ret |= static_cast<unsigned char>(*start);
				++start;
			}
			return ret;
		}

		template <class T, class OutIt>
		inline void write_impl(T val, OutIt& start)
		{
			for (int i = (int)sizeof(T)-1; i >= 0; --i)
			{
				*start = static_cast<unsigned char>((val >> (i * 8)) & 0xff);
				++start;
			}
		}

		// -- adaptors

		template <class InIt>
		boost::int64_t read_int64(InIt& start)
		{ return read_impl(start, type<boost::int64_t>()); }

		template <class InIt>
		boost::uint64_t read_uint64(InIt& start)
		{ return read_impl(start, type<boost::uint64_t>()); }

		template <class InIt>
		boost::uint32_t read_uint32(InIt& start)
		{ return read_impl(start, type<boost::uint32_t>()); }

		template <class InIt>
		boost::int32_t read_int32(InIt& start)
		{ return read_impl(start, type<boost::int32_t>()); }

		template <class InIt>
		boost::int16_t read_int16(InIt& start)
		{ return read_impl(start, type<boost::int16_t>()); }

		template <class InIt>
		boost::uint16_t read_uint16(InIt& start)
		{ return read_impl(start, type<boost::uint16_t>()); }

		template <class InIt>
		boost::int8_t read_int8(InIt& start)
		{ return read_impl(start, type<boost::int8_t>()); }

		template <class InIt>
		boost::uint8_t read_uint8(InIt& start)
		{ return read_impl(start, type<boost::uint8_t>()); }

		template <class OutIt>
		void write_uint64(boost::uint64_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int64(boost::int64_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_uint32(boost::uint32_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int32(boost::int32_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_uint16(boost::uint16_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int16(boost::int16_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_uint8(boost::uint8_t val, OutIt& start)
		{ write_impl(val, start); }

		template <class OutIt>
		void write_int8(boost::int8_t val, OutIt& start)
		{ write_impl(val, start); }

	}
}

#endif // TORRENT_IO_HPP_INCLUDED
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

#ifndef _OCTREE_HPP_
#define _OCTREE_HPP_

#include <boost/format.hpp>
#include <boost/utility.hpp>
#include <vector>
#include <iostream>
#include <deque>

namespace mapnik {

   typedef uint8_t byte ;
   struct rgb
   {
         byte r;
         byte g;
         byte b;
         rgb(byte r_, byte b_, byte g_)
            : r(r_), g(g_), b(b_) {}
   };

   struct RGBPolicy
   {
         const static unsigned MAX_LEVELS = 6;
         inline static unsigned index_from_level(unsigned level, rgb const& c)
         {
            unsigned shift = (MAX_LEVELS + 1) - level;
            return (((c.r >> shift) & 1) << 2)
               | (((c.g >> shift) & 1) << 1)
               | ((c.b >> shift) & 1);
         }
   };

   template <typename T, typename InsertPolicy = RGBPolicy >
   class octree : private boost::noncopyable
   {
         struct node
         {
               node ()
                  :  reds(0),
                     greens(0),
                     blues(0),
                     count(0),
                     index(0)
               {
                  memset(&children_[0],0,sizeof(children_));
               }

               ~node ()
               {
                  for (unsigned i = 0;i < 8; ++i) {
                     if (children_[i] != 0) delete children_[i],children_[i]=0;
                  }
               }

               bool is_leaf() const { return count == 0; }
               node * children_[8];
               unsigned reds;
               unsigned greens;
               unsigned blues;
               unsigned count;
               uint8_t  index;
         };
         struct node_cmp
         {
               bool operator() ( const node * lhs,const node* rhs) const
               {
                  unsigned left_total=0;
                  unsigned right_total=0;
                  for (unsigned i=0; i<8;++i)
                  {
                     if (lhs->children_[i]) left_total+=lhs->children_[i]->count;
                     if (rhs->children_[i]) right_total+=rhs->children_[i]->count;
                  }
                  return left_total < right_total;
               }
         };

         std::deque<node*> reducible_[InsertPolicy::MAX_LEVELS];
         unsigned max_colors_;
         unsigned colors_;
         unsigned leaf_level_;

      public:
         explicit octree(unsigned max_colors=256)
            : max_colors_(max_colors),
              colors_(0),
              leaf_level_(InsertPolicy::MAX_LEVELS),
              root_(new node())
         {}

         ~octree() { delete root_;}

         void insert(T const& data)
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (true) {

               if ( cur_node->count > 0 || level == leaf_level_)
               {
                  cur_node->reds   += data.r;
                  cur_node->greens += data.g;
                  cur_node->blues  += data.b;
                  cur_node->count  += 1;
                  if (cur_node->count == 1) ++colors_;
                  //if (colors_ >= max_colors_ - 1)
                  //reduce();
                  break;
               }

               unsigned idx = InsertPolicy::index_from_level(level,data);
               if (cur_node->children_[idx] == 0) {
                  cur_node->children_[idx] = new node();
                  if (level < leaf_level_-1)
                  {
                     reducible_[level+1].push_back(cur_node->children_[idx]);
                  }
               }
               cur_node = cur_node->children_[idx];
               ++level;
            }
         }

         int quantize(rgb const& c) const
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (cur_node)
            {
               if (cur_node->count != 0) return cur_node->index;
               unsigned idx = InsertPolicy::index_from_level(level,c);
               cur_node = cur_node->children_[idx];
               ++level;
            }
            return -1;
         }

         void create_palette(std::vector<rgb> & palette)
         {
            reduce();
            palette.reserve(colors_);
            create_palette(palette, root_);
         }

         void reduce()
         {
            // sort reducible
            for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
            {
               std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
            }

            while ( colors_ >= max_colors_ - 1)
            {
               while (leaf_level_ >0  && reducible_[leaf_level_-1].size() == 0)
               {
                  --leaf_level_;
               }

               if (leaf_level_ < 1) continue;

               if ( reducible_[leaf_level_-1].size() == 0) return;

               typename std::deque<node*>::iterator pos = reducible_[leaf_level_-1].begin();
               node * cur_node = *pos;
               unsigned num_children = 0;
               for (unsigned idx=0; idx < 8; ++idx)
               {
                  if (cur_node->children_[idx] != 0)
                  {
                     ++num_children;
                     cur_node->reds   += cur_node->children_[idx]->reds;
                     cur_node->greens += cur_node->children_[idx]->greens;
                     cur_node->blues  += cur_node->children_[idx]->blues;
                     cur_node->count  += cur_node->children_[idx]->count;
                     delete cur_node->children_[idx], cur_node->children_[idx]=0;
                  }
               }

               reducible_[leaf_level_-1].erase(pos);
               if (num_children > 0 )
               {
                  colors_ -= (num_children - 1);
               }
            }
         }

         void create_palette(std::vector<rgb> & palette, node * itr) const
         {
            if (itr->count != 0)
            {
               unsigned count = itr->count;
               palette.push_back(rgb(uint8_t(itr->reds/float(count)),
                                     uint8_t(itr->greens/float(count)),
                                     uint8_t(itr->blues/float(count))));
               itr->index = palette.size() - 1;
            }
            for (unsigned i=0; i < 8 ;++i)
            {
               if (itr->children_[i] != 0)
                  create_palette(palette, itr->children_[i]);
            }
         }
      private:
         node * root_;
   };
} // namespace mapnik

#endif /* _OCTREE_HPP_ */
<commit_msg>+ mapnik_png256_reduce.patch (Marcin Rudowski)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

#ifndef _OCTREE_HPP_
#define _OCTREE_HPP_

#include <boost/format.hpp>
#include <boost/utility.hpp>
#include <vector>
#include <iostream>
#include <deque>

namespace mapnik {

   typedef uint8_t byte ;
   struct rgb
   {
         byte r;
         byte g;
         byte b;
         rgb(byte r_, byte b_, byte g_)
            : r(r_), g(g_), b(b_) {}
   };

   struct RGBPolicy
   {
         const static unsigned MAX_LEVELS = 6;
         inline static unsigned index_from_level(unsigned level, rgb const& c)
         {
            unsigned shift = (MAX_LEVELS + 1) - level;
            return (((c.r >> shift) & 1) << 2)
               | (((c.g >> shift) & 1) << 1)
               | ((c.b >> shift) & 1);
         }
   };

   template <typename T, typename InsertPolicy = RGBPolicy >
   class octree : private boost::noncopyable
   {
         struct node
         {
               node ()
                  :  reds(0),
                     greens(0),
                     blues(0),
                     count(0),
                     count2(0),
                     index(0)
               {
                  memset(&children_[0],0,sizeof(children_));
               }

               ~node ()
               {
                  for (unsigned i = 0;i < 8; ++i) {
                     if (children_[i] != 0) delete children_[i],children_[i]=0;
                  }
               }

               bool is_leaf() const { return count == 0; }
               node * children_[8];
               unsigned reds;
               unsigned greens;
               unsigned blues;
               unsigned count;
               unsigned count2;
               uint8_t  index;
         };
         struct node_cmp
         {
               bool operator() ( const node * lhs,const node* rhs) const
               {
                  return lhs->count2 < rhs->count2;
               }
         };

         std::deque<node*> reducible_[InsertPolicy::MAX_LEVELS];
         unsigned max_colors_;
         unsigned colors_;
         unsigned leaf_level_;

      public:
         explicit octree(unsigned max_colors=256)
            : max_colors_(max_colors),
              colors_(0),
              leaf_level_(InsertPolicy::MAX_LEVELS),
              root_(new node())
         {}

         ~octree() { delete root_;}

         void insert(T const& data)
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (true) {
               cur_node->count2++;

               if ( cur_node->count > 0 || level == leaf_level_)
               {
                  cur_node->reds   += data.r;
                  cur_node->greens += data.g;
                  cur_node->blues  += data.b;
                  cur_node->count  += 1;
                  if (cur_node->count == 1) ++colors_;
                  //if (colors_ >= max_colors_ - 1)
                  //reduce();
                  break;
               }

               unsigned idx = InsertPolicy::index_from_level(level,data);
               if (cur_node->children_[idx] == 0) {
                  cur_node->children_[idx] = new node();
                  if (level < leaf_level_-1)
                  {
                     reducible_[level+1].push_back(cur_node->children_[idx]);
                  }
               }
               cur_node = cur_node->children_[idx];
               ++level;
            }
         }

         int quantize(rgb const& c) const
         {
            unsigned level = 0;
            node * cur_node = root_;
            while (cur_node)
            {
               if (cur_node->count != 0) return cur_node->index;
               unsigned idx = InsertPolicy::index_from_level(level,c);
               cur_node = cur_node->children_[idx];
               ++level;
            }
            return -1;
         }

         void create_palette(std::vector<rgb> & palette)
         {
            reduce();
            palette.reserve(colors_);
            create_palette(palette, root_);
         }

         void reduce()
         {
            // sort reducible
            for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
            {
               std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
            }

            while ( colors_ >= max_colors_ - 1)
            {
               while (leaf_level_ >0  && reducible_[leaf_level_-1].size() == 0)
               {
                  --leaf_level_;
               }

               if (leaf_level_ < 1) continue;

               if ( reducible_[leaf_level_-1].size() == 0) return;

               typename std::deque<node*>::iterator pos = reducible_[leaf_level_-1].begin();
               node * cur_node = *pos;
               unsigned num_children = 0;
               for (unsigned idx=0; idx < 8; ++idx)
               {
                  if (cur_node->children_[idx] != 0)
                  {
                     ++num_children;
                     cur_node->reds   += cur_node->children_[idx]->reds;
                     cur_node->greens += cur_node->children_[idx]->greens;
                     cur_node->blues  += cur_node->children_[idx]->blues;
                     cur_node->count  += cur_node->children_[idx]->count;
                     delete cur_node->children_[idx], cur_node->children_[idx]=0;
                  }
               }

               reducible_[leaf_level_-1].erase(pos);
               if (num_children > 0 )
               {
                  colors_ -= (num_children - 1);
               }
            }
         }

         void create_palette(std::vector<rgb> & palette, node * itr) const
         {
            if (itr->count != 0)
            {
               unsigned count = itr->count;
               palette.push_back(rgb(uint8_t(itr->reds/float(count)),
                                     uint8_t(itr->greens/float(count)),
                                     uint8_t(itr->blues/float(count))));
               itr->index = palette.size() - 1;
            }
            for (unsigned i=0; i < 8 ;++i)
            {
               if (itr->children_[i] != 0)
                  create_palette(palette, itr->children_[i]);
            }
         }
      private:
         node * root_;
   };
} // namespace mapnik

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


<commit_before>#ifndef V_SMC_PARTICLE_HPP
#define V_SMC_PARTICLE_HPP

#include <algorithm>
#include <limits>
#include <cstddef>
#include <mkl_cblas.h>
#include <mkl_vml.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <boost/function.hpp>
#include <vDist/tool/buffer.hpp>
#include <vDist/tool/eblas.hpp>

namespace vSMC {

/// Resample scheme
enum ResampleScheme {MULTINOMIAL, RESIDUAL, STRATIFIED, SYSTEMATIC};

/// \brief Particle class
///
/// Particle class store the particle set and arrays of weights and log
/// weights. It provides access to particle values as well as weights. It
/// computes and manages resources for ESS, resampling, etc, tasks unique to
/// each iteration.
template <typename T>
class Particle
{
    public :

    /// \brief Particle does not have a default constructor
    ///
    /// \param N The number of particles
    /// \param copy A pointer to the function that can copy particle from one
    /// position to another position
    Particle (std::size_t N) :
        size_(N), value_(N), weight_(N), log_weight_(N), inc_weight_(N),
        replication_(N),
        ess_(0), resampled_(false), zconst_(0), estimate_zconst_(false) {}

    /// \brief Size of the particle set
    ///
    /// \return The number of particles
    std::size_t size () const
    {
        return size_;
    }

    /// \brief Read and write access to particle values
    ///
    /// \return A reference to the particle values, type (T &)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the reference.
    T &value ()
    {
        return value_;
    }

    /// \brief Read only access to particle values
    ///
    /// \return A const reference to the particle values, type (const T &)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the reference.
    const T &value () const
    {
        return value_;
    }

    /// \brief Read only access to the weights
    ///
    /// \return A const pointer to the weights, type (const double *)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the pointer.
    const double *get_weight_ptr () const
    {
        return weight_.get();
    }

    /// \brief Read only access to the log weights
    ///
    /// \return A const pointer to the log weights, type (const double *)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the pointer.
    const double *get_log_weight_ptr () const
    {
        return log_weight_.get();
    }

    /// \brief Set the log weights of the particle sets
    ///
    /// \param [in] new_weight New log weights
    void set_log_weight (const double *new_weight)
    {
        cblas_dcopy(size_, new_weight, 1, log_weight_, 1);
        set_weight();
    }

    /// \brief Add to the log weights of the particle sets
    ///
    /// \param [in] inc_weight Incremental log weights
    void add_log_weight (const double *inc_weight)
    {
        if (estimate_zconst_) {
            vdExp(size_, inc_weight, inc_weight_);
            zconst_ += std::log(
                    cblas_ddot(size_, weight_, 1, inc_weight_, 1));
        }

        vdAdd(size_, log_weight_, inc_weight, log_weight_);
        set_weight();
    }

    /// \brief The ESS (Effective Sample Size)
    ///
    /// \return The value of ESS for current particle set
    double get_ESS () const
    {
        return ess_;
    }

    /// \brief Get indicator of resampling
    ///
    /// \return A bool value, \b true if the this iteration was resampled
    bool get_resample () const
    {
        return resampled_;
    }

    /// \brief Set indicator of resampling
    ///
    /// \param resampled \b true if the this iteration was resampled
    void set_resample (bool resampled)
    {
        resampled_ = resampled;
    }

    /// \brief Perform resampling
    ///
    /// \param scheme The resampling scheme, see ResamplingScheme
    /// \param [in] rng A gsl rng object pointer
    void resample (ResampleScheme scheme, const gsl_rng *rng)
    {
        switch (scheme) {
            case MULTINOMIAL :
                resample_multinomial(rng);
                break;
            case RESIDUAL :
                resample_residual(rng);
                break;
            case STRATIFIED :
                resample_stratified(rng);
                break;
            case SYSTEMATIC :
                resample_systematic(rng);
                break;
            default :
                throw std::runtime_error(
                        "ERROR: vSMC::Particle::resample: "
                        "Unknown Resample Scheme");
        }
    }

    /// \brief Toggle whether or not record SMC normalizing constant
    ///
    /// \param estimate_zconst Start estimating normalzing constant if true.
    void set_estimate_zconst (bool estimate_zconst)
    {
        estimate_zconst_ = estimate_zconst;
    }

    /// \brief Get the value of SMC normalizing constant
    ///
    /// \return SMC normalizng constant estimate
    double get_estimate_zconst () const
    {
        return zconst_;
    }

    /// \brief Reset the value of SMC normalizing constant
    void reset_estimate_zconst ()
    {
        zconst_ = 0;
    }

    private :

    std::size_t size_;
    T value_;
    vDist::tool::Buffer<double> weight_;
    vDist::tool::Buffer<double> log_weight_;
    vDist::tool::Buffer<double> inc_weight_;
    vDist::tool::Buffer<unsigned> replication_;
    double ess_;
    bool resampled_;
    double zconst_;
    bool estimate_zconst_;

    void set_weight ()
    {
        double max_weight = -std::numeric_limits<double>::infinity();

        for (std::size_t i = 0; i != size_; ++i)
            max_weight = std::max(max_weight, log_weight_[i]);
        for (std::size_t i = 0; i != size_; ++i)
            log_weight_[i] -= max_weight;
        vdExp(size_, log_weight_, weight_);
        double sum = cblas_dasum(size_, weight_, 1);
        cblas_dscal(size_, 1 / sum, weight_, 1);
        ess_ = 1 / cblas_ddot(size_, weight_, 1, weight_, 1);
    }

    void resample_multinomial (const gsl_rng *rng)
    {
        gsl_ran_multinomial(rng, size_, size_, weight_, replication_);
        resample_do();
    }

    void resample_residual (const gsl_rng *rng)
    {
        /// \internal Reuse weight and log_weight.
        /// weight: act as the fractional part of N * weight.
        /// log_weight: act as the integral part of N * weight.
        /// They all will be reset to equal weights after resampling.
        /// So it is safe to modify them here.
        vDist::tool::dyatx(size_, size_, weight_, 1, log_weight_, 1);
        vdModf(size_, log_weight_, log_weight_, weight_);
        std::size_t size = size_;
        size -= cblas_dasum(size_, log_weight_, 1);
        gsl_ran_multinomial(rng, size_, size, weight_, replication_);
        for (std::size_t i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
        resample_do();
    }

    void resample_stratified (const gsl_rng *rng) {}
    void resample_systematic (const gsl_rng *rng) {}

    void resample_do ()
    {
        std::size_t from = 0;
        std::size_t time = 0;

        for (std::size_t to = 0; to != size_; ++to)
        {
            if (!replication_[to]) {
                // replication_[to] has zero child, copy from elsewhere
                if (replication_[from] - time <= 1) {
                    // only 1 child left on replication_[from]
                    time = 0;
                    do // move from to some position with at least 2 children
                        ++from;
                    while (replication_[from] < 2);
                }
                value_.copy(from, to);
                ++time;
            }
        }
        vDist::tool::dfill(size_, 1.0 / size_, weight_, 1);
        vDist::tool::dfill(size_, 0, log_weight_, 1);
        ess_ = size_;
    }
}; // class Particle

} // namespace vSMC

#endif // V_SMC_PARTICLE_HPP
<commit_msg>cleanup<commit_after>#ifndef V_SMC_PARTICLE_HPP
#define V_SMC_PARTICLE_HPP

#include <algorithm>
#include <limits>
#include <cstddef>
#include <mkl_cblas.h>
#include <mkl_vml.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <boost/function.hpp>
#include <vDist/tool/buffer.hpp>
#include <vDist/tool/eblas.hpp>

namespace vSMC {

/// Resample scheme
enum ResampleScheme {MULTINOMIAL, RESIDUAL, STRATIFIED, SYSTEMATIC};

/// \brief Particle class
///
/// Particle class store the particle set and arrays of weights and log
/// weights. It provides access to particle values as well as weights. It
/// computes and manages resources for ESS, resampling, etc, tasks unique to
/// each iteration.
template <typename T>
class Particle
{
    public :

    /// \brief Particle does not have a default constructor
    ///
    /// \param N The number of particles
    /// \param copy A pointer to the function that can copy particle from one
    /// position to another position
    Particle (std::size_t N) :
        size_(N), value_(N), weight_(N), log_weight_(N), inc_weight_(N),
        replication_(N),
        ess_(0), resampled_(false), zconst_(0), estimate_zconst_(false) {}

    /// \brief Size of the particle set
    ///
    /// \return The number of particles
    std::size_t size () const
    {
        return size_;
    }

    /// \brief Read and write access to particle values
    ///
    /// \return A reference to the particle values, type (T &)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the reference.
    T &value ()
    {
        return value_;
    }

    /// \brief Read only access to particle values
    ///
    /// \return A const reference to the particle values, type (const T &)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the reference.
    const T &value () const
    {
        return value_;
    }

    /// \brief Read only access to the weights
    ///
    /// \return A const pointer to the weights, type (const double *)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the pointer.
    const double *get_weight_ptr () const
    {
        return weight_.get();
    }

    /// \brief Read only access to the log weights
    ///
    /// \return A const pointer to the log weights, type (const double *)
    /// \note Any operations that change the state of the particle set (e.g.,
    /// setting log weights or resampling) may invalidate the pointer.
    const double *get_log_weight_ptr () const
    {
        return log_weight_.get();
    }

    /// \brief Set the log weights of the particle sets
    ///
    /// \param [in] new_weight New log weights
    void set_log_weight (const double *new_weight)
    {
        cblas_dcopy(size_, new_weight, 1, log_weight_, 1);
        set_weight();
    }

    /// \brief Add to the log weights of the particle sets
    ///
    /// \param [in] inc_weight Incremental log weights
    void add_log_weight (const double *inc_weight)
    {
        if (estimate_zconst_) {
            vdExp(size_, inc_weight, inc_weight_);
            zconst_ +=
                std::log(cblas_ddot(size_, weight_, 1, inc_weight_, 1));
        }

        vdAdd(size_, log_weight_, inc_weight, log_weight_);
        set_weight();
    }

    /// \brief The ESS (Effective Sample Size)
    ///
    /// \return The value of ESS for current particle set
    double get_ESS () const
    {
        return ess_;
    }

    /// \brief Get indicator of resampling
    ///
    /// \return A bool value, \b true if the this iteration was resampled
    bool get_resample () const
    {
        return resampled_;
    }

    /// \brief Set indicator of resampling
    ///
    /// \param resampled \b true if the this iteration was resampled
    void set_resample (bool resampled)
    {
        resampled_ = resampled;
    }

    /// \brief Perform resampling
    ///
    /// \param scheme The resampling scheme, see ResamplingScheme
    /// \param [in] rng A gsl rng object pointer
    void resample (ResampleScheme scheme, const gsl_rng *rng)
    {
        switch (scheme) {
            case MULTINOMIAL :
                resample_multinomial(rng);
                break;
            case RESIDUAL :
                resample_residual(rng);
                break;
            case STRATIFIED :
                resample_stratified(rng);
                break;
            case SYSTEMATIC :
                resample_systematic(rng);
                break;
            default :
                throw std::runtime_error(
                        "ERROR: vSMC::Particle::resample: "
                        "Unknown Resample Scheme");
        }
    }

    /// \brief Toggle whether or not record SMC normalizing constant
    ///
    /// \param estimate_zconst Start estimating normalzing constant if true.
    void set_estimate_zconst (bool estimate_zconst)
    {
        estimate_zconst_ = estimate_zconst;
    }

    /// \brief Get the value of SMC normalizing constant
    ///
    /// \return SMC normalizng constant estimate
    double get_estimate_zconst () const
    {
        return zconst_;
    }

    /// \brief Reset the value of SMC normalizing constant
    void reset_estimate_zconst ()
    {
        zconst_ = 0;
    }

    private :

    std::size_t size_;
    T value_;
    vDist::tool::Buffer<double> weight_;
    vDist::tool::Buffer<double> log_weight_;
    vDist::tool::Buffer<double> inc_weight_;
    vDist::tool::Buffer<unsigned> replication_;
    double ess_;
    bool resampled_;
    double zconst_;
    bool estimate_zconst_;

    void set_weight ()
    {
        double max_weight = -std::numeric_limits<double>::infinity();

        for (std::size_t i = 0; i != size_; ++i)
            max_weight = std::max(max_weight, log_weight_[i]);
        for (std::size_t i = 0; i != size_; ++i)
            log_weight_[i] -= max_weight;
        vdExp(size_, log_weight_, weight_);
        double sum = cblas_dasum(size_, weight_, 1);
        cblas_dscal(size_, 1 / sum, weight_, 1);
        ess_ = 1 / cblas_ddot(size_, weight_, 1, weight_, 1);
    }

    void resample_multinomial (const gsl_rng *rng)
    {
        gsl_ran_multinomial(rng, size_, size_, weight_, replication_);
        resample_do();
    }

    void resample_residual (const gsl_rng *rng)
    {
        /// \internal Reuse weight and log_weight.
        /// weight: act as the fractional part of N * weight.
        /// log_weight: act as the integral part of N * weight.
        /// They all will be reset to equal weights after resampling.
        /// So it is safe to modify them here.
        vDist::tool::dyatx(size_, size_, weight_, 1, log_weight_, 1);
        vdModf(size_, log_weight_, log_weight_, weight_);
        std::size_t size = size_;
        size -= cblas_dasum(size_, log_weight_, 1);
        gsl_ran_multinomial(rng, size_, size, weight_, replication_);
        for (std::size_t i = 0; i != size_; ++i)
            replication_[i] += log_weight_[i];
        resample_do();
    }

    void resample_stratified (const gsl_rng *rng) {}
    void resample_systematic (const gsl_rng *rng) {}

    void resample_do ()
    {
        std::size_t from = 0;
        std::size_t time = 0;

        for (std::size_t to = 0; to != size_; ++to)
        {
            if (!replication_[to]) {
                // replication_[to] has zero child, copy from elsewhere
                if (replication_[from] - time <= 1) {
                    // only 1 child left on replication_[from]
                    time = 0;
                    do // move from to some position with at least 2 children
                        ++from;
                    while (replication_[from] < 2);
                }
                value_.copy(from, to);
                ++time;
            }
        }
        vDist::tool::dfill(size_, 1.0 / size_, weight_, 1);
        vDist::tool::dfill(size_, 0, log_weight_, 1);
        ess_ = size_;
    }
}; // class Particle

} // namespace vSMC

#endif // V_SMC_PARTICLE_HPP
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/gpu/opencl_context.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>
#ifdef STAN_OPENCL
#include <stan/math/gpu/cholesky_decompose.hpp>
#include <stan/math/gpu/copy.hpp>
#endif

#include <cmath>

namespace stan {
namespace math {

/**
 * Return the lower-triangular Cholesky factor (i.e., matrix
 * square root) of the specified square, symmetric matrix.  The return
 * value \f$L\f$ will be a lower-traingular matrix such that the
 * original matrix \f$A\f$ is given by
 *
\f$A = L \times L^T\f$.
 * @param m Symmetrix matrix.
 * @return Square root of matrix.
 * @throw std::domain_error if m is not a symmetric matrix or
 *   if m is not positive definite (if m has more than 0 elements)
 */
template <typename T, typename std::enable_if_t<std::is_same<T, double>::value,
                                                T>* = nullptr>
inline Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> cholesky_decompose(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) {
  check_square("cholesky_decompose", "m", m);
  check_symmetric("cholesky_decompose", "m", m);
#ifdef STAN_OPENCL
  if (m.rows() >= opencl_context.tuning_opts().cholesky_size_worth_transfer) {
    matrix_gpu m_gpu(m);
    Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> m_chol(m.rows(), m.cols());
    m_gpu = cholesky_decompose(m_gpu);
    copy(m_chol, m_gpu);  // NOLINT
    return m_chol;
  } else {
    Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
    llt.compute(m);
    check_pos_definite("cholesky_decompose", "m", llt);
    return llt.matrixL();
  }
#else
  Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
  llt.compute(m);
  check_pos_definite("cholesky_decompose", "m", llt);
  return llt.matrixL();
#endif
}

/**
 * Return the lower-triangular Cholesky factor (i.e., matrix
 * square root) of the specified square, symmetric matrix.  The return
 * value \f$L\f$ will be a lower-traingular matrix such that the
 * original matrix \f$A\f$ is given by
 *
\f$A = L \times L^T\f$.
 * @param m Symmetrix matrix.
 * @return Square root of matrix.
 * @throw std::domain_error if m is not a symmetric matrix or
 *   if m is not positive definite (if m has more than 0 elements)
 */
template <typename T, typename std::enable_if_t<!std::is_same<T, double>::value,
                                                T>* = nullptr>
inline Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> cholesky_decompose(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) {
  check_square("cholesky_decompose", "m", m);
  check_symmetric("cholesky_decompose", "m", m);
  Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
  llt.compute(m);
  check_pos_definite("cholesky_decompose", "m", llt);
  return llt.matrixL();
}
}  // namespace math

}  // namespace stan
#endif
<commit_msg>Adds a note to one of the cholesky functions that explains the difference between the two templates<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/gpu/opencl_context.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>
#ifdef STAN_OPENCL
#include <stan/math/gpu/cholesky_decompose.hpp>
#include <stan/math/gpu/copy.hpp>
#endif

#include <cmath>

namespace stan {
namespace math {

/**
 * Return the lower-triangular Cholesky factor (i.e., matrix
 * square root) of the specified square, symmetric matrix.  The return
 * value \f$L\f$ will be a lower-traingular matrix such that the
 * original matrix \f$A\f$ is given by
 *
\f$A = L \times L^T\f$.
 * @param m Symmetrix matrix.
 * @return Square root of matrix.
 * @note Because OpenCL only works on doubles there are two
 * cholesky_decompose functions. One that works on doubles
 * (this one) and another that works on all other types.
 * @throw std::domain_error if m is not a symmetric matrix or
 *   if m is not positive definite (if m has more than 0 elements)
 */
template <typename T, typename std::enable_if_t<std::is_same<T, double>::value,
                                                T>* = nullptr>
inline Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> cholesky_decompose(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) {
  check_square("cholesky_decompose", "m", m);
  check_symmetric("cholesky_decompose", "m", m);
#ifdef STAN_OPENCL
  if (m.rows() >= opencl_context.tuning_opts().cholesky_size_worth_transfer) {
    matrix_gpu m_gpu(m);
    Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> m_chol(m.rows(), m.cols());
    m_gpu = cholesky_decompose(m_gpu);
    copy(m_chol, m_gpu);  // NOLINT
    return m_chol;
  } else {
    Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
    llt.compute(m);
    check_pos_definite("cholesky_decompose", "m", llt);
    return llt.matrixL();
  }
#else
  Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
  llt.compute(m);
  check_pos_definite("cholesky_decompose", "m", llt);
  return llt.matrixL();
#endif
}

/**
 * Return the lower-triangular Cholesky factor (i.e., matrix
 * square root) of the specified square, symmetric matrix.  The return
 * value \f$L\f$ will be a lower-traingular matrix such that the
 * original matrix \f$A\f$ is given by
 *
\f$A = L \times L^T\f$.
 * @param m Symmetrix matrix.
 * @return Square root of matrix.
 * @note Because OpenCL only works on doubles there are two
 * cholesky_decompose functions. One that works on doubles
 * and another that works on all other types (this one).
 * @throw std::domain_error if m is not a symmetric matrix or
 *   if m is not positive definite (if m has more than 0 elements)
 */
template <typename T, typename std::enable_if_t<!std::is_same<T, double>::value,
                                                T>* = nullptr>
inline Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> cholesky_decompose(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) {
  check_square("cholesky_decompose", "m", m);
  check_symmetric("cholesky_decompose", "m", m);
  Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
  llt.compute(m);
  check_pos_definite("cholesky_decompose", "m", llt);
  return llt.matrixL();
}
}  // namespace math

}  // namespace stan
#endif
<|endoftext|>


<commit_before>#include "gc/gc.hpp"

#include "builtin/compiledmethod.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/iseq.hpp"
#include "builtin/staticscope.hpp"
#include "builtin/symbol.hpp"
#include "builtin/tuple.hpp"
#include "builtin/string.hpp"
#include "builtin/lookuptable.hpp"
#include "builtin/call_unit.hpp"

#include "ffi.hpp"
#include "marshal.hpp"
#include "primitives.hpp"
#include "objectmemory.hpp"
#include "arguments.hpp"
#include "dispatch.hpp"
#include "call_frame.hpp"
#include "object_utils.hpp"
#include "vm/object_utils.hpp"
#include "configuration.hpp"

#include "inline_cache.hpp"
#include "bytecode_verification.hpp"
#include "instruments/timing.hpp"

#ifdef ENABLE_LLVM
#include "llvm/jit.hpp"
#include "llvm/jit_compiler.hpp"
#include "llvm/jit_runtime.hpp"
#endif

namespace rubinius {

  void CompiledMethod::init(STATE) {
    GO(cmethod).set(state->new_class("CompiledMethod", G(executable), G(rubinius)));
    G(cmethod)->set_object_type(state, CompiledMethodType);
    G(cmethod)->name(state, state->symbol("Rubinius::CompiledMethod"));
  }

  CompiledMethod* CompiledMethod::create(STATE) {
    CompiledMethod* cm = state->new_object<CompiledMethod>(G(cmethod));
    cm->local_count(state, Fixnum::from(0));
    cm->set_executor(CompiledMethod::default_executor);
    cm->backend_method_ = NULL;
    cm->inliners_ = NULL;
    cm->prim_index_ = -1;

#ifdef ENABLE_LLVM
    cm->jit_data_ = NULL;
#endif

    return cm;
  }

  CompiledMethod* CompiledMethod::dup_cm(STATE) {
    CompiledMethod* cm = CompiledMethod::create(state);
    cm->copy_object(state, this);

    cm->set_executor(CompiledMethod::default_executor);
    cm->jit_data_ = NULL;
    cm->backend_method_ = NULL;

    return cm;
  }

  int CompiledMethod::start_line(STATE) {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(state, 1))->to_native();
  }

  int CompiledMethod::start_line() {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(1))->to_native();
  }

  int CompiledMethod::line(STATE, int ip) {
    if(lines_->nil_p()) return -3;

    size_t fin = lines_->num_fields() - 2;
    for(size_t i = 0; i < fin; i += 2) {
      Fixnum* start_ip = as<Fixnum>(lines_->at(state, i));
      Fixnum* end_ip   = as<Fixnum>(lines_->at(state, i+2));

      if(start_ip->to_native() <= ip && end_ip->to_native() > ip) {
        return as<Fixnum>(lines_->at(state, i+1))->to_native();
      }
    }

    return as<Fixnum>(lines_->at(state, fin+1))->to_native();
  }

  VMMethod* CompiledMethod::internalize(STATE, const char** reason, int* ip) {
    if(!backend_method_) {
      {
        timer::Running<double, timer::milliseconds> tr(
            state->shared.stats.verification_time);

        BytecodeVerification bv(this);
        if(!bv.verify(state)) {
          if(reason) *reason = bv.failure_reason();
          if(ip) *ip = bv.failure_ip();
          std::cerr << "Error validating bytecode: " << bv.failure_reason() << "\n";
          return 0;
        }
      }

      VMMethod* vmm = NULL;
      vmm = new VMMethod(state, this);
      backend_method_ = vmm;

      resolve_primitive(state);
      return vmm;
    }

    return backend_method_;
  }

  Object* CompiledMethod::primitive_failed(STATE, CallFrame* call_frame,
                            Dispatch& msg, Arguments& args)
  {
    if(try_as<CompiledMethod>(msg.method)) {
      return VMMethod::execute(state, call_frame, msg, args);
    }

    // TODO fix me to raise an exception
    assert(0);
    return Qnil;
  }

  void CompiledMethod::specialize(STATE, TypeInfo* ti) {
    backend_method_->specialize(state, this, ti);
  }

  Object* CompiledMethod::default_executor(STATE, CallFrame* call_frame, Dispatch& msg,
                                           Arguments& args) {
    CompiledMethod* cm = as<CompiledMethod>(msg.method);
    const char* reason = 0;
    int ip = -1;

    if(!cm->internalize(state, &reason, &ip)) {
      Exception::bytecode_error(state, call_frame, cm, ip, reason);
      return 0;
    }

    // Refactor
    cm->backend_method_->find_super_instructions();
    return cm->execute(state, call_frame, msg, args);
  }

  void CompiledMethod::post_marshal(STATE) {
  }

  size_t CompiledMethod::number_of_locals() {
    return local_count_->to_native();
  }

  String* CompiledMethod::full_name(STATE) {
    return name_->to_str(state);
  }

  Object* CompiledMethod::set_breakpoint(STATE, Fixnum* ip, Object* bp) {
    int i = ip->to_native();
    if(backend_method_ == NULL) {
      if(!internalize(state)) return Primitives::failure();
    }
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    if(breakpoints_->nil_p()) {
      breakpoints(state, LookupTable::create(state));
    }

    breakpoints_->store(state, ip, bp);
    backend_method_->debugging = 1;
    backend_method_->run = VMMethod::debugger_interpreter;
    return ip;
  }

  Object* CompiledMethod::clear_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return ip;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    bool removed = false;
    if(!breakpoints_->nil_p()) {
      breakpoints_->remove(state, ip, &removed);

      // No more breakpoints, switch back to the normal interpreter
      if(breakpoints_->entries()->to_native() == 0) {
        backend_method_->debugging = 0;
        backend_method_->run = VMMethod::interpreter;
      }
    }

    return removed ? Qtrue : Qfalse;
  }

  Object* CompiledMethod::is_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return Qfalse;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();
    if(breakpoints_->nil_p()) return Qfalse;

    bool found = false;
    breakpoints_->fetch(state, ip, &found);

    if(found) return Qtrue;
    return Qfalse;
  }

  CompiledMethod* CompiledMethod::of_sender(STATE, CallFrame* calling_environment) {
    CallFrame* caller = static_cast<CallFrame*>(calling_environment->previous);
    if(caller) {
      if(caller->cm) {
        return caller->cm;
      }
    }

    return nil<CompiledMethod>();
  }

  void CompiledMethod::Info::mark(Object* obj, ObjectMark& mark) {
    auto_mark(obj, mark);

    mark_inliners(obj, mark);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;
    vmm->set_mark();

    Object* tmp;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->set_mark();
      cm->jit_data()->mark_all(cm, mark);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        tmp = mark.call(cache->module);
        if(tmp) {
          cache->module = (Module*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->method) {
        tmp = mark.call(cache->method);
        if(tmp) {
          cache->method = (Executable*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->klass_) {
        tmp = mark.call(cache->klass_);
        if(tmp) {
          cache->klass_ = (Class*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->call_unit_) {
        tmp = mark.call(cache->call_unit_);
        if(tmp) {
          cache->call_unit_ = (CallUnit*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) {
          tmp = mark.call(mod);
          if(tmp) {
            cache->seen_classes_[i].set_klass(force_as<Class>(tmp));
            mark.just_set(obj, tmp);
          }
        }
      }
    }

    for(IndirectLiterals::iterator i = vmm->indirect_literals().begin();
        i != vmm->indirect_literals().end();
        i++) {
      Object** ptr = (*i);
      if((tmp = mark.call(*ptr)) != NULL) {
        *ptr = tmp;
        mark.just_set(obj, tmp);
      }
    }
  }

  void CompiledMethod::Info::visit(Object* obj, ObjectVisitor& visit) {
    auto_visit(obj, visit);

    visit_inliners(obj, visit);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->visit_all(visit);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        visit.call(cache->module);
      }

      if(cache->method) {
        visit.call(cache->method);
      }

      if(cache->klass_) {
        visit.call(cache->klass_);
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) visit.call(mod);
      }
    }
  }

  void CompiledMethod::Info::show(STATE, Object* self, int level) {
    CompiledMethod* cm = as<CompiledMethod>(self);

    class_header(state, self);
    indent_attribute(++level, "file"); cm->file()->show(state, level);
    indent_attribute(level, "iseq"); cm->iseq()->show(state, level);
    indent_attribute(level, "lines"); cm->lines()->show_simple(state, level);
    indent_attribute(level, "literals"); cm->literals()->show_simple(state, level);
    indent_attribute(level, "local_count"); cm->local_count()->show(state, level);
    indent_attribute(level, "local_names"); cm->local_names()->show_simple(state, level);
    indent_attribute(level, "name"); cm->name()->show(state, level);
    indent_attribute(level, "required_args"); cm->required_args()->show(state, level);
    indent_attribute(level, "scope"); cm->scope()->show(state, level);
    indent_attribute(level, "splat"); cm->splat()->show(state, level);
    indent_attribute(level, "stack_size"); cm->stack_size()->show(state, level);
    indent_attribute(level, "total_args"); cm->total_args()->show(state, level);

#ifdef ENABLE_LLVM
    if(cm->backend_method_ && cm->backend_method_->jitted()) {
      llvm::outs() << "<LLVM>\n"
                   << *cm->backend_method_->llvm_function()
                   << "</LLVM>\n<MachineCode>\n";
      LLVMState::show_machine_code(
          cm->backend_method_->jitted_impl(),
          cm->backend_method_->jitted_bytes());
      llvm::outs() << "</MachineCode>\n";
    }
#endif

    close_body(level);
  }
}
<commit_msg>Improve the details the VM can show about a CompiledMethod<commit_after>#include "gc/gc.hpp"

#include "builtin/compiledmethod.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/iseq.hpp"
#include "builtin/staticscope.hpp"
#include "builtin/symbol.hpp"
#include "builtin/tuple.hpp"
#include "builtin/string.hpp"
#include "builtin/lookuptable.hpp"
#include "builtin/call_unit.hpp"

#include "ffi.hpp"
#include "marshal.hpp"
#include "primitives.hpp"
#include "objectmemory.hpp"
#include "arguments.hpp"
#include "dispatch.hpp"
#include "call_frame.hpp"
#include "object_utils.hpp"
#include "vm/object_utils.hpp"
#include "configuration.hpp"

#include "inline_cache.hpp"
#include "bytecode_verification.hpp"
#include "instruments/timing.hpp"

#ifdef ENABLE_LLVM
#include "llvm/jit.hpp"
#include "llvm/jit_compiler.hpp"
#include "llvm/jit_runtime.hpp"
#endif

namespace rubinius {

  void CompiledMethod::init(STATE) {
    GO(cmethod).set(state->new_class("CompiledMethod", G(executable), G(rubinius)));
    G(cmethod)->set_object_type(state, CompiledMethodType);
    G(cmethod)->name(state, state->symbol("Rubinius::CompiledMethod"));
  }

  CompiledMethod* CompiledMethod::create(STATE) {
    CompiledMethod* cm = state->new_object<CompiledMethod>(G(cmethod));
    cm->local_count(state, Fixnum::from(0));
    cm->set_executor(CompiledMethod::default_executor);
    cm->backend_method_ = NULL;
    cm->inliners_ = NULL;
    cm->prim_index_ = -1;

#ifdef ENABLE_LLVM
    cm->jit_data_ = NULL;
#endif

    return cm;
  }

  CompiledMethod* CompiledMethod::dup_cm(STATE) {
    CompiledMethod* cm = CompiledMethod::create(state);
    cm->copy_object(state, this);

    cm->set_executor(CompiledMethod::default_executor);
    cm->jit_data_ = NULL;
    cm->backend_method_ = NULL;

    return cm;
  }

  int CompiledMethod::start_line(STATE) {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(state, 1))->to_native();
  }

  int CompiledMethod::start_line() {
    if(lines_->nil_p()) return -1;
    if(lines_->num_fields() < 2) return -1;
    // This is fixed as one because entry 0 is always ip = 0 and
    // 1 is the first line
    return as<Fixnum>(lines_->at(1))->to_native();
  }

  int CompiledMethod::line(STATE, int ip) {
    if(lines_->nil_p()) return -3;

    size_t fin = lines_->num_fields() - 2;
    for(size_t i = 0; i < fin; i += 2) {
      Fixnum* start_ip = as<Fixnum>(lines_->at(state, i));
      Fixnum* end_ip   = as<Fixnum>(lines_->at(state, i+2));

      if(start_ip->to_native() <= ip && end_ip->to_native() > ip) {
        return as<Fixnum>(lines_->at(state, i+1))->to_native();
      }
    }

    return as<Fixnum>(lines_->at(state, fin+1))->to_native();
  }

  VMMethod* CompiledMethod::internalize(STATE, const char** reason, int* ip) {
    if(!backend_method_) {
      {
        timer::Running<double, timer::milliseconds> tr(
            state->shared.stats.verification_time);

        BytecodeVerification bv(this);
        if(!bv.verify(state)) {
          if(reason) *reason = bv.failure_reason();
          if(ip) *ip = bv.failure_ip();
          std::cerr << "Error validating bytecode: " << bv.failure_reason() << "\n";
          return 0;
        }
      }

      VMMethod* vmm = NULL;
      vmm = new VMMethod(state, this);
      backend_method_ = vmm;

      resolve_primitive(state);
      return vmm;
    }

    return backend_method_;
  }

  Object* CompiledMethod::primitive_failed(STATE, CallFrame* call_frame,
                            Dispatch& msg, Arguments& args)
  {
    if(try_as<CompiledMethod>(msg.method)) {
      return VMMethod::execute(state, call_frame, msg, args);
    }

    // TODO fix me to raise an exception
    assert(0);
    return Qnil;
  }

  void CompiledMethod::specialize(STATE, TypeInfo* ti) {
    backend_method_->specialize(state, this, ti);
  }

  Object* CompiledMethod::default_executor(STATE, CallFrame* call_frame, Dispatch& msg,
                                           Arguments& args) {
    CompiledMethod* cm = as<CompiledMethod>(msg.method);
    const char* reason = 0;
    int ip = -1;

    if(!cm->internalize(state, &reason, &ip)) {
      Exception::bytecode_error(state, call_frame, cm, ip, reason);
      return 0;
    }

    // Refactor
    cm->backend_method_->find_super_instructions();
    return cm->execute(state, call_frame, msg, args);
  }

  void CompiledMethod::post_marshal(STATE) {
  }

  size_t CompiledMethod::number_of_locals() {
    return local_count_->to_native();
  }

  String* CompiledMethod::full_name(STATE) {
    return name_->to_str(state);
  }

  Object* CompiledMethod::set_breakpoint(STATE, Fixnum* ip, Object* bp) {
    int i = ip->to_native();
    if(backend_method_ == NULL) {
      if(!internalize(state)) return Primitives::failure();
    }
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    if(breakpoints_->nil_p()) {
      breakpoints(state, LookupTable::create(state));
    }

    breakpoints_->store(state, ip, bp);
    backend_method_->debugging = 1;
    backend_method_->run = VMMethod::debugger_interpreter;
    return ip;
  }

  Object* CompiledMethod::clear_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return ip;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();

    bool removed = false;
    if(!breakpoints_->nil_p()) {
      breakpoints_->remove(state, ip, &removed);

      // No more breakpoints, switch back to the normal interpreter
      if(breakpoints_->entries()->to_native() == 0) {
        backend_method_->debugging = 0;
        backend_method_->run = VMMethod::interpreter;
      }
    }

    return removed ? Qtrue : Qfalse;
  }

  Object* CompiledMethod::is_breakpoint(STATE, Fixnum* ip) {
    int i = ip->to_native();
    if(backend_method_ == NULL) return Qfalse;
    if(!backend_method_->validate_ip(state, i)) return Primitives::failure();
    if(breakpoints_->nil_p()) return Qfalse;

    bool found = false;
    breakpoints_->fetch(state, ip, &found);

    if(found) return Qtrue;
    return Qfalse;
  }

  CompiledMethod* CompiledMethod::of_sender(STATE, CallFrame* calling_environment) {
    CallFrame* caller = static_cast<CallFrame*>(calling_environment->previous);
    if(caller) {
      if(caller->cm) {
        return caller->cm;
      }
    }

    return nil<CompiledMethod>();
  }

  void CompiledMethod::Info::mark(Object* obj, ObjectMark& mark) {
    auto_mark(obj, mark);

    mark_inliners(obj, mark);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;
    vmm->set_mark();

    Object* tmp;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->set_mark();
      cm->jit_data()->mark_all(cm, mark);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        tmp = mark.call(cache->module);
        if(tmp) {
          cache->module = (Module*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->method) {
        tmp = mark.call(cache->method);
        if(tmp) {
          cache->method = (Executable*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->klass_) {
        tmp = mark.call(cache->klass_);
        if(tmp) {
          cache->klass_ = (Class*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      if(cache->call_unit_) {
        tmp = mark.call(cache->call_unit_);
        if(tmp) {
          cache->call_unit_ = (CallUnit*)tmp;
          mark.just_set(obj, tmp);
        }
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) {
          tmp = mark.call(mod);
          if(tmp) {
            cache->seen_classes_[i].set_klass(force_as<Class>(tmp));
            mark.just_set(obj, tmp);
          }
        }
      }
    }

    for(IndirectLiterals::iterator i = vmm->indirect_literals().begin();
        i != vmm->indirect_literals().end();
        i++) {
      Object** ptr = (*i);
      if((tmp = mark.call(*ptr)) != NULL) {
        *ptr = tmp;
        mark.just_set(obj, tmp);
      }
    }
  }

  void CompiledMethod::Info::visit(Object* obj, ObjectVisitor& visit) {
    auto_visit(obj, visit);

    visit_inliners(obj, visit);

    CompiledMethod* cm = as<CompiledMethod>(obj);
    if(!cm->backend_method_) return;

    VMMethod* vmm = cm->backend_method_;

#ifdef ENABLE_LLVM
    if(cm->jit_data()) {
      cm->jit_data()->visit_all(visit);
    }
#endif

    for(size_t i = 0; i < vmm->inline_cache_count(); i++) {
      InlineCache* cache = &vmm->caches[i];

      if(cache->module) {
        visit.call(cache->module);
      }

      if(cache->method) {
        visit.call(cache->method);
      }

      if(cache->klass_) {
        visit.call(cache->klass_);
      }

      for(int i = 0; i < cTrackedICHits; i++) {
        Module* mod = cache->seen_classes_[i].klass();
        if(mod) visit.call(mod);
      }
    }
  }

  void CompiledMethod::Info::show(STATE, Object* self, int level) {
    CompiledMethod* cm = as<CompiledMethod>(self);

    class_header(state, self);
    indent_attribute(++level, "file"); cm->file()->show(state, level);
    indent_attribute(level, "iseq"); cm->iseq()->show(state, level);
    indent_attribute(level, "lines"); cm->lines()->show_simple(state, level);
    indent_attribute(level, "literals"); cm->literals()->show_simple(state, level);
    indent_attribute(level, "local_count"); cm->local_count()->show(state, level);
    indent_attribute(level, "local_names"); cm->local_names()->show_simple(state, level);
    indent_attribute(level, "name"); cm->name()->show(state, level);
    indent_attribute(level, "required_args"); cm->required_args()->show(state, level);
    indent_attribute(level, "scope"); cm->scope()->show(state, level);
    indent_attribute(level, "splat"); cm->splat()->show(state, level);
    indent_attribute(level, "stack_size"); cm->stack_size()->show(state, level);
    indent_attribute(level, "total_args"); cm->total_args()->show(state, level);

    indent_attribute(level, "internalized");
    if(!cm->backend_method_) {
      std::cout << "no\n";
    } else {
      std::cout << "yes\n";

#ifdef ENABLE_LLVM
      if(cm->backend_method_->llvm_function()) {
        llvm::outs() << "<LLVM>\n"
                     << *cm->backend_method_->llvm_function()
                     << "</LLVM>\n<MachineCode>\n";
        LLVMState::show_machine_code(
            cm->backend_method_->jitted_impl(),
            cm->backend_method_->jitted_bytes());
        llvm::outs() << "</MachineCode>\n";
      }
#endif
    }

    close_body(level);
  }
}
<|endoftext|>


<commit_before>#include <thread>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <functional>

#include "test.hpp"
#include "ping_pong.hpp"
#include "cppa/cppa.hpp"
#include "cppa/logging.hpp"
#include "cppa/exception.hpp"

using namespace std;
using namespace cppa;

namespace {

typedef std::pair<std::string, std::string> string_pair;

typedef vector<actor_ptr> actor_vector;

vector<string_pair> get_kv_pairs(int argc, char** argv, int begin = 1) {
    vector<string_pair> result;
    for (int i = begin; i < argc; ++i) {
        auto vec = split(argv[i], '=');
        auto eq_fun = [&](const string_pair& p) { return p.first == vec[0]; };
        if (vec.size() != 2) {
            CPPA_PRINTERR("\"" << argv[i] << "\" is not a key-value pair");
        }
        else if (any_of(result.begin(), result.end(), eq_fun)) {
            CPPA_PRINTERR("key \"" << vec[0] << "\" is already defined");
        }
        else {
            result.emplace_back(vec[0], vec[1]);
        }
    }
    return result;
}

struct reflector : public event_based_actor {
    void init() {
        become (
            others() >> [=] {
                reply_tuple(last_dequeued());
                quit();
            }
        );
    }
};

struct replier : public event_based_actor {
    void init() {
        become (
            others() >> [=] {
                reply(42);
                quit();
            }
        );
    }
};

// receive seven reply messages (2 local, 5 remote)
void spawn5_server(actor_ptr client, bool inverted) {
    auto default_case = others() >> CPPA_UNEXPECTED_MSG_CB();
    group_ptr grp;
    if (!inverted) {
        grp = group::get("local", "foobar");
    }
    else {
        send(client, atom("GetGroup"));
        receive (
            on_arg_match >> [&](const group_ptr& remote_group) {
                grp = remote_group;
            }
        );
    }
    spawn_in_group<reflector>(grp);
    spawn_in_group<reflector>(grp);
    receive_response (sync_send(client, atom("Spawn5"), grp)) (
        on(atom("ok"), arg_match) >> [&](const actor_vector& vec) {
            send(grp, "Hello reflectors!", 5.0);
            if (vec.size() != 5) {
                CPPA_PRINT("remote client did not spawn five reflectors!");
            }
            for (auto& a : vec) {
                self->monitor(a);
            }
        },
        default_case,
        after(chrono::seconds(10)) >> [&] {
            throw runtime_error("timeout");
        }
    );
    CPPA_PRINT("wait for reflected messages");
    // receive seven reply messages (2 local, 5 remote)
    int x = 0;
    receive_for(x, 7) (
        on("Hello reflectors!", 5.0) >> [] { }
    );
    CPPA_PRINT("wait for DOWN messages");
    // wait for DOWN messages
    {int i = 0; receive_for(i, 5) (
        on(atom("DOWN"), arg_match) >> [](std::uint32_t reason) {
            if (reason != exit_reason::normal) {
                CPPA_PRINT("reflector exited for non-normal exit reason!");
            }
        },
        default_case,
        after(chrono::seconds(2)) >> [&] {
            i = 4;
            CPPA_PRINTERR("timeout while waiting for DOWN messages!");
        }
    );}
    // wait for locally spawned reflectors
    await_all_others_done();
    send(client, atom("Spawn5Done"));
}

void spawn5_client() {
    bool spawned_reflectors = false;
    do_receive (
        on(atom("Spawn5"), arg_match) >> [&](const group_ptr& grp) {
            actor_vector vec;
            for (int i = 0; i < 5; ++i) {
                vec.push_back(spawn_in_group<reflector>(grp));
            }
            reply(atom("ok"), std::move(vec));
            spawned_reflectors = true;
        },
        on(atom("GetGroup")) >> [] {
            reply(group::get("local", "foobar"));
        }
    ).until(gref(spawned_reflectors));
    await_all_others_done();
    // wait for server
    receive (
        on(atom("Spawn5Done")) >> [] { }
    );
}

int client_part(const vector<string_pair>& args) {
    CPPA_TEST(test__remote_actor_client_part);
    auto i = find_if(args.begin(), args.end(),
                          [](const string_pair& p) { return p.first == "port"; });
    if (i == args.end()) {
        throw runtime_error("no port specified");
    }
    auto port = static_cast<uint16_t>(stoi(i->second));
    auto server = remote_actor("localhost", port);
    // remote_actor is supposed to return the same server when connecting to
    // the same host again
    for (int i = 0; i < 5; ++i) {
        auto server2 = remote_actor("localhost", port);
        CPPA_CHECK(server == server2);
    }
    send(server, atom("SpawnPing"));
    receive (
        on(atom("PingPtr"), arg_match) >> [](actor_ptr ping_actor) {
            spawn<detached>(pong, ping_actor);
        }
    );
    await_all_others_done();
    receive_response (sync_send(server, atom("SyncMsg"))) (
        others() >> [&] {
            if (self->last_dequeued() != make_cow_tuple(atom("SyncReply"))) {
                ostringstream oss;
                oss << "unexpected message; "
                    << __FILE__ << " line " << __LINE__ << ": "
                    << to_string(self->last_dequeued()) << endl;
                send(server, atom("Failure"), oss.str());
            }
            else {
                send(server, atom("Done"));
            }
        },
        after(chrono::seconds(5)) >> [&] {
            CPPA_PRINTERR("sync_send timed out!");
            send(server, atom("Timeout"));
        }
    );
    receive (
        others() >> [&] {
            CPPA_ERROR("unexpected message; "
                       << __FILE__ << " line " << __LINE__ << ": "
                       << to_string(self->last_dequeued()));
        },
        after(chrono::seconds(0)) >> [&] { }
    );
    // test 100 sync_messages
    for (int i = 0; i < 100; ++i) {
        receive_response (sync_send(server, atom("foo"), atom("bar"), i)) (
            on(atom("foo"), atom("bar"), i) >> [] {

            },
            others() >> [&] {
                CPPA_ERROR("unexpected message; "
                           << __FILE__ << " line " << __LINE__ << ": "
                           << to_string(self->last_dequeued()));
            },
            after(chrono::seconds(10)) >> [&] {
                CPPA_ERROR("unexpected timeout!");
            }
        );
    }
    spawn5_server(server, false);
    spawn5_client();
    // wait for locally spawned reflectors
    await_all_others_done();

    receive (
        on(atom("fwd"), arg_match) >> [&](const actor_ptr& fwd, const string&) {
            forward_to(fwd);
        }
    );

    send(server, atom("farewell"));
    shutdown();
    return CPPA_TEST_RESULT();
}

} // namespace <anonymous>

void verbose_terminate() {
    try { if (std::uncaught_exception()) throw; }
    catch (std::exception& e) {
        CPPA_PRINTERR("terminate called after throwing "
                      << to_verbose_string(e));
    }
    catch (...) {
        CPPA_PRINTERR("terminate called after throwing an unknown exception");
    }

    abort();
}

int main(int argc, char** argv) {
    set_terminate(verbose_terminate);
    announce<actor_vector>();
    cout.unsetf(ios_base::unitbuf);
    string app_path = argv[0];
    bool run_remote_actor = true;
    if (argc > 1) {
        if (strcmp(argv[1], "run_remote_actor=false") == 0) {
            run_remote_actor = false;
        }
        else {
            auto args = get_kv_pairs(argc, argv);
            return client_part(args);
        }
    }
    CPPA_TEST(test__remote_actor);
    CPPA_LOGF_TRACE("");
    //auto ping_actor = spawn(ping, 10);
    uint16_t port = 4242;
    bool success = false;
    do {
        try {
            publish(self, port, "127.0.0.1");
            success = true;
            CPPA_LOGF_DEBUG("running on port " << port);
        }
        catch (bind_failure&) {
            // try next port
            ++port;
        }
    }
    while (!success);
    thread child;
    ostringstream oss;
    if (run_remote_actor) {
        oss << app_path << " run=remote_actor port=" << port;// << " &>client.txt";
        // execute client_part() in a separate process,
        // connected via localhost socket
        child = thread([&oss]() {
            CPPA_LOGF_TRACE("lambda expression calling system()");
            string cmdstr = oss.str();
            if (system(cmdstr.c_str()) != 0) {
                CPPA_PRINTERR("FATAL: command \"" << cmdstr << "\" failed!");
                abort();
            }
        });
    }
    else {
        CPPA_PRINT("actor published at port " << port);
    }
    //CPPA_PRINT("await SpawnPing message");
    actor_ptr remote_client;
    CPPA_LOGF_DEBUG("send 'SpawnPing', expect 'PingPtr'");
    receive (
        on(atom("SpawnPing")) >> [&]() {
            remote_client = self->last_sender();
            CPPA_LOGF_ERROR_IF(!remote_client, "last_sender() == nullptr");
            CPPA_LOGF_DEBUG("spawn 10 event-based ping actors");
            reply(atom("PingPtr"), spawn_event_based_ping(10));
        }
    );
    CPPA_LOGF_DEBUG("wait until spawned ping actors are done");
    await_all_others_done();
    CPPA_CHECK_EQUAL(pongs(), 10);
    CPPA_PRINT("test remote sync_send");
    receive (
        on(atom("SyncMsg")) >> [] {
            reply(atom("SyncReply"));
        }
    );
    receive (
        on(atom("Done")) >> [] {
            // everything's fine
        },
        on(atom("Failure"), arg_match) >> [&](const string& str) {
            CPPA_ERROR(str);
        },
        on(atom("Timeout")) >> [&] {
            CPPA_ERROR("sync_send timed out");
        }
    );
    // test 100 sync messages
    CPPA_PRINT("test 100 synchronous messages");
    int i = 0;
    receive_for(i, 100) (
        others() >> [] {
            reply_tuple(self->last_dequeued());
        }
    );
    CPPA_PRINT("test group communication via network");
    // group test
    spawn5_client();
    CPPA_PRINT("test group communication via network (inverted setup)");
    spawn5_server(remote_client, true);

    self->on_sync_failure([&] {
        CPPA_ERROR("unexpected message: "
                   << to_string(self->last_dequeued())
                   << endl);
    });

    // test forward_to "over network and back"
    CPPA_PRINT("test forwarding over network 'and back'");
    auto ra = spawn<replier>();
    timed_sync_send(remote_client, chrono::seconds(5), atom("fwd"), ra, "hello replier!").await(
        [&](int forty_two) {
            CPPA_CHECK_EQUAL(forty_two, 42);
            auto from = self->last_sender();
            CPPA_CHECK_EQUAL(from, ra);
            if (from) CPPA_CHECK_EQUAL(from->is_proxy(), false);
        }
    );

    CPPA_PRINT("wait for a last goodbye");
    receive (
        on(atom("farewell")) >> [] { }
    );
    // wait until separate process (in sep. thread) finished execution
    if (run_remote_actor) child.join();
    shutdown();
    return CPPA_TEST_RESULT();
}
<commit_msg>added shutdown handshake to test_remote_actor<commit_after>#include <thread>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <functional>

#include "test.hpp"
#include "ping_pong.hpp"
#include "cppa/cppa.hpp"
#include "cppa/logging.hpp"
#include "cppa/exception.hpp"

using namespace std;
using namespace cppa;

namespace {

typedef std::pair<std::string, std::string> string_pair;

typedef vector<actor_ptr> actor_vector;

vector<string_pair> get_kv_pairs(int argc, char** argv, int begin = 1) {
    vector<string_pair> result;
    for (int i = begin; i < argc; ++i) {
        auto vec = split(argv[i], '=');
        auto eq_fun = [&](const string_pair& p) { return p.first == vec[0]; };
        if (vec.size() != 2) {
            CPPA_PRINTERR("\"" << argv[i] << "\" is not a key-value pair");
        }
        else if (any_of(result.begin(), result.end(), eq_fun)) {
            CPPA_PRINTERR("key \"" << vec[0] << "\" is already defined");
        }
        else {
            result.emplace_back(vec[0], vec[1]);
        }
    }
    return result;
}

struct reflector : public event_based_actor {
    void init() {
        become (
            others() >> [=] {
                reply_tuple(last_dequeued());
                quit();
            }
        );
    }
};

struct replier : public event_based_actor {
    void init() {
        become (
            others() >> [=] {
                reply(42);
                quit();
            }
        );
    }
};

// receive seven reply messages (2 local, 5 remote)
void spawn5_server(actor_ptr client, bool inverted) {
    auto default_case = others() >> CPPA_UNEXPECTED_MSG_CB();
    group_ptr grp;
    if (!inverted) {
        grp = group::get("local", "foobar");
    }
    else {
        send(client, atom("GetGroup"));
        receive (
            on_arg_match >> [&](const group_ptr& remote_group) {
                grp = remote_group;
            }
        );
    }
    spawn_in_group<reflector>(grp);
    spawn_in_group<reflector>(grp);
    receive_response (sync_send(client, atom("Spawn5"), grp)) (
        on(atom("ok"), arg_match) >> [&](const actor_vector& vec) {
            send(grp, "Hello reflectors!", 5.0);
            if (vec.size() != 5) {
                CPPA_PRINT("remote client did not spawn five reflectors!");
            }
            for (auto& a : vec) {
                self->monitor(a);
            }
        },
        default_case,
        after(chrono::seconds(10)) >> [&] {
            throw runtime_error("timeout");
        }
    );
    CPPA_PRINT("wait for reflected messages");
    // receive seven reply messages (2 local, 5 remote)
    int x = 0;
    receive_for(x, 7) (
        on("Hello reflectors!", 5.0) >> [] { }
    );
    CPPA_PRINT("wait for DOWN messages");
    // wait for DOWN messages
    {int i = 0; receive_for(i, 5) (
        on(atom("DOWN"), arg_match) >> [](std::uint32_t reason) {
            if (reason != exit_reason::normal) {
                CPPA_PRINT("reflector exited for non-normal exit reason!");
            }
        },
        default_case,
        after(chrono::seconds(2)) >> [&] {
            i = 4;
            CPPA_PRINTERR("timeout while waiting for DOWN messages!");
        }
    );}
    // wait for locally spawned reflectors
    await_all_others_done();
    send(client, atom("Spawn5Done"));
}

void spawn5_client() {
    bool spawned_reflectors = false;
    do_receive (
        on(atom("Spawn5"), arg_match) >> [&](const group_ptr& grp) {
            actor_vector vec;
            for (int i = 0; i < 5; ++i) {
                vec.push_back(spawn_in_group<reflector>(grp));
            }
            reply(atom("ok"), std::move(vec));
            spawned_reflectors = true;
        },
        on(atom("GetGroup")) >> [] {
            reply(group::get("local", "foobar"));
        }
    ).until(gref(spawned_reflectors));
    await_all_others_done();
    // wait for server
    receive (
        on(atom("Spawn5Done")) >> [] { }
    );
}

int client_part(const vector<string_pair>& args) {
    CPPA_TEST(test__remote_actor_client_part);
    auto i = find_if(args.begin(), args.end(),
                          [](const string_pair& p) { return p.first == "port"; });
    if (i == args.end()) {
        throw runtime_error("no port specified");
    }
    auto port = static_cast<uint16_t>(stoi(i->second));
    auto server = remote_actor("localhost", port);
    // remote_actor is supposed to return the same server when connecting to
    // the same host again
    for (int i = 0; i < 5; ++i) {
        auto server2 = remote_actor("localhost", port);
        CPPA_CHECK(server == server2);
    }
    send(server, atom("SpawnPing"));
    receive (
        on(atom("PingPtr"), arg_match) >> [](actor_ptr ping_actor) {
            spawn<detached>(pong, ping_actor);
        }
    );
    await_all_others_done();
    receive_response (sync_send(server, atom("SyncMsg"))) (
        others() >> [&] {
            if (self->last_dequeued() != make_cow_tuple(atom("SyncReply"))) {
                ostringstream oss;
                oss << "unexpected message; "
                    << __FILE__ << " line " << __LINE__ << ": "
                    << to_string(self->last_dequeued()) << endl;
                send(server, atom("Failure"), oss.str());
            }
            else {
                send(server, atom("Done"));
            }
        },
        after(chrono::seconds(5)) >> [&] {
            CPPA_PRINTERR("sync_send timed out!");
            send(server, atom("Timeout"));
        }
    );
    receive (
        others() >> [&] {
            CPPA_ERROR("unexpected message; "
                       << __FILE__ << " line " << __LINE__ << ": "
                       << to_string(self->last_dequeued()));
        },
        after(chrono::seconds(0)) >> [&] { }
    );
    // test 100 sync_messages
    for (int i = 0; i < 100; ++i) {
        receive_response (sync_send(server, atom("foo"), atom("bar"), i)) (
            on(atom("foo"), atom("bar"), i) >> [] {

            },
            others() >> [&] {
                CPPA_ERROR("unexpected message; "
                           << __FILE__ << " line " << __LINE__ << ": "
                           << to_string(self->last_dequeued()));
            },
            after(chrono::seconds(10)) >> [&] {
                CPPA_ERROR("unexpected timeout!");
            }
        );
    }
    spawn5_server(server, false);
    spawn5_client();
    // wait for locally spawned reflectors
    await_all_others_done();

    receive (
        on(atom("fwd"), arg_match) >> [&](const actor_ptr& fwd, const string&) {
            forward_to(fwd);
        }
    );
    // shutdown handshake
    send(server, atom("farewell"));
    receive(on(atom("cu")) >> [] { });
    shutdown();
    return CPPA_TEST_RESULT();
}

} // namespace <anonymous>

void verbose_terminate() {
    try { if (std::uncaught_exception()) throw; }
    catch (std::exception& e) {
        CPPA_PRINTERR("terminate called after throwing "
                      << to_verbose_string(e));
    }
    catch (...) {
        CPPA_PRINTERR("terminate called after throwing an unknown exception");
    }

    abort();
}

int main(int argc, char** argv) {
    set_terminate(verbose_terminate);
    announce<actor_vector>();
    cout.unsetf(ios_base::unitbuf);
    string app_path = argv[0];
    bool run_remote_actor = true;
    if (argc > 1) {
        if (strcmp(argv[1], "run_remote_actor=false") == 0) {
            run_remote_actor = false;
        }
        else {
            auto args = get_kv_pairs(argc, argv);
            return client_part(args);
        }
    }
    CPPA_TEST(test__remote_actor);
    CPPA_LOGF_TRACE("");
    //auto ping_actor = spawn(ping, 10);
    uint16_t port = 4242;
    bool success = false;
    do {
        try {
            publish(self, port, "127.0.0.1");
            success = true;
            CPPA_LOGF_DEBUG("running on port " << port);
        }
        catch (bind_failure&) {
            // try next port
            ++port;
        }
    }
    while (!success);
    thread child;
    ostringstream oss;
    if (run_remote_actor) {
        oss << app_path << " run=remote_actor port=" << port;// << " &>client.txt";
        // execute client_part() in a separate process,
        // connected via localhost socket
        child = thread([&oss]() {
            CPPA_LOGF_TRACE("lambda expression calling system()");
            string cmdstr = oss.str();
            if (system(cmdstr.c_str()) != 0) {
                CPPA_PRINTERR("FATAL: command \"" << cmdstr << "\" failed!");
                abort();
            }
        });
    }
    else {
        CPPA_PRINT("actor published at port " << port);
    }
    //CPPA_PRINT("await SpawnPing message");
    actor_ptr remote_client;
    CPPA_LOGF_DEBUG("send 'SpawnPing', expect 'PingPtr'");
    receive (
        on(atom("SpawnPing")) >> [&]() {
            remote_client = self->last_sender();
            CPPA_LOGF_ERROR_IF(!remote_client, "last_sender() == nullptr");
            CPPA_LOGF_DEBUG("spawn 10 event-based ping actors");
            reply(atom("PingPtr"), spawn_event_based_ping(10));
        }
    );
    CPPA_LOGF_DEBUG("wait until spawned ping actors are done");
    await_all_others_done();
    CPPA_CHECK_EQUAL(pongs(), 10);
    CPPA_PRINT("test remote sync_send");
    receive (
        on(atom("SyncMsg")) >> [] {
            reply(atom("SyncReply"));
        }
    );
    receive (
        on(atom("Done")) >> [] {
            // everything's fine
        },
        on(atom("Failure"), arg_match) >> [&](const string& str) {
            CPPA_ERROR(str);
        },
        on(atom("Timeout")) >> [&] {
            CPPA_ERROR("sync_send timed out");
        }
    );
    // test 100 sync messages
    CPPA_PRINT("test 100 synchronous messages");
    int i = 0;
    receive_for(i, 100) (
        others() >> [] {
            reply_tuple(self->last_dequeued());
        }
    );
    CPPA_PRINT("test group communication via network");
    // group test
    spawn5_client();
    CPPA_PRINT("test group communication via network (inverted setup)");
    spawn5_server(remote_client, true);

    self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB());

    // test forward_to "over network and back"
    CPPA_PRINT("test forwarding over network 'and back'");
    auto ra = spawn<replier>();
    timed_sync_send(remote_client, chrono::seconds(5), atom("fwd"), ra, "hello replier!").await(
        [&](int forty_two) {
            CPPA_CHECK_EQUAL(forty_two, 42);
            auto from = self->last_sender();
            CPPA_CHECK_EQUAL(from, ra);
            if (from) CPPA_CHECK_EQUAL(from->is_proxy(), false);
        }
    );

    CPPA_PRINT("wait for a last goodbye");
    receive(on(atom("farewell")) >> [&] {
        send(remote_client, atom("cu"));
        CPPA_CHECKPOINT();
    });
    // wait until separate process (in sep. thread) finished execution
    if (run_remote_actor) child.join();
    shutdown();
    return CPPA_TEST_RESULT();
}
<|endoftext|>