<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  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 copyright holder(s) 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 PCL_POINT_CLOUD_ITERATOR_HPP_
#define PCL_POINT_CLOUD_ITERATOR_HPP_

#include <pcl/cloud_iterator.h>

namespace pcl
{
  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class DefaultIterator : public CloudIterator<PointT>::Iterator
  {
    public:
      DefaultIterator (PointCloud<PointT>& cloud)
      : cloud_ (cloud)
      , iterator_ (cloud.begin ())
      {
      }

      ~DefaultIterator ()
      {
      }

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      PointT& operator* () const
      {
        return (*iterator_);
      }

      PointT* operator-> ()
      {
        return (&(*iterator_));
      }

      unsigned getCurrentPointIndex () const
      {
        return (iterator_ - cloud_.begin ());
      }

      unsigned getCurrentIndex () const
      {
        return (iterator_ - cloud_.begin ());
      }

      void reset ()
      {
        iterator_ = cloud_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != cloud_.end ());
      }
    private:
      PointCloud<PointT>& cloud_;
      typename PointCloud<PointT>::iterator iterator_;
  };

  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class IteratorIdx : public CloudIterator<PointT>::Iterator
  {
    public:
      IteratorIdx (PointCloud<PointT>& cloud, const std::vector<int>& indices)
        : cloud_ (cloud)
        , indices_ (indices)
        , iterator_ (indices_.begin ())
      {
      }

      IteratorIdx (PointCloud<PointT>& cloud, const PointIndices& indices)
        : cloud_ (cloud)
        , indices_ (indices.indices)
        , iterator_ (indices_.begin ())
      {
      }

      virtual ~IteratorIdx () {}

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      PointT& operator* () const
      {
        return (cloud_.points [*iterator_]);
      }

      PointT* operator-> ()
      {
        return (&(cloud_.points [*iterator_]));
      }

      unsigned getCurrentPointIndex () const
      {
        return (*iterator_);
      }

      unsigned getCurrentIndex () const
      {
        return (iterator_ - indices_.begin ());
      }

      void reset ()
      {
        iterator_ = indices_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != indices_.end ());
      }

      private:
        PointCloud<PointT>& cloud_;
        std::vector<int> indices_;
        std::vector<int>::iterator iterator_;
  };

  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class ConstCloudIterator<PointT>::DefaultConstIterator : public ConstCloudIterator<PointT>::Iterator
  {
    public:
      DefaultConstIterator (const PointCloud<PointT>& cloud)
        : cloud_ (cloud)
        , iterator_ (cloud.begin ())
      {
      }

      ~DefaultConstIterator ()
      {
      }

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      const PointT& operator* () const
      {
        return (*iterator_);
      }

      const PointT* operator-> () const
      {
        return (&(*iterator_));
      }

      unsigned getCurrentPointIndex () const
      {
        return (iterator_ - cloud_.begin ());
      }

      unsigned getCurrentIndex () const
      {
        return (iterator_ - cloud_.begin ());
      }

      void reset ()
      {
        iterator_ = cloud_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != cloud_.end ());
      }
    private:
      const PointCloud<PointT>& cloud_;
      typename PointCloud<PointT>::const_iterator iterator_;
  };

  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class ConstCloudIterator<PointT>::ConstIteratorIdx : public ConstCloudIterator<PointT>::Iterator
  {
    public:
      ConstIteratorIdx (const PointCloud<PointT>& cloud,
                        const std::vector<int>& indices)
        : cloud_ (cloud)
        , indices_ (indices)
        , iterator_ (indices_.begin ())
      {
      }

      ConstIteratorIdx (const PointCloud<PointT>& cloud,
                        const PointIndices& indices)
        : cloud_ (cloud)
        , indices_ (indices.indices)
        , iterator_ (indices_.begin ())
      {
      }

      virtual ~ConstIteratorIdx () {}

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      const PointT& operator* () const
      {
        return (cloud_.points[*iterator_]);
      }

      const PointT* operator-> () const
      {
        return (&(cloud_.points [*iterator_]));
      }

      unsigned getCurrentPointIndex () const
      {
        return (unsigned (*iterator_));
      }

      unsigned getCurrentIndex () const
      {
        return (unsigned (iterator_ - indices_.begin ()));
      }

      void reset ()
      {
        iterator_ = indices_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != indices_.end ());
      }

      private:
        const PointCloud<PointT>& cloud_;
        std::vector<int> indices_;
        std::vector<int>::iterator iterator_;
  };
} // namespace pcl

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (PointCloud<PointT>& cloud)
  : iterator_ (new DefaultIterator<PointT> (cloud))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (
    PointCloud<PointT>& cloud, const std::vector<int>& indices)
  : iterator_ (new IteratorIdx<PointT> (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (
    PointCloud<PointT>& cloud, const PointIndices& indices)
  : iterator_ (new IteratorIdx<PointT> (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (
    PointCloud<PointT>& cloud, const Correspondences& corrs, bool source)
{
  std::vector<int> indices;
  indices.reserve (corrs.size ());
  if (source)
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_query);
  }
  else
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_match);
  }
  iterator_ = new IteratorIdx<PointT> (cloud, indices);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::~CloudIterator ()
{
  delete iterator_;
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::CloudIterator<PointT>::operator ++ ()
{
  iterator_->operator++ ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::CloudIterator<PointT>::operator ++ (int)
{
  iterator_->operator++ (0);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> PointT&
pcl::CloudIterator<PointT>::operator* () const
{
  return (iterator_->operator * ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> PointT*
pcl::CloudIterator<PointT>::operator-> () const
{
  return (iterator_->operator-> ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::CloudIterator<PointT>::getCurrentPointIndex () const
{
  return (iterator_->getCurrentPointIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::CloudIterator<PointT>::getCurrentIndex () const
{
  return (iterator_->getCurrentIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::CloudIterator<PointT>::reset ()
{
  iterator_->reset ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> bool
pcl::CloudIterator<PointT>::isValid () const
{
  return (iterator_->isValid ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (const PointCloud<PointT>& cloud)
  : iterator_ (new typename pcl::ConstCloudIterator<PointT>::DefaultConstIterator (cloud))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (
    const PointCloud<PointT>& cloud, const std::vector<int>& indices)
  : iterator_ (new typename pcl::ConstCloudIterator<PointT>::ConstIteratorIdx (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (
    const PointCloud<PointT>& cloud, const PointIndices& indices)
  : iterator_ (new typename pcl::ConstCloudIterator<PointT>::ConstIteratorIdx (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (
    const PointCloud<PointT>& cloud, const Correspondences& corrs, bool source)
{
  std::vector<int> indices;
  indices.reserve (corrs.size ());
  if (source)
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_query);
  }
  else
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_match);
  }
  iterator_ = new typename pcl::ConstCloudIterator<PointT>::ConstIteratorIdx (cloud, indices);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::~ConstCloudIterator ()
{
  delete iterator_;
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::ConstCloudIterator<PointT>::operator ++ ()
{
  iterator_->operator++ ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::ConstCloudIterator<PointT>::operator ++ (int)
{
  iterator_->operator++ (0);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> const PointT&
pcl::ConstCloudIterator<PointT>::operator* () const
{
  return (iterator_->operator * ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> const PointT*
pcl::ConstCloudIterator<PointT>::operator-> () const
{
  return (iterator_->operator-> ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::ConstCloudIterator<PointT>::getCurrentPointIndex () const
{
  return (iterator_->getCurrentPointIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::ConstCloudIterator<PointT>::getCurrentIndex () const
{
  return (iterator_->getCurrentIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::ConstCloudIterator<PointT>::reset ()
{
  iterator_->reset ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> bool
pcl::ConstCloudIterator<PointT>::isValid () const
{
  return (iterator_->isValid ());
}

#endif    // PCL_POINT_CLOUD_ITERATOR_HPP_

<commit_msg>remove compiler warnings<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  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 copyright holder(s) 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 PCL_POINT_CLOUD_ITERATOR_HPP_
#define PCL_POINT_CLOUD_ITERATOR_HPP_

#include <pcl/cloud_iterator.h>

namespace pcl
{
  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class DefaultIterator : public CloudIterator<PointT>::Iterator
  {
    public:
      DefaultIterator (PointCloud<PointT>& cloud)
      : cloud_ (cloud)
      , iterator_ (cloud.begin ())
      {
      }

      ~DefaultIterator ()
      {
      }

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      PointT& operator* () const
      {
        return (*iterator_);
      }

      PointT* operator-> ()
      {
        return (&(*iterator_));
      }

      unsigned getCurrentPointIndex () const
      {
        return (iterator_ - cloud_.begin ());
      }

      unsigned getCurrentIndex () const
      {
        return (iterator_ - cloud_.begin ());
      }

      void reset ()
      {
        iterator_ = cloud_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != cloud_.end ());
      }
    private:
      PointCloud<PointT>& cloud_;
      typename PointCloud<PointT>::iterator iterator_;
  };

  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class IteratorIdx : public CloudIterator<PointT>::Iterator
  {
    public:
      IteratorIdx (PointCloud<PointT>& cloud, const std::vector<int>& indices)
        : cloud_ (cloud)
        , indices_ (indices)
        , iterator_ (indices_.begin ())
      {
      }

      IteratorIdx (PointCloud<PointT>& cloud, const PointIndices& indices)
        : cloud_ (cloud)
        , indices_ (indices.indices)
        , iterator_ (indices_.begin ())
      {
      }

      virtual ~IteratorIdx () {}

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      PointT& operator* () const
      {
        return (cloud_.points [*iterator_]);
      }

      PointT* operator-> ()
      {
        return (&(cloud_.points [*iterator_]));
      }

      unsigned getCurrentPointIndex () const
      {
        return (*iterator_);
      }

      unsigned getCurrentIndex () const
      {
        return (iterator_ - indices_.begin ());
      }

      void reset ()
      {
        iterator_ = indices_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != indices_.end ());
      }

      private:
        PointCloud<PointT>& cloud_;
        std::vector<int> indices_;
        std::vector<int>::iterator iterator_;
  };

  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class ConstCloudIterator<PointT>::DefaultConstIterator : public ConstCloudIterator<PointT>::Iterator
  {
    public:
      DefaultConstIterator (const PointCloud<PointT>& cloud)
        : cloud_ (cloud)
        , iterator_ (cloud.begin ())
      {
      }

      ~DefaultConstIterator ()
      {
      }

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      const PointT& operator* () const
      {
        return (*iterator_);
      }

      const PointT* operator-> () const
      {
        return (&(*iterator_));
      }

      unsigned getCurrentPointIndex () const
      {
        return (unsigned (iterator_ - cloud_.begin ()));
      }

      unsigned getCurrentIndex () const
      {
        return (unsigned (iterator_ - cloud_.begin ()));
      }

      void reset ()
      {
        iterator_ = cloud_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != cloud_.end ());
      }
    private:
      const PointCloud<PointT>& cloud_;
      typename PointCloud<PointT>::const_iterator iterator_;
  };

  /** \brief
    * \author Suat Gedikli
    */
  template <class PointT>
  class ConstCloudIterator<PointT>::ConstIteratorIdx : public ConstCloudIterator<PointT>::Iterator
  {
    public:
      ConstIteratorIdx (const PointCloud<PointT>& cloud,
                        const std::vector<int>& indices)
        : cloud_ (cloud)
        , indices_ (indices)
        , iterator_ (indices_.begin ())
      {
      }

      ConstIteratorIdx (const PointCloud<PointT>& cloud,
                        const PointIndices& indices)
        : cloud_ (cloud)
        , indices_ (indices.indices)
        , iterator_ (indices_.begin ())
      {
      }

      virtual ~ConstIteratorIdx () {}

      void operator ++ ()
      {
        ++iterator_;
      }

      void operator ++ (int)
      {
        iterator_++;
      }

      const PointT& operator* () const
      {
        return (cloud_.points[*iterator_]);
      }

      const PointT* operator-> () const
      {
        return (&(cloud_.points [*iterator_]));
      }

      unsigned getCurrentPointIndex () const
      {
        return (unsigned (*iterator_));
      }

      unsigned getCurrentIndex () const
      {
        return (unsigned (iterator_ - indices_.begin ()));
      }

      void reset ()
      {
        iterator_ = indices_.begin ();
      }

      bool isValid () const
      {
        return (iterator_ != indices_.end ());
      }

      private:
        const PointCloud<PointT>& cloud_;
        std::vector<int> indices_;
        std::vector<int>::iterator iterator_;
  };
} // namespace pcl

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (PointCloud<PointT>& cloud)
  : iterator_ (new DefaultIterator<PointT> (cloud))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (
    PointCloud<PointT>& cloud, const std::vector<int>& indices)
  : iterator_ (new IteratorIdx<PointT> (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (
    PointCloud<PointT>& cloud, const PointIndices& indices)
  : iterator_ (new IteratorIdx<PointT> (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::CloudIterator (
    PointCloud<PointT>& cloud, const Correspondences& corrs, bool source)
{
  std::vector<int> indices;
  indices.reserve (corrs.size ());
  if (source)
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_query);
  }
  else
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_match);
  }
  iterator_ = new IteratorIdx<PointT> (cloud, indices);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::CloudIterator<PointT>::~CloudIterator ()
{
  delete iterator_;
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::CloudIterator<PointT>::operator ++ ()
{
  iterator_->operator++ ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::CloudIterator<PointT>::operator ++ (int)
{
  iterator_->operator++ (0);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> PointT&
pcl::CloudIterator<PointT>::operator* () const
{
  return (iterator_->operator * ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> PointT*
pcl::CloudIterator<PointT>::operator-> () const
{
  return (iterator_->operator-> ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::CloudIterator<PointT>::getCurrentPointIndex () const
{
  return (iterator_->getCurrentPointIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::CloudIterator<PointT>::getCurrentIndex () const
{
  return (iterator_->getCurrentIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::CloudIterator<PointT>::reset ()
{
  iterator_->reset ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> bool
pcl::CloudIterator<PointT>::isValid () const
{
  return (iterator_->isValid ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (const PointCloud<PointT>& cloud)
  : iterator_ (new typename pcl::ConstCloudIterator<PointT>::DefaultConstIterator (cloud))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (
    const PointCloud<PointT>& cloud, const std::vector<int>& indices)
  : iterator_ (new typename pcl::ConstCloudIterator<PointT>::ConstIteratorIdx (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (
    const PointCloud<PointT>& cloud, const PointIndices& indices)
  : iterator_ (new typename pcl::ConstCloudIterator<PointT>::ConstIteratorIdx (cloud, indices))
{
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::ConstCloudIterator (
    const PointCloud<PointT>& cloud, const Correspondences& corrs, bool source)
{
  std::vector<int> indices;
  indices.reserve (corrs.size ());
  if (source)
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_query);
  }
  else
  {
    for (typename Correspondences::const_iterator indexIt = corrs.begin (); indexIt != corrs.end (); ++indexIt)
      indices.push_back (indexIt->index_match);
  }
  iterator_ = new typename pcl::ConstCloudIterator<PointT>::ConstIteratorIdx (cloud, indices);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT>
pcl::ConstCloudIterator<PointT>::~ConstCloudIterator ()
{
  delete iterator_;
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::ConstCloudIterator<PointT>::operator ++ ()
{
  iterator_->operator++ ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::ConstCloudIterator<PointT>::operator ++ (int)
{
  iterator_->operator++ (0);
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> const PointT&
pcl::ConstCloudIterator<PointT>::operator* () const
{
  return (iterator_->operator * ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> const PointT*
pcl::ConstCloudIterator<PointT>::operator-> () const
{
  return (iterator_->operator-> ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::ConstCloudIterator<PointT>::getCurrentPointIndex () const
{
  return (iterator_->getCurrentPointIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> unsigned
pcl::ConstCloudIterator<PointT>::getCurrentIndex () const
{
  return (iterator_->getCurrentIndex ());
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> void
pcl::ConstCloudIterator<PointT>::reset ()
{
  iterator_->reset ();
}

//////////////////////////////////////////////////////////////////////////////
template <class PointT> bool
pcl::ConstCloudIterator<PointT>::isValid () const
{
  return (iterator_->isValid ());
}

#endif    // PCL_POINT_CLOUD_ITERATOR_HPP_

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/common_audio/audio_ring_buffer.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_processing/channel_buffer.h"

namespace webrtc {

class AudioRingBufferTest :
    public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > {
};

void ReadAndWriteTest(const ChannelBuffer<float>& input,
                      size_t num_write_chunk_frames,
                      size_t num_read_chunk_frames,
                      size_t buffer_frames,
                      ChannelBuffer<float>* output) {
  const size_t num_channels = input.num_channels();
  const size_t total_frames = input.samples_per_channel();
  AudioRingBuffer buf(num_channels, buffer_frames);
  scoped_ptr<float*[]> slice(new float*[num_channels]);

  size_t input_pos = 0;
  size_t output_pos = 0;
  while (input_pos + buf.WriteFramesAvailable() < total_frames) {
    // Write until the buffer is as full as possible.
    while (buf.WriteFramesAvailable() >= num_write_chunk_frames) {
      buf.Write(input.Slice(slice.get(), static_cast<int>(input_pos)),
                num_channels, num_write_chunk_frames);
      input_pos += num_write_chunk_frames;
    }
    // Read until the buffer is as empty as possible.
    while (buf.ReadFramesAvailable() >= num_read_chunk_frames) {
      EXPECT_LT(output_pos, total_frames);
      buf.Read(output->Slice(slice.get(), static_cast<int>(output_pos)),
               num_channels, num_read_chunk_frames);
      output_pos += num_read_chunk_frames;
    }
  }

  // Write and read the last bit.
  if (input_pos < total_frames)
    buf.Write(input.Slice(slice.get(), static_cast<int>(input_pos)),
              num_channels, total_frames - input_pos);
  if (buf.ReadFramesAvailable())
    buf.Read(output->Slice(slice.get(), static_cast<int>(output_pos)),
             num_channels, buf.ReadFramesAvailable());
  EXPECT_EQ(0u, buf.ReadFramesAvailable());
}

TEST_P(AudioRingBufferTest, ReadDataMatchesWrittenData) {
  const size_t kFrames = 5000;
  const size_t num_channels = ::testing::get<3>(GetParam());

  // Initialize the input data to an increasing sequence.
  ChannelBuffer<float> input(kFrames, static_cast<int>(num_channels));
  for (size_t i = 0; i < num_channels; ++i)
    for (size_t j = 0; j < kFrames; ++j)
      input.channels()[i][j] = i * j;

  ChannelBuffer<float> output(kFrames, static_cast<int>(num_channels));
  ReadAndWriteTest(input,
                   ::testing::get<0>(GetParam()),
                   ::testing::get<1>(GetParam()),
                   ::testing::get<2>(GetParam()),
                   &output);

  // Verify the read data matches the input.
  for (size_t i = 0; i < num_channels; ++i)
    for (size_t j = 0; j < kFrames; ++j)
      EXPECT_EQ(input.channels()[i][j], output.channels()[i][j]);
}

INSTANTIATE_TEST_CASE_P(
    AudioRingBufferTest, AudioRingBufferTest,
    ::testing::Combine(::testing::Values(10, 20, 42),  // num_write_chunk_frames
                       ::testing::Values(1, 10, 17),   // num_read_chunk_frames
                       ::testing::Values(100, 256),    // buffer_frames
                       ::testing::Values(1, 4)));      // num_channels

TEST_F(AudioRingBufferTest, MoveReadPosition) {
  const size_t kNumChannels = 1;
  const float kInputArray[] = {1, 2, 3, 4};
  const size_t kNumFrames = sizeof(kInputArray) / sizeof(*kInputArray);
  ChannelBuffer<float> input(kInputArray, kNumFrames, kNumChannels);
  AudioRingBuffer buf(kNumChannels, kNumFrames);
  buf.Write(input.channels(), kNumChannels, kNumFrames);

  buf.MoveReadPosition(3);
  ChannelBuffer<float> output(1, kNumChannels);
  buf.Read(output.channels(), kNumChannels, 1);
  EXPECT_EQ(4, output.data()[0]);
  buf.MoveReadPosition(-3);
  buf.Read(output.channels(), kNumChannels, 1);
  EXPECT_EQ(2, output.data()[0]);
}

}  // namespace webrtc
<commit_msg>Use non-zero data in AudioRingBufferTest.<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/common_audio/audio_ring_buffer.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_processing/channel_buffer.h"

namespace webrtc {

class AudioRingBufferTest :
    public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > {
};

void ReadAndWriteTest(const ChannelBuffer<float>& input,
                      size_t num_write_chunk_frames,
                      size_t num_read_chunk_frames,
                      size_t buffer_frames,
                      ChannelBuffer<float>* output) {
  const size_t num_channels = input.num_channels();
  const size_t total_frames = input.samples_per_channel();
  AudioRingBuffer buf(num_channels, buffer_frames);
  scoped_ptr<float*[]> slice(new float*[num_channels]);

  size_t input_pos = 0;
  size_t output_pos = 0;
  while (input_pos + buf.WriteFramesAvailable() < total_frames) {
    // Write until the buffer is as full as possible.
    while (buf.WriteFramesAvailable() >= num_write_chunk_frames) {
      buf.Write(input.Slice(slice.get(), static_cast<int>(input_pos)),
                num_channels, num_write_chunk_frames);
      input_pos += num_write_chunk_frames;
    }
    // Read until the buffer is as empty as possible.
    while (buf.ReadFramesAvailable() >= num_read_chunk_frames) {
      EXPECT_LT(output_pos, total_frames);
      buf.Read(output->Slice(slice.get(), static_cast<int>(output_pos)),
               num_channels, num_read_chunk_frames);
      output_pos += num_read_chunk_frames;
    }
  }

  // Write and read the last bit.
  if (input_pos < total_frames)
    buf.Write(input.Slice(slice.get(), static_cast<int>(input_pos)),
              num_channels, total_frames - input_pos);
  if (buf.ReadFramesAvailable())
    buf.Read(output->Slice(slice.get(), static_cast<int>(output_pos)),
             num_channels, buf.ReadFramesAvailable());
  EXPECT_EQ(0u, buf.ReadFramesAvailable());
}

TEST_P(AudioRingBufferTest, ReadDataMatchesWrittenData) {
  const size_t kFrames = 5000;
  const size_t num_channels = ::testing::get<3>(GetParam());

  // Initialize the input data to an increasing sequence.
  ChannelBuffer<float> input(kFrames, static_cast<int>(num_channels));
  for (size_t i = 0; i < num_channels; ++i)
    for (size_t j = 0; j < kFrames; ++j)
      input.channels()[i][j] = (i + 1) * (j + 1);

  ChannelBuffer<float> output(kFrames, static_cast<int>(num_channels));
  ReadAndWriteTest(input,
                   ::testing::get<0>(GetParam()),
                   ::testing::get<1>(GetParam()),
                   ::testing::get<2>(GetParam()),
                   &output);

  // Verify the read data matches the input.
  for (size_t i = 0; i < num_channels; ++i)
    for (size_t j = 0; j < kFrames; ++j)
      EXPECT_EQ(input.channels()[i][j], output.channels()[i][j]);
}

INSTANTIATE_TEST_CASE_P(
    AudioRingBufferTest, AudioRingBufferTest,
    ::testing::Combine(::testing::Values(10, 20, 42),  // num_write_chunk_frames
                       ::testing::Values(1, 10, 17),   // num_read_chunk_frames
                       ::testing::Values(100, 256),    // buffer_frames
                       ::testing::Values(1, 4)));      // num_channels

TEST_F(AudioRingBufferTest, MoveReadPosition) {
  const size_t kNumChannels = 1;
  const float kInputArray[] = {1, 2, 3, 4};
  const size_t kNumFrames = sizeof(kInputArray) / sizeof(*kInputArray);
  ChannelBuffer<float> input(kInputArray, kNumFrames, kNumChannels);
  AudioRingBuffer buf(kNumChannels, kNumFrames);
  buf.Write(input.channels(), kNumChannels, kNumFrames);

  buf.MoveReadPosition(3);
  ChannelBuffer<float> output(1, kNumChannels);
  buf.Read(output.channels(), kNumChannels, 1);
  EXPECT_EQ(4, output.data()[0]);
  buf.MoveReadPosition(-3);
  buf.Read(output.channels(), kNumChannels, 1);
  EXPECT_EQ(2, output.data()[0]);
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/*
* Copyright (C) 2010,2011  Toni Gundogdu <legatvs@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#include <ctime>

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

#include <curl/curl.h>

#ifndef foreach
#define foreach BOOST_FOREACH
#endif

#include "cclive/application.h"
#include "cclive/get.h"
#include "cclive/error.h"
#include "cclive/log.h"
#include "cclive/wait.h"
#include "cclive/background.h"

namespace cclive
{

static boost::mt19937 _rng;

static void
rand_decor ()
{
  boost::uniform_int<> r(2,5);

  boost::variate_generator<boost::mt19937&, boost::uniform_int<> > v(_rng,r);

  const int n = v();

  for (int i=0; i<n; ++i) cclive::log << ".";
}

static void
handle_fetch (const quvi_word type, void*)
{
  rand_decor();
  if (type == QUVISTATUSTYPE_DONE)
    cclive::log << " ";
}

static void
handle_verify (const quvi_word type)
{
  rand_decor();
  if (type == QUVISTATUSTYPE_DONE)
    cclive::log << "done.\n";
}

static int
status_callback (long param, void *ptr)
{
  const quvi_word status = quvi_loword(param);
  const quvi_word type   = quvi_hiword(param);

  switch (status)
    {
    case QUVISTATUS_FETCH :
      handle_fetch (type,ptr);
      break;
    case QUVISTATUS_VERIFY:
      handle_verify(type);
      break;
    }

  cclive::log << std::flush;

  return QUVI_OK;
}

template<class Iterator>
static Iterator
make_unique (Iterator first, Iterator last)
{
  while (first != last)
    {
      Iterator next (first);
      last  = std::remove (++next, last, *first);
      first = next;
    }
  return last;
}

static void
print_retrying (
  const int retry,
  const int max_retries,
  const int retry_wait)
{
  if (retry > 0)
    {

      cclive::log
          << "Retrying "
          << retry
          << " of "
          << max_retries
          << " ... "
          << std::flush;

      cclive::wait (retry_wait);
    }
}

static void
print_checking (const int i, const int n)
{
  if (n > 1)  cclive::log << "(" << i << " of " << n << ") ";
  cclive::log << "Checking ... " << std::flush;
}

static void
print_quvi_error (const quvicpp::error& e)
{
  cclive::log << "libquvi: error: " << e.what() << std::endl;
}

static void
check_quvi_error (const quvicpp::error& e)
{
  const long resp_code = e.response_code ();

  if (resp_code >= 400 && resp_code <= 500)
    throw e;

  else
    {

      switch (e.quvi_code ())
        {

        case QUVI_CURL:
          print_quvi_error (e);
          break; // Retry.

        default:
          throw e;
        }

    }

}

static const char format_usage[] =
  "Usage:\n"
  "   --format arg            get format arg\n"
  "   --format list           list websites and supported formats\n"
  "   --format list arg       match arg to websites, list formats\n"
  "Examples:\n"
  "   --format webm_480p      get format webm_480p (youtube)\n"
  "   --format list youtube   list youtube formats\n"
  "   --format list dailym    list dailym(otion) formats";

static application::exit_status
print_format_help ()
{
  std::cout << format_usage << std::endl;
  return application::ok;
}

typedef std::map<std::string,std::string> map_ss;

static void
print_host (const map_ss::value_type& t)
{
  std::cout << t.first << ":\n  " << t.second << "\n";
}

static application::exit_status
handle_format_list (
  const boost::program_options::variables_map& map,
  const quvicpp::query& query)
{
  map_ss m = query.support ();

  // -f list <pattern>

  if (map.count ("url"))
    {

      const std::string arg0 =
        map["url"].as< std::vector<std::string> >()[0];

      foreach (map_ss::value_type& t, m)
      {
        if (t.first.find (arg0) != std::string::npos)
          print_host (t);
      }

    }

  // -f list

  else
    {
      foreach (map_ss::value_type& t, m)
      print_host (t);
    }

  return application::ok;
}

extern char LICENSE[]; // cclive/license.cpp

application::exit_status
application::exec (int argc, char **argv)
{
  try
    {
      _opts.exec(argc,argv);
    }

  catch (const std::exception& e)
    {
      std::clog << "error: " << e.what() << std::endl;
      return invalid_option;
    }

  const boost::program_options::variables_map map = _opts.map();

  // Dump and terminate options.

  if (map.count("help"))
    {
      std::cout << _opts << std::flush;
      return ok;
    }

  if (map.count("version"))
    {
      std::cout
          << "cclive version "
          << VERSION_LONG
          << "\n"
          << "libquvi version "
          << quvi_version (QUVI_VERSION_LONG)
          << std::endl;
      return ok;
    }

  if (map.count("license"))
    {
      std::cout << LICENSE << std::endl;
      return ok;
    }

  // --support

  quvicpp::query query; // Throws quvicpp::error caught in main.cpp

  if (map.count("support"))
    {
      std::cout << quvicpp::support_to_s (query.support ()) << std::flush;
      return ok;
    }

  // --format [<id> | [<help> | <list> [<pattern]]]

  const std::string format = map["format"].as<std::string>();

  if (format == "help")
    return print_format_help ();

  else if (format == "list")
    return handle_format_list (map, query);

  // Parse input.

  std::vector<std::string> input;

  if (map.count("url"))
    input = map["url"].as< std::vector<std::string> >();
  else
    _read_stdin (input);

  // Remove duplicates.

  input.erase (make_unique (input.begin(), input.end()), input.end());

  // Turn on libcurl verbose output.

  if (map.count("verbose-libcurl"))
    curl_easy_setopt (query.curlHandle(), CURLOPT_VERBOSE, 1L);

  // Set up quvicpp.

  _tweak_curl_opts(query,map);

  quvicpp::options qopts;
  qopts.statusfunc (status_callback);
  qopts.format     (format);
#ifdef _0
  qopts.verify     (map.count ("no-verify"));
#endif
  qopts.shortened  (map.count ("no-shortened"));

  // Seed random generator.

  _rng.seed ( static_cast<unsigned int>(std::time(0)) );

  // Omit flag.

  bool omit = map.count ("quiet");

  // Go to background.

#ifdef HAVE_FORK
  const bool background_given = map.count ("background");

  if (background_given)
    {

      // (Boost) Throws std::runtime_error if fails.

      cclive::go_background (map["log-file"].as<std::string>(), omit);
    }
#endif

  // Omit std output. Note that --background flips this above.

  cclive::log.push (cclive::omit_sink (omit));

#if defined (HAVE_FORK) && defined (HAVE_GETPID)
  if (background_given)
    {
      cclive::log
          << "Running in background (pid: "
          << static_cast<long>(getpid ())
          << ")."
          << std::endl;
    }
#endif

  // For each input URL.

  const size_t n = input.size();
  size_t i = 0;

  const int max_retries  = map["max-retries"].as<int>();
  const int retry_wait   = map["retry-wait"].as<int>();

  foreach(std::string url, input)
  {
    ++i;

    try
      {

        int retry = 0;

        while (retry <= max_retries)
          {

            print_retrying (retry, max_retries, retry_wait);

            ++retry;

            print_checking (i, n);

            quvicpp::video v;

            try
              {
                v = query.parse (url, qopts);
              }

            catch (const quvicpp::error& e)
              {
                check_quvi_error (e);
              }

            cclive::get (query, v, _opts);

            break; // Stop retrying.
          }
      }

    catch (const quvicpp::error& e)
      {
        print_quvi_error (e);
      }

    catch (const std::runtime_error& e)
      {
        cclive::log << "error: " << e.what() << std::endl;
      }
  }

  return ok;
}

void
application::_read_stdin (std::vector<std::string>& dst)
{
  std::string s;
  char ch = 0;

  while (std::cin.get(ch))
    s += ch;

  std::istringstream iss(s);
  std::copy(
    std::istream_iterator<std::string >(iss),
    std::istream_iterator<std::string >(),
    std::back_inserter<std::vector<std::string> >(dst)
  );
}

void
application::_tweak_curl_opts (
  const quvicpp::query& query,
  const boost::program_options::variables_map& map)
{
  CURL *curl = query.curlHandle();

  curl_easy_setopt(curl, CURLOPT_USERAGENT,
                   map["agent"].as<std::string>().c_str());

  if (map.count("verbose-curl"))
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

  if (map.count("proxy"))
    {
      curl_easy_setopt(curl, CURLOPT_PROXY,
                       map["proxy"].as<std::string>().c_str());
    }

  if (map.count("no-proxy"))
    curl_easy_setopt(curl, CURLOPT_PROXY, "");

  if (map.count("throttle"))
    {
      curl_off_t limit = map["throttle"].as<int>()*1024;
      curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, limit);
    }

  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,
                   map["connect-timeout"].as<int>());
}

} // End namespace.

// vim: set ts=2 sw=2 tw=72 expandtab:
<commit_msg>--format help: Use mp4_360p instead<commit_after>/*
* Copyright (C) 2010,2011  Toni Gundogdu <legatvs@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#include <ctime>

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

#include <curl/curl.h>

#ifndef foreach
#define foreach BOOST_FOREACH
#endif

#include "cclive/application.h"
#include "cclive/get.h"
#include "cclive/error.h"
#include "cclive/log.h"
#include "cclive/wait.h"
#include "cclive/background.h"

namespace cclive
{

static boost::mt19937 _rng;

static void
rand_decor ()
{
  boost::uniform_int<> r(2,5);

  boost::variate_generator<boost::mt19937&, boost::uniform_int<> > v(_rng,r);

  const int n = v();

  for (int i=0; i<n; ++i) cclive::log << ".";
}

static void
handle_fetch (const quvi_word type, void*)
{
  rand_decor();
  if (type == QUVISTATUSTYPE_DONE)
    cclive::log << " ";
}

static void
handle_verify (const quvi_word type)
{
  rand_decor();
  if (type == QUVISTATUSTYPE_DONE)
    cclive::log << "done.\n";
}

static int
status_callback (long param, void *ptr)
{
  const quvi_word status = quvi_loword(param);
  const quvi_word type   = quvi_hiword(param);

  switch (status)
    {
    case QUVISTATUS_FETCH :
      handle_fetch (type,ptr);
      break;
    case QUVISTATUS_VERIFY:
      handle_verify(type);
      break;
    }

  cclive::log << std::flush;

  return QUVI_OK;
}

template<class Iterator>
static Iterator
make_unique (Iterator first, Iterator last)
{
  while (first != last)
    {
      Iterator next (first);
      last  = std::remove (++next, last, *first);
      first = next;
    }
  return last;
}

static void
print_retrying (
  const int retry,
  const int max_retries,
  const int retry_wait)
{
  if (retry > 0)
    {

      cclive::log
          << "Retrying "
          << retry
          << " of "
          << max_retries
          << " ... "
          << std::flush;

      cclive::wait (retry_wait);
    }
}

static void
print_checking (const int i, const int n)
{
  if (n > 1)  cclive::log << "(" << i << " of " << n << ") ";
  cclive::log << "Checking ... " << std::flush;
}

static void
print_quvi_error (const quvicpp::error& e)
{
  cclive::log << "libquvi: error: " << e.what() << std::endl;
}

static void
check_quvi_error (const quvicpp::error& e)
{
  const long resp_code = e.response_code ();

  if (resp_code >= 400 && resp_code <= 500)
    throw e;

  else
    {

      switch (e.quvi_code ())
        {

        case QUVI_CURL:
          print_quvi_error (e);
          break; // Retry.

        default:
          throw e;
        }

    }

}

static const char format_usage[] =
  "Usage:\n"
  "   --format arg            get format arg\n"
  "   --format list           list websites and supported formats\n"
  "   --format list arg       match arg to websites, list formats\n"
  "Examples:\n"
  "   --format mp4_360p       get format mp4_360p (youtube)\n"
  "   --format list youtube   list youtube formats\n"
  "   --format list dailym    list dailym(otion) formats";

static application::exit_status
print_format_help ()
{
  std::cout << format_usage << std::endl;
  return application::ok;
}

typedef std::map<std::string,std::string> map_ss;

static void
print_host (const map_ss::value_type& t)
{
  std::cout << t.first << ":\n  " << t.second << "\n";
}

static application::exit_status
handle_format_list (
  const boost::program_options::variables_map& map,
  const quvicpp::query& query)
{
  map_ss m = query.support ();

  // -f list <pattern>

  if (map.count ("url"))
    {

      const std::string arg0 =
        map["url"].as< std::vector<std::string> >()[0];

      foreach (map_ss::value_type& t, m)
      {
        if (t.first.find (arg0) != std::string::npos)
          print_host (t);
      }

    }

  // -f list

  else
    {
      foreach (map_ss::value_type& t, m)
      print_host (t);
    }

  return application::ok;
}

extern char LICENSE[]; // cclive/license.cpp

application::exit_status
application::exec (int argc, char **argv)
{
  try
    {
      _opts.exec(argc,argv);
    }

  catch (const std::exception& e)
    {
      std::clog << "error: " << e.what() << std::endl;
      return invalid_option;
    }

  const boost::program_options::variables_map map = _opts.map();

  // Dump and terminate options.

  if (map.count("help"))
    {
      std::cout << _opts << std::flush;
      return ok;
    }

  if (map.count("version"))
    {
      std::cout
          << "cclive version "
          << VERSION_LONG
          << "\n"
          << "libquvi version "
          << quvi_version (QUVI_VERSION_LONG)
          << std::endl;
      return ok;
    }

  if (map.count("license"))
    {
      std::cout << LICENSE << std::endl;
      return ok;
    }

  // --support

  quvicpp::query query; // Throws quvicpp::error caught in main.cpp

  if (map.count("support"))
    {
      std::cout << quvicpp::support_to_s (query.support ()) << std::flush;
      return ok;
    }

  // --format [<id> | [<help> | <list> [<pattern]]]

  const std::string format = map["format"].as<std::string>();

  if (format == "help")
    return print_format_help ();

  else if (format == "list")
    return handle_format_list (map, query);

  // Parse input.

  std::vector<std::string> input;

  if (map.count("url"))
    input = map["url"].as< std::vector<std::string> >();
  else
    _read_stdin (input);

  // Remove duplicates.

  input.erase (make_unique (input.begin(), input.end()), input.end());

  // Turn on libcurl verbose output.

  if (map.count("verbose-libcurl"))
    curl_easy_setopt (query.curlHandle(), CURLOPT_VERBOSE, 1L);

  // Set up quvicpp.

  _tweak_curl_opts(query,map);

  quvicpp::options qopts;
  qopts.statusfunc (status_callback);
  qopts.format     (format);
#ifdef _0
  qopts.verify     (map.count ("no-verify"));
#endif
  qopts.shortened  (map.count ("no-shortened"));

  // Seed random generator.

  _rng.seed ( static_cast<unsigned int>(std::time(0)) );

  // Omit flag.

  bool omit = map.count ("quiet");

  // Go to background.

#ifdef HAVE_FORK
  const bool background_given = map.count ("background");

  if (background_given)
    {

      // (Boost) Throws std::runtime_error if fails.

      cclive::go_background (map["log-file"].as<std::string>(), omit);
    }
#endif

  // Omit std output. Note that --background flips this above.

  cclive::log.push (cclive::omit_sink (omit));

#if defined (HAVE_FORK) && defined (HAVE_GETPID)
  if (background_given)
    {
      cclive::log
          << "Running in background (pid: "
          << static_cast<long>(getpid ())
          << ")."
          << std::endl;
    }
#endif

  // For each input URL.

  const size_t n = input.size();
  size_t i = 0;

  const int max_retries  = map["max-retries"].as<int>();
  const int retry_wait   = map["retry-wait"].as<int>();

  foreach(std::string url, input)
  {
    ++i;

    try
      {

        int retry = 0;

        while (retry <= max_retries)
          {

            print_retrying (retry, max_retries, retry_wait);

            ++retry;

            print_checking (i, n);

            quvicpp::video v;

            try
              {
                v = query.parse (url, qopts);
              }

            catch (const quvicpp::error& e)
              {
                check_quvi_error (e);
              }

            cclive::get (query, v, _opts);

            break; // Stop retrying.
          }
      }

    catch (const quvicpp::error& e)
      {
        print_quvi_error (e);
      }

    catch (const std::runtime_error& e)
      {
        cclive::log << "error: " << e.what() << std::endl;
      }
  }

  return ok;
}

void
application::_read_stdin (std::vector<std::string>& dst)
{
  std::string s;
  char ch = 0;

  while (std::cin.get(ch))
    s += ch;

  std::istringstream iss(s);
  std::copy(
    std::istream_iterator<std::string >(iss),
    std::istream_iterator<std::string >(),
    std::back_inserter<std::vector<std::string> >(dst)
  );
}

void
application::_tweak_curl_opts (
  const quvicpp::query& query,
  const boost::program_options::variables_map& map)
{
  CURL *curl = query.curlHandle();

  curl_easy_setopt(curl, CURLOPT_USERAGENT,
                   map["agent"].as<std::string>().c_str());

  if (map.count("verbose-curl"))
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

  if (map.count("proxy"))
    {
      curl_easy_setopt(curl, CURLOPT_PROXY,
                       map["proxy"].as<std::string>().c_str());
    }

  if (map.count("no-proxy"))
    curl_easy_setopt(curl, CURLOPT_PROXY, "");

  if (map.count("throttle"))
    {
      curl_off_t limit = map["throttle"].as<int>()*1024;
      curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, limit);
    }

  curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT,
                   map["connect-timeout"].as<int>());
}

} // End namespace.

// vim: set ts=2 sw=2 tw=72 expandtab:
<|endoftext|>


<commit_before>/* The MIT License

Copyright (c) 2011 Sahab Yazdani

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "stippler_impl.h"

#include <fstream>
#include <limits>

#include <boost/random.hpp>

#include "VoronoiDiagramGenerator.h"

Stippler::Stippler( const StipplingParameters &parameters )
: IStippler(),
parameters(parameters),
displacement(std::numeric_limits<float>::max()),
vertsX(new float[parameters.points]), vertsY(new float[parameters.points]), radii(new float[parameters.points]),
image(parameters.inputFile) {
	createInitialDistribution();
}

Stippler::~Stippler() {
	delete[] radii;
	delete[] vertsX;
	delete[] vertsY;
}

void Stippler::distribute() {
	createVoronoiDiagram();
	redistributeStipples();
}

float Stippler::getAverageDisplacement() {
	return displacement;
}

void Stippler::createInitialDistribution() {
	using std::ceil;

	// find initial distribution
	boost::mt19937 rng;
	boost::uniform_01<boost::mt19937, float> generator( rng );

	float w = (float)(image.getWidth() - 1), h = (float)(image.getHeight() - 1);
	float xC, yC;

	for ( unsigned int i = 0; i < parameters.points; ) {
		xC = generator() * w;
		yC = generator() * h;

		// do a nearest neighbour search on the vertices
		if ( ceil(generator() * 255.0f) <= image.getIntensity( xC, yC ) ) {
			vertsX[i] = xC;
			vertsY[i] = yC;
			radii[i] = 0.0f;

			i++;
		}
	}
}

void Stippler::getStipples( StipplePoint *dst ) {
	StipplePoint *workingPtr;

	for (unsigned int i = 0; i < parameters.points; i++ ) {
		workingPtr = &(dst[i]);

		workingPtr->x = vertsX[i];
		workingPtr->y = vertsY[i];
		workingPtr->radius = radii[i];

		image.getColour(vertsX[i], vertsY[i], workingPtr->r, workingPtr->g, workingPtr->b);
	}
}

void Stippler::createVoronoiDiagram() {
	VoronoiDiagramGenerator generator;

	generator.generateVoronoi( vertsX, vertsY, parameters.points,
		0.0f, (float)(image.getWidth() - 1), 0.0f, (float)(image.getHeight() - 1), 0.0f/*::sqrt(8.0f) + 0.1f*/ );

	edges.clear();

	Point< float > p1, p2;
	Edge< float > edge;

	generator.resetIterator();
	while ( generator.getNext(
		edge.begin.x, edge.begin.y, edge.end.x, edge.end.y,
		p1.x, p1.y, p2.x, p2.y ) ) {

		if ( edge.begin == edge.end ) {
			continue;
		}

		if ( edges.find( p1 ) == edges.end() ) {
			edges[p1] = EdgeList();
		}
		if ( edges.find( p2 ) == edges.end() ) {
			edges[p2] = EdgeList();
		}
		edges[p1].push_back( edge );
		edges[p2].push_back( edge );
	}
}

void Stippler::redistributeStipples() {
	using std::pow;
	using std::sqrt;
	using std::pair;
	using std::make_pair;
	using std::vector;

	unsigned int j = 0;
	float distance, local_displacement;

	vector< pair< Point< float >, EdgeList > > vectorized;
	for ( EdgeMap::iterator key_iter = edges.begin(); key_iter != edges.end(); ++key_iter ) {
		vectorized.push_back(make_pair(key_iter->first, key_iter->second));
	}

	local_displacement = displacement = 0.0f;

	#pragma omp parallel for private(distance) reduction(+:local_displacement)
	for (int i = 0; i < (int)vectorized.size(); i++) {
		pair< Point< float >, EdgeList > item = vectorized[i];
		pair< Point<float>, float > centroid = calculateCellCentroid( item.first, item.second );

		distance = sqrt( pow( item.first.x - centroid.first.x, 2.0f ) + pow( item.first.y - centroid.first.y, 2.0f ) );

		radii[i] = centroid.second;
		vertsX[i] = centroid.first.x;
		vertsY[i] = centroid.first.y;

		local_displacement += distance;
	}

	displacement = local_displacement / vectorized.size(); // average out the displacement
}

inline Stippler::line Stippler::createClipLine( float insideX, float insideY, float x1, float y1, float x2, float y2 ) {
	using std::abs;
	using std::numeric_limits;

	Stippler::line l;

	// if the floating point version of the line collapsed down to one
	// point, then just ignore it all
	if (abs(x1 - x2) < numeric_limits<float>::epsilon() && abs(y1 - y2) < numeric_limits<float>::epsilon()) {
		l.a = .0f;
		l.b = .0f;
		l.c = .0f;

		return l;
	}

	l.a = -(y1 - y2);
	l.b = x1 - x2;
	l.c = (y1 - y2) * x1 - (x1 - x2) * y1;

	// make sure the known inside point falls on the correct side of the clipping plane
	if ( insideX * l.a + insideY * l.b + l.c > 0.0f ) {
		l.a *= -1;
		l.b *= -1;
		l.c *= -1;
	}

	return l;
}

std::pair< Point<float>, float > Stippler::calculateCellCentroid( Point<float> &inside, EdgeList &edgeList ) {
	using std::make_pair;
	using std::numeric_limits;
	using std::vector;
	using std::floor;
	using std::ceil;
	using std::abs;
	using std::sqrt;
	using std::pow;

	vector<line> clipLines;
	extents extent = getCellExtents(edgeList);

	unsigned int x, y;

	float xDiff = ( extent.maxX - extent.minX );
	float yDiff = ( extent.maxY - extent.minY );

	unsigned int tileWidth = (unsigned int)ceil(xDiff) * parameters.subpixels;
	unsigned int tileHeight = (unsigned int)ceil(yDiff) * parameters.subpixels;

	float xStep = xDiff / (float)tileWidth;
	float yStep = yDiff / (float)tileHeight;

	float spotDensity, areaDensity = 0.0f, maxAreaDensity = 0.0f;
	float xSum = 0.0f;
	float ySum = 0.0f;

	float xCurrent;
	float yCurrent;

	// compute the clip lines
	for ( EdgeList::iterator value_iter = edgeList.begin(); value_iter != edgeList.end(); ++value_iter ) {
		line l = createClipLine( inside.x, inside.y,
			value_iter->begin.x, value_iter->begin.y,
			value_iter->end.x, value_iter->end.y );

		if (l.a < numeric_limits<float>::epsilon() && abs(l.b) < numeric_limits<float>::epsilon()) {
			continue;
		}

		clipLines.push_back(l);
	}

	for ( y = 0, yCurrent = extent.minY; y < tileHeight; ++y, yCurrent += yStep ) {
		for ( x = 0, xCurrent = extent.minX; x < tileWidth; ++x, xCurrent += xStep ) {
			// a point is outside of the polygon if it is outside of all clipping planes
			bool outside = false;
			for ( vector<line>::iterator iter = clipLines.begin(); iter != clipLines.end(); iter++ ) {
				if ( xCurrent * iter->a + yCurrent * iter->b + iter->c >= 0.0f ) {
					outside = true;
					break;
				}
			}

			if (!outside) {
				spotDensity = image.getIntensity(xCurrent, yCurrent);

				areaDensity += spotDensity;
				maxAreaDensity += 255.0f;
				xSum += spotDensity * xCurrent;
				ySum += spotDensity * yCurrent;
			}
		}
	}

	float area = areaDensity * xStep * yStep / 255.0f;
	float maxArea = maxAreaDensity * xStep * yStep / 255.0f;

	Point<float> pt;
	if (areaDensity > numeric_limits<float>::epsilon()) {
		pt.x = xSum / areaDensity;
		pt.y = ySum / areaDensity;
	} else {
		// if for some reason, the cell is completely white, then the centroid does not move
		pt.x = inside.x;
		pt.y = inside.y;
	}

	float closest = numeric_limits<float>::max(),
		  farthest = numeric_limits<float>::min(),
		  distance;
	float x0 = pt.x, y0 = pt.y,
	      x1, x2, y1, y2;

	for ( EdgeList::iterator value_iter = edgeList.begin(); value_iter != edgeList.end(); ++value_iter ) {
		x1 = value_iter->begin.x; x2 = value_iter->end.x;
		y1 = value_iter->begin.y; y2 = value_iter->end.y;

		distance = abs( ( x2 - x1 ) * ( y1 - y0 ) - ( x1 - x0 ) * ( y2 - y1 ) ) / sqrt( pow( x2 - x1, 2.0f ) + pow( y2 - y1, 2.0f ) );
		if ( closest > distance ) {
			closest = distance;
		}
		if ( farthest < distance ) {
			farthest = distance;
		}
	}

	float radius;
	if ( parameters.noOverlap ) {
		radius = closest;
	} else {
		radius = farthest;
	}
	radius *= area / maxArea;

	return make_pair( pt, radius );
}

Stippler::extents Stippler::getCellExtents( Stippler::EdgeList &edgeList ) {
	using std::numeric_limits;

	extents extent;

	extent.minX = extent.minY = numeric_limits<float>::max();
	extent.maxX = extent.maxY = numeric_limits<float>::min();

	for ( EdgeList::iterator value_iter = edgeList.begin(); value_iter != edgeList.end(); ++value_iter ) {
		if ( value_iter->begin.x < extent.minX ) extent.minX = value_iter->begin.x;
		if ( value_iter->end.x < extent.minX ) extent.minX = value_iter->end.x;
		if ( value_iter->begin.y < extent.minY ) extent.minY = value_iter->begin.y;
		if ( value_iter->end.y < extent.minY ) extent.minY = value_iter->end.y;

		if ( value_iter->begin.x > extent.maxX ) extent.maxX = value_iter->begin.x;
		if ( value_iter->end.x > extent.maxX ) extent.maxX = value_iter->end.x;
		if ( value_iter->begin.y > extent.maxY ) extent.maxY = value_iter->begin.y;
		if ( value_iter->end.y > extent.maxY ) extent.maxY = value_iter->end.y;
	}

	return extent;
}

bool operator==(Point<float> const& p1, Point<float> const& p2)
{
	using std::abs;
	using std::numeric_limits;

	return abs( p1.x - p2.x ) < numeric_limits<float>::epsilon() &&
		abs( p1.y - p2.y ) < numeric_limits<float>::epsilon();
}

std::size_t hash_value(Point<float> const& p) {
	using std::size_t;
	using boost::hash_combine;

    size_t seed = 0;

    hash_combine(seed, p.x);
    hash_combine(seed, p.y);

    return seed;
}

<commit_msg>Last parameter is implied.<commit_after>/* The MIT License

Copyright (c) 2011 Sahab Yazdani

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include "stippler_impl.h"

#include <fstream>
#include <limits>

#include <boost/random.hpp>

#include "VoronoiDiagramGenerator.h"

Stippler::Stippler( const StipplingParameters &parameters )
: IStippler(),
parameters(parameters),
displacement(std::numeric_limits<float>::max()),
vertsX(new float[parameters.points]), vertsY(new float[parameters.points]), radii(new float[parameters.points]),
image(parameters.inputFile) {
	createInitialDistribution();
}

Stippler::~Stippler() {
	delete[] radii;
	delete[] vertsX;
	delete[] vertsY;
}

void Stippler::distribute() {
	createVoronoiDiagram();
	redistributeStipples();
}

float Stippler::getAverageDisplacement() {
	return displacement;
}

void Stippler::createInitialDistribution() {
	using std::ceil;

	// find initial distribution
	boost::mt19937 rng;
	boost::uniform_01<boost::mt19937, float> generator( rng );

	float w = (float)(image.getWidth() - 1), h = (float)(image.getHeight() - 1);
	float xC, yC;

	for ( unsigned int i = 0; i < parameters.points; ) {
		xC = generator() * w;
		yC = generator() * h;

		// do a nearest neighbour search on the vertices
		if ( ceil(generator() * 255.0f) <= image.getIntensity( xC, yC ) ) {
			vertsX[i] = xC;
			vertsY[i] = yC;
			radii[i] = 0.0f;

			i++;
		}
	}
}

void Stippler::getStipples( StipplePoint *dst ) {
	StipplePoint *workingPtr;

	for (unsigned int i = 0; i < parameters.points; i++ ) {
		workingPtr = &(dst[i]);

		workingPtr->x = vertsX[i];
		workingPtr->y = vertsY[i];
		workingPtr->radius = radii[i];

		image.getColour(vertsX[i], vertsY[i], workingPtr->r, workingPtr->g, workingPtr->b);
	}
}

void Stippler::createVoronoiDiagram() {
	VoronoiDiagramGenerator generator;

	generator.generateVoronoi( vertsX, vertsY, parameters.points,
		0.0f, (float)(image.getWidth() - 1), 0.0f, (float)(image.getHeight() - 1) );

	edges.clear();

	Point< float > p1, p2;
	Edge< float > edge;

	generator.resetIterator();
	while ( generator.getNext(
		edge.begin.x, edge.begin.y, edge.end.x, edge.end.y,
		p1.x, p1.y, p2.x, p2.y ) ) {

		if ( edge.begin == edge.end ) {
			continue;
		}

		if ( edges.find( p1 ) == edges.end() ) {
			edges[p1] = EdgeList();
		}
		if ( edges.find( p2 ) == edges.end() ) {
			edges[p2] = EdgeList();
		}
		edges[p1].push_back( edge );
		edges[p2].push_back( edge );
	}
}

void Stippler::redistributeStipples() {
	using std::pow;
	using std::sqrt;
	using std::pair;
	using std::make_pair;
	using std::vector;

	unsigned int j = 0;
	float distance, local_displacement;

	vector< pair< Point< float >, EdgeList > > vectorized;
	for ( EdgeMap::iterator key_iter = edges.begin(); key_iter != edges.end(); ++key_iter ) {
		vectorized.push_back(make_pair(key_iter->first, key_iter->second));
	}

	local_displacement = displacement = 0.0f;

	#pragma omp parallel for private(distance) reduction(+:local_displacement)
	for (int i = 0; i < (int)vectorized.size(); i++) {
		pair< Point< float >, EdgeList > item = vectorized[i];
		pair< Point<float>, float > centroid = calculateCellCentroid( item.first, item.second );

		distance = sqrt( pow( item.first.x - centroid.first.x, 2.0f ) + pow( item.first.y - centroid.first.y, 2.0f ) );

		radii[i] = centroid.second;
		vertsX[i] = centroid.first.x;
		vertsY[i] = centroid.first.y;

		local_displacement += distance;
	}

	displacement = local_displacement / vectorized.size(); // average out the displacement
}

inline Stippler::line Stippler::createClipLine( float insideX, float insideY, float x1, float y1, float x2, float y2 ) {
	using std::abs;
	using std::numeric_limits;

	Stippler::line l;

	// if the floating point version of the line collapsed down to one
	// point, then just ignore it all
	if (abs(x1 - x2) < numeric_limits<float>::epsilon() && abs(y1 - y2) < numeric_limits<float>::epsilon()) {
		l.a = .0f;
		l.b = .0f;
		l.c = .0f;

		return l;
	}

	l.a = -(y1 - y2);
	l.b = x1 - x2;
	l.c = (y1 - y2) * x1 - (x1 - x2) * y1;

	// make sure the known inside point falls on the correct side of the clipping plane
	if ( insideX * l.a + insideY * l.b + l.c > 0.0f ) {
		l.a *= -1;
		l.b *= -1;
		l.c *= -1;
	}

	return l;
}

std::pair< Point<float>, float > Stippler::calculateCellCentroid( Point<float> &inside, EdgeList &edgeList ) {
	using std::make_pair;
	using std::numeric_limits;
	using std::vector;
	using std::floor;
	using std::ceil;
	using std::abs;
	using std::sqrt;
	using std::pow;

	vector<line> clipLines;
	extents extent = getCellExtents(edgeList);

	unsigned int x, y;

	float xDiff = ( extent.maxX - extent.minX );
	float yDiff = ( extent.maxY - extent.minY );

	unsigned int tileWidth = (unsigned int)ceil(xDiff) * parameters.subpixels;
	unsigned int tileHeight = (unsigned int)ceil(yDiff) * parameters.subpixels;

	float xStep = xDiff / (float)tileWidth;
	float yStep = yDiff / (float)tileHeight;

	float spotDensity, areaDensity = 0.0f, maxAreaDensity = 0.0f;
	float xSum = 0.0f;
	float ySum = 0.0f;

	float xCurrent;
	float yCurrent;

	// compute the clip lines
	for ( EdgeList::iterator value_iter = edgeList.begin(); value_iter != edgeList.end(); ++value_iter ) {
		line l = createClipLine( inside.x, inside.y,
			value_iter->begin.x, value_iter->begin.y,
			value_iter->end.x, value_iter->end.y );

		if (l.a < numeric_limits<float>::epsilon() && abs(l.b) < numeric_limits<float>::epsilon()) {
			continue;
		}

		clipLines.push_back(l);
	}

	for ( y = 0, yCurrent = extent.minY; y < tileHeight; ++y, yCurrent += yStep ) {
		for ( x = 0, xCurrent = extent.minX; x < tileWidth; ++x, xCurrent += xStep ) {
			// a point is outside of the polygon if it is outside of all clipping planes
			bool outside = false;
			for ( vector<line>::iterator iter = clipLines.begin(); iter != clipLines.end(); iter++ ) {
				if ( xCurrent * iter->a + yCurrent * iter->b + iter->c >= 0.0f ) {
					outside = true;
					break;
				}
			}

			if (!outside) {
				spotDensity = image.getIntensity(xCurrent, yCurrent);

				areaDensity += spotDensity;
				maxAreaDensity += 255.0f;
				xSum += spotDensity * xCurrent;
				ySum += spotDensity * yCurrent;
			}
		}
	}

	float area = areaDensity * xStep * yStep / 255.0f;
	float maxArea = maxAreaDensity * xStep * yStep / 255.0f;

	Point<float> pt;
	if (areaDensity > numeric_limits<float>::epsilon()) {
		pt.x = xSum / areaDensity;
		pt.y = ySum / areaDensity;
	} else {
		// if for some reason, the cell is completely white, then the centroid does not move
		pt.x = inside.x;
		pt.y = inside.y;
	}

	float closest = numeric_limits<float>::max(),
		  farthest = numeric_limits<float>::min(),
		  distance;
	float x0 = pt.x, y0 = pt.y,
	      x1, x2, y1, y2;

	for ( EdgeList::iterator value_iter = edgeList.begin(); value_iter != edgeList.end(); ++value_iter ) {
		x1 = value_iter->begin.x; x2 = value_iter->end.x;
		y1 = value_iter->begin.y; y2 = value_iter->end.y;

		distance = abs( ( x2 - x1 ) * ( y1 - y0 ) - ( x1 - x0 ) * ( y2 - y1 ) ) / sqrt( pow( x2 - x1, 2.0f ) + pow( y2 - y1, 2.0f ) );
		if ( closest > distance ) {
			closest = distance;
		}
		if ( farthest < distance ) {
			farthest = distance;
		}
	}

	float radius;
	if ( parameters.noOverlap ) {
		radius = closest;
	} else {
		radius = farthest;
	}
	radius *= area / maxArea;

	return make_pair( pt, radius );
}

Stippler::extents Stippler::getCellExtents( Stippler::EdgeList &edgeList ) {
	using std::numeric_limits;

	extents extent;

	extent.minX = extent.minY = numeric_limits<float>::max();
	extent.maxX = extent.maxY = numeric_limits<float>::min();

	for ( EdgeList::iterator value_iter = edgeList.begin(); value_iter != edgeList.end(); ++value_iter ) {
		if ( value_iter->begin.x < extent.minX ) extent.minX = value_iter->begin.x;
		if ( value_iter->end.x < extent.minX ) extent.minX = value_iter->end.x;
		if ( value_iter->begin.y < extent.minY ) extent.minY = value_iter->begin.y;
		if ( value_iter->end.y < extent.minY ) extent.minY = value_iter->end.y;

		if ( value_iter->begin.x > extent.maxX ) extent.maxX = value_iter->begin.x;
		if ( value_iter->end.x > extent.maxX ) extent.maxX = value_iter->end.x;
		if ( value_iter->begin.y > extent.maxY ) extent.maxY = value_iter->begin.y;
		if ( value_iter->end.y > extent.maxY ) extent.maxY = value_iter->end.y;
	}

	return extent;
}

bool operator==(Point<float> const& p1, Point<float> const& p2)
{
	using std::abs;
	using std::numeric_limits;

	return abs( p1.x - p2.x ) < numeric_limits<float>::epsilon() &&
		abs( p1.y - p2.y ) < numeric_limits<float>::epsilon();
}

std::size_t hash_value(Point<float> const& p) {
	using std::size_t;
	using boost::hash_combine;

    size_t seed = 0;

    hash_combine(seed, p.x);
    hash_combine(seed, p.y);

    return seed;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include "repair.hh"

#include "streaming/stream_plan.hh"
#include "streaming/stream_state.hh"
#include "gms/inet_address.hh"

static logging::logger logger("repair");

static std::vector<sstring> list_column_families(const database& db, const sstring& keyspace) {
    std::vector<sstring> ret;
    for (auto &&e : db.get_column_families_mapping()) {
        if (e.first.first == keyspace) {
            ret.push_back(e.first.second);
        }
    }
    return ret;
}

template<typename Collection, typename T>
void remove_item(Collection& c, T& item) {
    auto it = std::find(c.begin(), c.end(), item);
    if (it != c.end()) {
        c.erase(it);
    }
}

// Return all of the neighbors with whom we share the provided range.
static std::vector<gms::inet_address> get_neighbors(database& db,
        const sstring& ksname, query::range<dht::token> range
        //Collection<String> dataCenters, Collection<String> hosts)
        ) {
    keyspace& ks = db.find_keyspace(ksname);
    auto& rs = ks.get_replication_strategy();

    dht::token tok = range.end() ? range.end()->value() : dht::maximum_token();
    auto ret = rs.get_natural_endpoints(tok);
    remove_item(ret, utils::fb_utilities::get_broadcast_address());
    return ret;

#if 0
    // Origin's ActiveRepairService.getNeighbors() contains a lot of important
    // stuff we need to do, like verifying the requested range fits a local
    // range, and also taking the "datacenters" and "hosts" options.
        StorageService ss = StorageService.instance;
        Map<Range<Token>, List<InetAddress>> replicaSets = ss.getRangeToAddressMap(keyspaceName);
        Range<Token> rangeSuperSet = null;
        for (Range<Token> range : ss.getLocalRanges(keyspaceName))
        {
            if (range.contains(toRepair))
            {
                rangeSuperSet = range;
                break;
            }
            else if (range.intersects(toRepair))
            {
                throw new IllegalArgumentException("Requested range intersects a local range but is not fully contained in one; this would lead to imprecise repair");
            }
        }
        if (rangeSuperSet == null || !replicaSets.containsKey(rangeSuperSet))
            return Collections.emptySet();

        Set<InetAddress> neighbors = new HashSet<>(replicaSets.get(rangeSuperSet));
        neighbors.remove(FBUtilities.getBroadcastAddress());

        if (dataCenters != null && !dataCenters.isEmpty())
        {
            TokenMetadata.Topology topology = ss.getTokenMetadata().cloneOnlyTokenMap().getTopology();
            Set<InetAddress> dcEndpoints = Sets.newHashSet();
            Multimap<String,InetAddress> dcEndpointsMap = topology.getDatacenterEndpoints();
            for (String dc : dataCenters)
            {
                Collection<InetAddress> c = dcEndpointsMap.get(dc);
                if (c != null)
                   dcEndpoints.addAll(c);
            }
            return Sets.intersection(neighbors, dcEndpoints);
        }
        else if (hosts != null && !hosts.isEmpty())
        {
            Set<InetAddress> specifiedHost = new HashSet<>();
            for (final String host : hosts)
            {
                try
                {
                    final InetAddress endpoint = InetAddress.getByName(host.trim());
                    if (endpoint.equals(FBUtilities.getBroadcastAddress()) || neighbors.contains(endpoint))
                        specifiedHost.add(endpoint);
                }
                catch (UnknownHostException e)
                {
                    throw new IllegalArgumentException("Unknown host specified " + host, e);
                }
            }

            if (!specifiedHost.contains(FBUtilities.getBroadcastAddress()))
                throw new IllegalArgumentException("The current host must be part of the repair");

            if (specifiedHost.size() <= 1)
            {
                String msg = "Repair requires at least two endpoints that are neighbours before it can continue, the endpoint used for this repair is %s, " +
                             "other available neighbours are %s but these neighbours were not part of the supplied list of hosts to use during the repair (%s).";
                throw new IllegalArgumentException(String.format(msg, specifiedHost, neighbors, hosts));
            }

            specifiedHost.remove(FBUtilities.getBroadcastAddress());
            return specifiedHost;

        }

        return neighbors;
#endif
}

// Each repair_start() call returns a unique integer which the user can later
// use to follow the status of this repair with the repair_status() function.
static std::atomic<int> next_repair_command {0};

// The repair_tracker tracks ongoing repair operations and their progress.
// A repair which has already finished successfully is dropped from this
// table, but a failed repair will remain in the table forever so it can
// be queried about more than once (FIXME: reconsider this. But note that
// failed repairs should be rare anwyay).
// This object is not thread safe, and must be used by only one cpu.
static class {
private:
    // Note that there are no "SUCCESSFUL" entries in the "status" map:
    // Successfully-finished repairs are those with id < next_repair_command
    // but aren't listed as running or failed the status map.
    std::unordered_map<int, repair_status> _status;
public:
    void start(int id) {
        _status[id] = repair_status::RUNNING;
    }
    void done(int id, bool succeeded) {
        if (succeeded) {
            _status.erase(id);
        } else {
            _status[id] = repair_status::FAILED;
        }
    }
    repair_status get(int id) {
        if (id >= next_repair_command.load(std::memory_order_relaxed)) {
            throw std::runtime_error(sprint("unknown repair id %d", id));
        }
        auto it = _status.find(id);
        if (it == _status.end()) {
            return repair_status::SUCCESSFUL;
        } else {
            return it->second;
        }
    }
} repair_tracker;

// repair_start() can run on any cpu; It runs on cpu0 the function
// do_repair_start(). The benefit of always running that function on the same
// CPU is that it allows us to keep some state (like a list of ongoing
// repairs). It is fine to always do this on one CPU, because the function
// itself does very little (mainly tell other nodes and CPUs what to do).

// Repair a single range. Comparable to RepairSession in Origin
// In Origin, this is composed of several "repair jobs", each with one cf,
// but our streaming already works for several cfs.
static future<> repair_range(seastar::sharded<database>& db, sstring keyspace,
        query::range<dht::token> range, std::vector<sstring> cfs) {
    auto sp = make_lw_shared<streaming::stream_plan>("repair");
    auto id = utils::UUID_gen::get_time_UUID();

    auto neighbors = get_neighbors(db.local(), keyspace, range);
    logger.info("[repair #{}] new session: will sync {} on range {} for {}.{}", id, neighbors, range, keyspace, cfs);
    for (auto peer : neighbors) {
        // FIXME: think: if we have several neighbors, perhaps we need to
        // request ranges from all of them and only later transfer ranges to
        // all of them? Otherwise, we won't necessarily fully repair the
        // other ndoes, just this one? What does Cassandra do here?
        sp->transfer_ranges(peer, peer, keyspace, {range}, cfs);
        sp->request_ranges(peer, peer, keyspace, {range}, cfs);
    }
    return sp->execute().discard_result().then([sp, id] {
        logger.info("repair session #{} successful", id);
    }).handle_exception([id] (auto ep) {
        logger.error("repair session #{} stream failed: {}", id, ep);
        return make_exception_future(std::runtime_error("repair_range failed"));
    });
}

static std::vector<query::range<dht::token>> get_ranges_for_endpoint(
        database& db, sstring keyspace, gms::inet_address ep) {
    auto& rs = db.find_keyspace(keyspace).get_replication_strategy();
    return rs.get_ranges(ep);
}

static std::vector<query::range<dht::token>> get_local_ranges(
        database& db, sstring keyspace) {
    return get_ranges_for_endpoint(db, keyspace, utils::fb_utilities::get_broadcast_address());
}

static void do_repair_start(seastar::sharded<database>& db, sstring keyspace,
        std::unordered_map<sstring, sstring> options, int id) {

    logger.info("starting user-requested repair for keyspace {}", keyspace);

    repair_tracker.start(id);

    // If the "ranges" option is not explicitly specified, we repair all the
    // local ranges (the token ranges for which this node holds a replica of).
    // Each of these ranges may have a different set of replicas, so the
    // repair of each range is performed separately with repair_range().
    std::vector<query::range<dht::token>> ranges;
    // FIXME: if the "ranges" options exists, use that instead of
    // get_local_ranges() below. Also, translate the following Origin code:

#if 0
         if (option.isPrimaryRange())
         {
             // when repairing only primary range, neither dataCenters nor hosts can be set
             if (option.getDataCenters().isEmpty() && option.getHosts().isEmpty())
                 option.getRanges().addAll(getPrimaryRanges(keyspace));
                 // except dataCenters only contain local DC (i.e. -local)
             else if (option.getDataCenters().size() == 1 && option.getDataCenters().contains(DatabaseDescriptor.getLocalDataCenter()))
                 option.getRanges().addAll(getPrimaryRangesWithinDC(keyspace));
             else
                 throw new IllegalArgumentException("You need to run primary range repair on all nodes in the cluster.");
         }
         else
#endif
    ranges = get_local_ranges(db.local(), keyspace);

    // FIXME: let the cfs be overriden by an option
    std::vector<sstring> cfs = list_column_families(db.local(), keyspace);

#if 1
    // repair all the ranges in parallel
    auto done = make_lw_shared<semaphore>(0);
    auto success = make_lw_shared<bool>(true);
    for (auto range : ranges) {
        repair_range(db, keyspace, range, cfs).
                handle_exception([success] (std::exception_ptr eptr)
                        { *success = false; }).
                finally([done] { done->signal(); });
    }
    done->wait(ranges.size()).then([done, id, success] {
        logger.info("repair {} complete, success={}", id, success);
        repair_tracker.done(id, *success);
    });
#else
    // repair all the ranges in sequence
    do_with(std::move(ranges), [&db, keyspace, cfs, id] (auto& ranges) {
        return do_for_each(ranges.begin(), ranges.end(), [&db, keyspace, cfs, id] (auto&& range) {
            return repair_range(db, keyspace, range, cfs);
        }).then([id] {
            logger.info("repair {} completed sucessfully", id);
            repair_tracker.done(id, true);
        }).handle_exception([id] (std::exception_ptr eptr) {
            logger.info("repair {} failed", id);
            repair_tracker.done(id, false);
        });
    });
#endif
}

int repair_start(seastar::sharded<database>& db, sstring keyspace,
        std::unordered_map<sstring, sstring> options) {
    int i = next_repair_command++;
    db.invoke_on(0, [i, &db, keyspace = std::move(keyspace), options = std::move(options)] (database& localdb) {
        do_repair_start(db, std::move(keyspace), std::move(options), i);
    }); // Note we ignore the value of this future
    return i;
}

future<repair_status> repair_get_status(seastar::sharded<database>& db, int id) {
    return db.invoke_on(0, [id] (database& localdb) {
        return repair_tracker.get(id);
    });
}
<commit_msg>repair: use parallel_for_each instead of semaphore<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#include "repair.hh"

#include "streaming/stream_plan.hh"
#include "streaming/stream_state.hh"
#include "gms/inet_address.hh"

static logging::logger logger("repair");

static std::vector<sstring> list_column_families(const database& db, const sstring& keyspace) {
    std::vector<sstring> ret;
    for (auto &&e : db.get_column_families_mapping()) {
        if (e.first.first == keyspace) {
            ret.push_back(e.first.second);
        }
    }
    return ret;
}

template<typename Collection, typename T>
void remove_item(Collection& c, T& item) {
    auto it = std::find(c.begin(), c.end(), item);
    if (it != c.end()) {
        c.erase(it);
    }
}

// Return all of the neighbors with whom we share the provided range.
static std::vector<gms::inet_address> get_neighbors(database& db,
        const sstring& ksname, query::range<dht::token> range
        //Collection<String> dataCenters, Collection<String> hosts)
        ) {
    keyspace& ks = db.find_keyspace(ksname);
    auto& rs = ks.get_replication_strategy();

    dht::token tok = range.end() ? range.end()->value() : dht::maximum_token();
    auto ret = rs.get_natural_endpoints(tok);
    remove_item(ret, utils::fb_utilities::get_broadcast_address());
    return ret;

#if 0
    // Origin's ActiveRepairService.getNeighbors() contains a lot of important
    // stuff we need to do, like verifying the requested range fits a local
    // range, and also taking the "datacenters" and "hosts" options.
        StorageService ss = StorageService.instance;
        Map<Range<Token>, List<InetAddress>> replicaSets = ss.getRangeToAddressMap(keyspaceName);
        Range<Token> rangeSuperSet = null;
        for (Range<Token> range : ss.getLocalRanges(keyspaceName))
        {
            if (range.contains(toRepair))
            {
                rangeSuperSet = range;
                break;
            }
            else if (range.intersects(toRepair))
            {
                throw new IllegalArgumentException("Requested range intersects a local range but is not fully contained in one; this would lead to imprecise repair");
            }
        }
        if (rangeSuperSet == null || !replicaSets.containsKey(rangeSuperSet))
            return Collections.emptySet();

        Set<InetAddress> neighbors = new HashSet<>(replicaSets.get(rangeSuperSet));
        neighbors.remove(FBUtilities.getBroadcastAddress());

        if (dataCenters != null && !dataCenters.isEmpty())
        {
            TokenMetadata.Topology topology = ss.getTokenMetadata().cloneOnlyTokenMap().getTopology();
            Set<InetAddress> dcEndpoints = Sets.newHashSet();
            Multimap<String,InetAddress> dcEndpointsMap = topology.getDatacenterEndpoints();
            for (String dc : dataCenters)
            {
                Collection<InetAddress> c = dcEndpointsMap.get(dc);
                if (c != null)
                   dcEndpoints.addAll(c);
            }
            return Sets.intersection(neighbors, dcEndpoints);
        }
        else if (hosts != null && !hosts.isEmpty())
        {
            Set<InetAddress> specifiedHost = new HashSet<>();
            for (final String host : hosts)
            {
                try
                {
                    final InetAddress endpoint = InetAddress.getByName(host.trim());
                    if (endpoint.equals(FBUtilities.getBroadcastAddress()) || neighbors.contains(endpoint))
                        specifiedHost.add(endpoint);
                }
                catch (UnknownHostException e)
                {
                    throw new IllegalArgumentException("Unknown host specified " + host, e);
                }
            }

            if (!specifiedHost.contains(FBUtilities.getBroadcastAddress()))
                throw new IllegalArgumentException("The current host must be part of the repair");

            if (specifiedHost.size() <= 1)
            {
                String msg = "Repair requires at least two endpoints that are neighbours before it can continue, the endpoint used for this repair is %s, " +
                             "other available neighbours are %s but these neighbours were not part of the supplied list of hosts to use during the repair (%s).";
                throw new IllegalArgumentException(String.format(msg, specifiedHost, neighbors, hosts));
            }

            specifiedHost.remove(FBUtilities.getBroadcastAddress());
            return specifiedHost;

        }

        return neighbors;
#endif
}

// Each repair_start() call returns a unique integer which the user can later
// use to follow the status of this repair with the repair_status() function.
static std::atomic<int> next_repair_command {0};

// The repair_tracker tracks ongoing repair operations and their progress.
// A repair which has already finished successfully is dropped from this
// table, but a failed repair will remain in the table forever so it can
// be queried about more than once (FIXME: reconsider this. But note that
// failed repairs should be rare anwyay).
// This object is not thread safe, and must be used by only one cpu.
static class {
private:
    // Note that there are no "SUCCESSFUL" entries in the "status" map:
    // Successfully-finished repairs are those with id < next_repair_command
    // but aren't listed as running or failed the status map.
    std::unordered_map<int, repair_status> _status;
public:
    void start(int id) {
        _status[id] = repair_status::RUNNING;
    }
    void done(int id, bool succeeded) {
        if (succeeded) {
            _status.erase(id);
        } else {
            _status[id] = repair_status::FAILED;
        }
    }
    repair_status get(int id) {
        if (id >= next_repair_command.load(std::memory_order_relaxed)) {
            throw std::runtime_error(sprint("unknown repair id %d", id));
        }
        auto it = _status.find(id);
        if (it == _status.end()) {
            return repair_status::SUCCESSFUL;
        } else {
            return it->second;
        }
    }
} repair_tracker;

// repair_start() can run on any cpu; It runs on cpu0 the function
// do_repair_start(). The benefit of always running that function on the same
// CPU is that it allows us to keep some state (like a list of ongoing
// repairs). It is fine to always do this on one CPU, because the function
// itself does very little (mainly tell other nodes and CPUs what to do).

// Repair a single range. Comparable to RepairSession in Origin
// In Origin, this is composed of several "repair jobs", each with one cf,
// but our streaming already works for several cfs.
static future<> repair_range(seastar::sharded<database>& db, sstring keyspace,
        query::range<dht::token> range, std::vector<sstring> cfs) {
    auto sp = make_lw_shared<streaming::stream_plan>("repair");
    auto id = utils::UUID_gen::get_time_UUID();

    auto neighbors = get_neighbors(db.local(), keyspace, range);
    logger.info("[repair #{}] new session: will sync {} on range {} for {}.{}", id, neighbors, range, keyspace, cfs);
    for (auto peer : neighbors) {
        // FIXME: think: if we have several neighbors, perhaps we need to
        // request ranges from all of them and only later transfer ranges to
        // all of them? Otherwise, we won't necessarily fully repair the
        // other ndoes, just this one? What does Cassandra do here?
        sp->transfer_ranges(peer, peer, keyspace, {range}, cfs);
        sp->request_ranges(peer, peer, keyspace, {range}, cfs);
    }
    return sp->execute().discard_result().then([sp, id] {
        logger.info("repair session #{} successful", id);
    }).handle_exception([id] (auto ep) {
        logger.error("repair session #{} stream failed: {}", id, ep);
        return make_exception_future(std::runtime_error("repair_range failed"));
    });
}

static std::vector<query::range<dht::token>> get_ranges_for_endpoint(
        database& db, sstring keyspace, gms::inet_address ep) {
    auto& rs = db.find_keyspace(keyspace).get_replication_strategy();
    return rs.get_ranges(ep);
}

static std::vector<query::range<dht::token>> get_local_ranges(
        database& db, sstring keyspace) {
    return get_ranges_for_endpoint(db, keyspace, utils::fb_utilities::get_broadcast_address());
}

static void do_repair_start(seastar::sharded<database>& db, sstring keyspace,
        std::unordered_map<sstring, sstring> options, int id) {

    logger.info("starting user-requested repair for keyspace {}", keyspace);

    repair_tracker.start(id);

    // If the "ranges" option is not explicitly specified, we repair all the
    // local ranges (the token ranges for which this node holds a replica of).
    // Each of these ranges may have a different set of replicas, so the
    // repair of each range is performed separately with repair_range().
    std::vector<query::range<dht::token>> ranges;
    // FIXME: if the "ranges" options exists, use that instead of
    // get_local_ranges() below. Also, translate the following Origin code:

#if 0
         if (option.isPrimaryRange())
         {
             // when repairing only primary range, neither dataCenters nor hosts can be set
             if (option.getDataCenters().isEmpty() && option.getHosts().isEmpty())
                 option.getRanges().addAll(getPrimaryRanges(keyspace));
                 // except dataCenters only contain local DC (i.e. -local)
             else if (option.getDataCenters().size() == 1 && option.getDataCenters().contains(DatabaseDescriptor.getLocalDataCenter()))
                 option.getRanges().addAll(getPrimaryRangesWithinDC(keyspace));
             else
                 throw new IllegalArgumentException("You need to run primary range repair on all nodes in the cluster.");
         }
         else
#endif
    ranges = get_local_ranges(db.local(), keyspace);

    // FIXME: let the cfs be overriden by an option
    std::vector<sstring> cfs = list_column_families(db.local(), keyspace);

    do_with(std::move(ranges), [&db, keyspace, cfs, id] (auto& ranges) {
#if 1
        // repair all the ranges in parallel
        return parallel_for_each(ranges.begin(), ranges.end(), [&db, keyspace, cfs, id] (auto&& range) {
#else
        // repair all the ranges in sequence
        return do_for_each(ranges.begin(), ranges.end(), [&db, keyspace, cfs, id] (auto&& range) {
#endif
            return repair_range(db, keyspace, range, cfs);
        }).then([id] {
            logger.info("repair {} completed sucessfully", id);
            repair_tracker.done(id, true);
        }).handle_exception([id] (std::exception_ptr eptr) {
            logger.info("repair {} failed", id);
            repair_tracker.done(id, false);
        });
    });
}

int repair_start(seastar::sharded<database>& db, sstring keyspace,
        std::unordered_map<sstring, sstring> options) {
    int i = next_repair_command++;
    db.invoke_on(0, [i, &db, keyspace = std::move(keyspace), options = std::move(options)] (database& localdb) {
        do_repair_start(db, std::move(keyspace), std::move(options), i);
    }); // Note we ignore the value of this future
    return i;
}

future<repair_status> repair_get_status(seastar::sharded<database>& db, int id) {
    return db.invoke_on(0, [id] (database& localdb) {
        return repair_tracker.get(id);
    });
}
<|endoftext|>