<commit_before>#pragma once

#include <unordered_map>
#include <boost/cast.hpp>

#include "BinaryMsg.hpp"

struct Dispatcher
{
  virtual ~Dispatcher(void) { }
  virtual void dispatch(BinaryMsg const& bin) = 0;
protected:
};

namespace detail
{
template<typename FinalType, typename C, typename H, typename ...T>
struct RegistrationHelper
{
  static void call(C& c)
  {
    auto h = [](FinalType& ft, BinaryMsg const& bin) { ft.handle( deserialize<H>(bin) ); };
    c[H::type()] = +h;
    RegistrationHelper<FinalType, C, T...>::call(c);
  }
};

template<typename FinalType, typename C>
struct RegistrationHelper<FinalType, C, void>
{
  static void call(C& c) { }
};
}

template<typename FinalType, typename ...M>
struct CustomDispatcher: public Dispatcher
{
  CustomDispatcher(void)
  {
    detail::RegistrationHelper<FinalType, decltype(handlers_), M..., void>::call(handlers_);
  }

  virtual void dispatch(BinaryMsg const& bin)
  {
    auto it = handlers_.find(bin.type_);
    if(it==std::end(handlers_))
      throw std::runtime_error("no handler for a given message type");
    auto h = it->second;
    assert(h);
    (*h)( *boost::polymorphic_downcast<FinalType*>(this), bin );
  }

private:
  std::unordered_map<unsigned, void(*)(FinalType&, BinaryMsg const&)> handlers_;
};
<commit_msg>fixed binary size issue; added runtime-check for unique message IDs<commit_after>#pragma once

#include <unordered_map>
#include <boost/cast.hpp>

#include "BinaryMsg.hpp"

struct Dispatcher
{
  virtual ~Dispatcher(void) { }
  virtual void dispatch(BinaryMsg const& bin) = 0;
protected:
};

namespace detail
{

template<typename FinalType, typename M>
void todo(FinalType& ft, BinaryMsg const& bin)
{
  ft.handle( deserialize<M>(bin) );
}

template<typename FinalType, typename C, typename H, typename ...T>
struct RegistrationHelper
{
  static void call(C& c)
  {
    // NOTE: although lambda version is way nicer, GCC generates 6x bigger code for that, clang 2x.
    //       apparently both misse some important optimization. too bad... :(
#if 0
    c[H::type()] = +[](FinalType& ft, BinaryMsg const& bin) { ft.handle( deserialize<H>(bin) ); };
#else
    c[H::type()] = todo<FinalType,H>;
#endif
    RegistrationHelper<FinalType, C, T...>::call(c);
  }
};

template<typename FinalType, typename C>
struct RegistrationHelper<FinalType, C, void>
{
  static void call(C& c) { }
};
}

template<typename FinalType, typename ...M>
struct CustomDispatcher: public Dispatcher
{
  CustomDispatcher(void)
  {
    // NOTE: compile time check for unique type-ids can be added here!
    detail::RegistrationHelper<FinalType, decltype(handlers_), M..., void>::call(handlers_);
    assert( handlers_.size() == sizeof...(M) && "non-unique message ids detected" );
  }

  virtual void dispatch(BinaryMsg const& bin)
  {
    auto it = handlers_.find(bin.type_);
    if(it==std::end(handlers_))
      throw std::runtime_error("no handler for a given message type");
    auto h = it->second;
    assert(h);
    (*h)( *boost::polymorphic_downcast<FinalType*>(this), bin );
  }

private:
  std::unordered_map<unsigned, void(*)(FinalType&, BinaryMsg const&)> handlers_;
};
<|endoftext|>


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

#ifndef _CPPCANVAS_VCLFACTORY_HXX
#define _CPPCANVAS_VCLFACTORY_HXX

#ifndef _CPPCANVAS_CANVAS_HXX
#include <cppcanvas/canvas.hxx>
#endif
#ifndef _CPPCANVAS_BITMAPCANVAS_HXX
#include <cppcanvas/bitmapcanvas.hxx>
#endif
#ifndef _CPPCANVAS_SPRITECANVAS_HXX
#include <cppcanvas/spritecanvas.hxx>
#endif
#ifndef _CPPCANVAS_POLYPOLYGON_HXX
#include <cppcanvas/polypolygon.hxx>
#endif
#ifndef _CPPCANVAS_BITMAP_HXX
#include <cppcanvas/bitmap.hxx>
#endif
#ifndef _CPPCANVAS_RENDERER_HXX
#include <cppcanvas/renderer.hxx>
#endif
#ifndef _CPPCANVAS_TEXT_HXX
#include <cppcanvas/text.hxx>
#endif
#ifndef _CPPCANVAS_SPRITE_HXX
#include <cppcanvas/sprite.hxx>
#endif

class Window;
class Bitmap;
class BitmapEx;
class Polygon;
class PolyPolygon;
class Size;
class Graphic;
class GDIMetaFile;
class Animation;

namespace rtl
{
    class OUString;
}
namespace com { namespace sun { namespace star { namespace rendering
{
    class  XBitmapCanvas;
    class  XSpriteCanvas;
} } } }

/* Definition of VCLFactory class */

namespace cppcanvas
{
    /** The VCLFactory creates Canvas objects for various VCL
        OutputDevice primitives, such as windows, polygons, bitmaps
        and metafiles.

        Please note that the objects created for a specific Canvas can
        only be drawn on exactly that canvas. You have to regenerate
        them for different canvases.
     */
    class VCLFactory
    {
    public:
        static VCLFactory& getInstance();

        BitmapCanvasSharedPtr   createCanvas( const ::Window& rVCLWindow );
        BitmapCanvasSharedPtr   createCanvas( const ::com::sun::star::uno::Reference<
                                                          ::com::sun::star::rendering::XBitmapCanvas >& xCanvas );

        SpriteCanvasSharedPtr   createSpriteCanvas( const ::Window& rVCLWindow ) const;
        SpriteCanvasSharedPtr   createSpriteCanvas( const ::com::sun::star::uno::Reference<
                                                               ::com::sun::star::rendering::XSpriteCanvas >& xCanvas ) const;
        SpriteCanvasSharedPtr   createFullscreenSpriteCanvas( const ::Window& rVCLWindow, const Size& rFullscreenSize ) const;

        /** Create a polygon from a tools::Polygon

            The created polygon initially has the same size in user
            coordinate space as the source polygon
         */
        PolyPolygonSharedPtr    createPolyPolygon( const CanvasSharedPtr&, const ::Polygon& rPoly ) const;
        PolyPolygonSharedPtr    createPolyPolygon( const CanvasSharedPtr&, const ::PolyPolygon& rPoly ) const;

        /** Create an uninitialized bitmap with the given size
         */
        BitmapSharedPtr         createBitmap( const CanvasSharedPtr&, const ::Size& rSize ) const;

        /** Create an uninitialized alpha bitmap with the given size
         */
        BitmapSharedPtr         createAlphaBitmap( const CanvasSharedPtr&, const ::Size& rSize ) const;

        /** Create a bitmap from a VCL Bitmap
         */
        BitmapSharedPtr         createBitmap( const CanvasSharedPtr&, const ::Bitmap& rBitmap ) const;
        BitmapSharedPtr         createBitmap( const CanvasSharedPtr&, const ::BitmapEx& rBmpEx ) const;

        /** Create a renderer object from a Graphic

            The created renderer initially draws the graphic
            one-by-one units large, in user coordinate space
         */
        RendererSharedPtr       createRenderer( const CanvasSharedPtr&          rCanvas,
                                                const ::Graphic&                rGraphic,
                                                const Renderer::Parameters&     rParms ) const;
        /** Create a renderer object from a Metafile

            The created renderer initially draws the metafile
            one-by-one units large, in user coordinate space
         */
        RendererSharedPtr       createRenderer( const CanvasSharedPtr&          rCanvas,
                                                const ::GDIMetaFile&            rMtf,
                                                const Renderer::Parameters&     rParms ) const;

        /** Create an animated sprite from a VCL animation
         */
        SpriteSharedPtr         createAnimatedSprite( const SpriteCanvasSharedPtr&, const ::Animation& rAnim ) const;

        /** Create a text portion with the given content string
         */
        TextSharedPtr           createText( const CanvasSharedPtr&, const ::rtl::OUString& ) const;

    private:
        friend struct InitInstance;

        // singleton
        VCLFactory();
        ~VCLFactory();

        // default: disabled copy/assignment
        VCLFactory(const VCLFactory&);
        VCLFactory& operator=( const VCLFactory& );
    };

}

#endif /* _CPPCANVAS_VCLFACTORY_HXX */
<commit_msg>INTEGRATION: CWS ooo19126 (1.4.20); FILE MERGED 2005/09/05 18:40:56 rt 1.4.20.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: vclfactory.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:16:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CPPCANVAS_VCLFACTORY_HXX
#define _CPPCANVAS_VCLFACTORY_HXX

#ifndef _CPPCANVAS_CANVAS_HXX
#include <cppcanvas/canvas.hxx>
#endif
#ifndef _CPPCANVAS_BITMAPCANVAS_HXX
#include <cppcanvas/bitmapcanvas.hxx>
#endif
#ifndef _CPPCANVAS_SPRITECANVAS_HXX
#include <cppcanvas/spritecanvas.hxx>
#endif
#ifndef _CPPCANVAS_POLYPOLYGON_HXX
#include <cppcanvas/polypolygon.hxx>
#endif
#ifndef _CPPCANVAS_BITMAP_HXX
#include <cppcanvas/bitmap.hxx>
#endif
#ifndef _CPPCANVAS_RENDERER_HXX
#include <cppcanvas/renderer.hxx>
#endif
#ifndef _CPPCANVAS_TEXT_HXX
#include <cppcanvas/text.hxx>
#endif
#ifndef _CPPCANVAS_SPRITE_HXX
#include <cppcanvas/sprite.hxx>
#endif

class Window;
class Bitmap;
class BitmapEx;
class Polygon;
class PolyPolygon;
class Size;
class Graphic;
class GDIMetaFile;
class Animation;

namespace rtl
{
    class OUString;
}
namespace com { namespace sun { namespace star { namespace rendering
{
    class  XBitmapCanvas;
    class  XSpriteCanvas;
} } } }

/* Definition of VCLFactory class */

namespace cppcanvas
{
    /** The VCLFactory creates Canvas objects for various VCL
        OutputDevice primitives, such as windows, polygons, bitmaps
        and metafiles.

        Please note that the objects created for a specific Canvas can
        only be drawn on exactly that canvas. You have to regenerate
        them for different canvases.
     */
    class VCLFactory
    {
    public:
        static VCLFactory& getInstance();

        BitmapCanvasSharedPtr   createCanvas( const ::Window& rVCLWindow );
        BitmapCanvasSharedPtr   createCanvas( const ::com::sun::star::uno::Reference<
                                                          ::com::sun::star::rendering::XBitmapCanvas >& xCanvas );

        SpriteCanvasSharedPtr   createSpriteCanvas( const ::Window& rVCLWindow ) const;
        SpriteCanvasSharedPtr   createSpriteCanvas( const ::com::sun::star::uno::Reference<
                                                               ::com::sun::star::rendering::XSpriteCanvas >& xCanvas ) const;
        SpriteCanvasSharedPtr   createFullscreenSpriteCanvas( const ::Window& rVCLWindow, const Size& rFullscreenSize ) const;

        /** Create a polygon from a tools::Polygon

            The created polygon initially has the same size in user
            coordinate space as the source polygon
         */
        PolyPolygonSharedPtr    createPolyPolygon( const CanvasSharedPtr&, const ::Polygon& rPoly ) const;
        PolyPolygonSharedPtr    createPolyPolygon( const CanvasSharedPtr&, const ::PolyPolygon& rPoly ) const;

        /** Create an uninitialized bitmap with the given size
         */
        BitmapSharedPtr         createBitmap( const CanvasSharedPtr&, const ::Size& rSize ) const;

        /** Create an uninitialized alpha bitmap with the given size
         */
        BitmapSharedPtr         createAlphaBitmap( const CanvasSharedPtr&, const ::Size& rSize ) const;

        /** Create a bitmap from a VCL Bitmap
         */
        BitmapSharedPtr         createBitmap( const CanvasSharedPtr&, const ::Bitmap& rBitmap ) const;
        BitmapSharedPtr         createBitmap( const CanvasSharedPtr&, const ::BitmapEx& rBmpEx ) const;

        /** Create a renderer object from a Graphic

            The created renderer initially draws the graphic
            one-by-one units large, in user coordinate space
         */
        RendererSharedPtr       createRenderer( const CanvasSharedPtr&          rCanvas,
                                                const ::Graphic&                rGraphic,
                                                const Renderer::Parameters&     rParms ) const;
        /** Create a renderer object from a Metafile

            The created renderer initially draws the metafile
            one-by-one units large, in user coordinate space
         */
        RendererSharedPtr       createRenderer( const CanvasSharedPtr&          rCanvas,
                                                const ::GDIMetaFile&            rMtf,
                                                const Renderer::Parameters&     rParms ) const;

        /** Create an animated sprite from a VCL animation
         */
        SpriteSharedPtr         createAnimatedSprite( const SpriteCanvasSharedPtr&, const ::Animation& rAnim ) const;

        /** Create a text portion with the given content string
         */
        TextSharedPtr           createText( const CanvasSharedPtr&, const ::rtl::OUString& ) const;

    private:
        friend struct InitInstance;

        // singleton
        VCLFactory();
        ~VCLFactory();

        // default: disabled copy/assignment
        VCLFactory(const VCLFactory&);
        VCLFactory& operator=( const VCLFactory& );
    };

}

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


<commit_before>#include "stdafx.h"
#include "SamplingTypeGenerator.h"
#include <math.h>
#include "DataHelper.h"
#include <algorithm>
#include <numeric>
#include "../FFTW-64/include/fftw3.h"

#pragma comment(lib, "../FFTW-64/lib/libfftw3-3.lib")
#pragma comment(lib, "../FFTW-64/lib/libfftw3f-3.lib")
#pragma comment(lib, "../FFTW-64/lib/libfftw3l-3.lib")

using namespace Yap;
using namespace std;

CSamplingTypeGenerator::CSamplingTypeGenerator(void):
	CProcessorImp(L"SamplingTypeGenerator"),
	_try_count(10),
	_tolerance(3)
{
	AddInputPort(L"Input", YAP_ANY_DIMENSION, DataTypeUnknown);
	AddOutputPort(L"Output", 1, DataTypeChar);

	AddProperty(PropertyFloat, L"pow", L"");
	SetFloat(L"pow", 3.0f);
	AddProperty(PropertyFloat, L"sample_percent", L"");
	SetFloat(L"sample_percent", 0.4);
	AddProperty(PropertyFloat, L"radius", L"");
	SetFloat(L"radius", 0.2f);
	AddProperty(PropertyBool, L"equal_subsampling", L"");
	SetBool(L"equal_subsampling", false);
	AddProperty(PropertyBool, L"random_subsampling", L"");
	SetBool(L"random_subsampling", true);
	AddProperty(PropertyInt, L"Rate", L"");
	SetInt(L"Rate", 2);
	AddProperty(PropertyInt, L"AcsCount", L"");
	SetInt(L"AcsCount", 16);
}

Yap::CSamplingTypeGenerator::CSamplingTypeGenerator(const CSamplingTypeGenerator & rhs)
	:CProcessorImp(rhs)
{
}

CSamplingTypeGenerator::~CSamplingTypeGenerator()
{
}

IProcessor * Yap::CSamplingTypeGenerator::Clone()
{
	try
	{
		auto processor = new CSamplingTypeGenerator(*this);
		return processor;
	}
	catch (std::bad_alloc&)
	{
		return nullptr;
	}
}

bool Yap::CSamplingTypeGenerator::Input(const wchar_t * name, IData * data)
{
	if (wstring(name) != L"Input")
		return false;

	if (data->GetDataType() != DataTypeComplexFloat)
		return false;

	CDataHelper input_data(data);
	if (GetBool(L"random_subsampling"))
	{
		auto row_count = input_data.GetHeight();
		float pow = static_cast<float> (GetFloat(L"pow"));
		float sample_percent = static_cast<float> (GetFloat(L"sample_percent"));
		float radius = static_cast<float> (GetFloat(L"radius"));

		auto sampling_pattern = GetMinInterferenceSamplingPattern(row_count, pow, sample_percent, radius);
		char * sampling_type = nullptr;
		try
		{
			sampling_type = new char[row_count];
		}
		catch(bad_alloc&)
		{
			return false;
		}
		memcpy(sampling_type, sampling_pattern.data(), sizeof(char));

		CDimensionsImp dimensions;
		dimensions(DimensionReadout, 0U, 1)
			(DimensionPhaseEncoding, 0U, row_count);
		CSmartPtr<CCharData> outdata(new CCharData(sampling_type, dimensions, nullptr, true));

		Feed(L"Output", outdata.get());
	}
	else
	{
		vector<unsigned char> sampling_pattern;
		unsigned int r = GetInt(L"Rate");
		unsigned int acs = GetInt(L"AcsCount");
		auto height = input_data.GetHeight();
		for (unsigned int i = 0; i <= height - r - 1; ++i)
		{
			if (i % r == 0)
			{
				sampling_pattern.push_back(1);
			}
			else
			{
				sampling_pattern.push_back(0);
			}
		}

		unsigned int first = static_cast<unsigned int>((floor((height - acs) / (2 * r))) * r + 1);
		unsigned int last = first + acs;
		sampling_pattern[first] = 1;
		while (first <= last)
		{
			++first;
			sampling_pattern[first] = 1;
		}

		char * sampling_type = nullptr;
		try
		{
			sampling_type = new char[height];
		}
		catch (bad_alloc&)
		{
			return false;
		}
		memcpy(sampling_type, sampling_pattern.data(), sizeof(char));

		CDimensionsImp dimensions;
		dimensions(DimensionReadout, 0U, 1)
			(DimensionPhaseEncoding, 0U, height);
		CSmartPtr<CCharData> outdata(new CCharData(sampling_type, dimensions, nullptr, true));

		Feed(L"Output", outdata.get());
	}
	return true;
}

std::vector<unsigned char> Yap::CSamplingTypeGenerator::GetMinInterferenceSamplingPattern(unsigned int row_count, float pow, float sample_percent, float radius)
{
	float min_peak_interference((float)INT_MAX);
	vector<float> pdf = GeneratePdf(row_count, pow, sample_percent, radius);

	vector<unsigned char> min_interference_pattern(pdf.size());
	vector<unsigned char> sampling_pattern(pdf.size());
	vector<complex<float>> normalized_sampling_pattern(pdf.size());
	vector<complex<float>> fft_result(pdf.size());

	fftwf_plan p = fftwf_plan_dft_1d(int(normalized_sampling_pattern.size()),
		(fftwf_complex*)normalized_sampling_pattern.data(),
		(fftwf_complex*)fft_result.data(),
		FFTW_BACKWARD, FFTW_ESTIMATE);	//kռ䵽ͼǷҶ任

	for (unsigned int i = 0; i < _try_count; ++i)
	{
		float sum_vector_element = 0;

		float sum_pdf = accumulate(pdf.begin(), pdf.end(), 0.0f);
		while (abs(sum_vector_element - sum_pdf) > _tolerance)
		{
			sum_vector_element = 0;
			for (unsigned int j = 0; j < pdf.size(); ++j)
			{
				sampling_pattern[j] = ((float)rand() / (RAND_MAX + 1) * 1) < pdf[j];
				sum_vector_element += sampling_pattern[j];
			}
		}

		//תΪʽ

		for (unsigned int t = 0; t < pdf.size(); t++)
		{
			normalized_sampling_pattern[t] = std::complex<float>(sampling_pattern[t] / pdf[t], 0);
		}
		// Ҷ任

		fftwf_execute(p);
		for (auto iter = fft_result.begin() + 1; iter != fft_result.end(); ++iter)
		{
			(*iter) /= float(sqrt(fft_result.size()));
		}
		*(fft_result.data()) = 0;
		float max_value = abs(fft_result[1]);
		for (auto it = fft_result.begin() + 1; it != fft_result.end(); ++it)
		{

			if (max_value < abs(*it))
			{
				max_value = abs(*it);
			}
		}

		if (max_value < min_peak_interference)
		{
			min_peak_interference = max_value;
			min_interference_pattern = sampling_pattern;
		}
	}
	//
	fftwf_destroy_plan(p);

	return min_interference_pattern;
}

std::vector<float> Yap::CSamplingTypeGenerator::GeneratePdf(unsigned int row_count, float p, float sample_percent, float radius)
{
	float minval = 0.0;
	float maxval = 1.0;
	float val = 0.5;
	unsigned int line_count = (unsigned int)floor(sample_percent * row_count);    // PCTG = 0.35 * 512 in Matlab
	float gap = float(2.0 / (row_count - 1));

	std::vector<float> pdf;

	pdf = LineSpace(-1, 1, row_count);
	std::vector<unsigned int> pdf_index(row_count);
	for (unsigned int i = 0; i < pdf.size(); ++i)
	{
		pdf_index[i] = 0;
		if (abs(pdf[i]) < radius)
		{
			pdf_index[i] = i;
		}
	}

	for (unsigned int i = 0; i < pdf.size(); ++i)
	{
		pdf[i] = pow(1 - abs(pdf[i]), p);
		if (i == pdf_index[i])
		{
			pdf[i] = 1;
		}
	}

	float sum = accumulate(pdf.begin(), pdf.end(), 0.0f);

	std::vector<float> pdf_temp;
	while (1)
	{
		val = minval / 2 + maxval / 2;
		pdf_temp.erase(pdf_temp.begin(), pdf_temp.end());
		for (unsigned int i = 0; i < row_count; ++i)
		{
			float pdf_elem = pdf[i] + val;
			if (pdf_elem > 1.0)
			{
				pdf_elem = 1.0;
			}
			pdf_temp.push_back(pdf_elem);
		}

		sum = floor(accumulate(pdf_temp.begin(), pdf_temp.end(), 0.0f));

		if (floor(sum) > line_count)
		{
			return vector<float>();  //pֵƫС
		}

		if (sum > line_count)
		{
			maxval = val;
		}
		else if (sum < line_count)
		{
			minval = val;
		}
		else
			break;
	}
	return pdf_temp;
}

std::vector<float> Yap::CSamplingTypeGenerator::LineSpace(float begin, float end, unsigned int count)
{
	std::vector<float> vec;
	float current_value = begin;
	float gap = float(2.0 / (count - 1));

	while (current_value <= end)
	{
		vec.push_back(current_value);
		current_value += gap;
	}
	while (vec.size() < count)
	{
		vec.push_back(end);
	}

	return vec;
}
<commit_msg>Modify SampingTypeGenerator<commit_after>#include "stdafx.h"
#include "SamplingTypeGenerator.h"
#include <math.h>
#include "DataHelper.h"
#include <algorithm>
#include <numeric>
#include "../FFTW-64/include/fftw3.h"

#pragma comment(lib, "../FFTW-64/lib/libfftw3-3.lib")
#pragma comment(lib, "../FFTW-64/lib/libfftw3f-3.lib")
#pragma comment(lib, "../FFTW-64/lib/libfftw3l-3.lib")

using namespace Yap;
using namespace std;

CSamplingTypeGenerator::CSamplingTypeGenerator(void):
	CProcessorImp(L"SamplingTypeGenerator"),
	_try_count(10),
	_tolerance(3)
{
	AddInputPort(L"Input", YAP_ANY_DIMENSION, DataTypeUnknown);
	AddOutputPort(L"Output", 1, DataTypeChar);

	AddProperty(PropertyFloat, L"pow", L"");
	SetFloat(L"pow", 3.0f);
	AddProperty(PropertyFloat, L"sample_percent", L"");
	SetFloat(L"sample_percent", 0.4);
	AddProperty(PropertyFloat, L"radius", L"");
	SetFloat(L"radius", 0.2f);

	AddProperty(PropertyBool, L"equal_subsampling", L"");
	SetBool(L"equal_subsampling", false);
	AddProperty(PropertyBool, L"random_subsampling", L"");
	SetBool(L"random_subsampling", true);

	AddProperty(PropertyInt, L"Rate", L"");
	SetInt(L"Rate", 2);
	AddProperty(PropertyInt, L"AcsCount", L"");
	SetInt(L"AcsCount", 16);
}

Yap::CSamplingTypeGenerator::CSamplingTypeGenerator(const CSamplingTypeGenerator & rhs)
	:CProcessorImp(rhs)
{
}

CSamplingTypeGenerator::~CSamplingTypeGenerator()
{
}

IProcessor * Yap::CSamplingTypeGenerator::Clone()
{
	try
	{
		auto processor = new CSamplingTypeGenerator(*this);
		return processor;
	}
	catch (std::bad_alloc&)
	{
		return nullptr;
	}
}

bool Yap::CSamplingTypeGenerator::Input(const wchar_t * name, IData * data)
{
	if (wstring(name) != L"Input")
		return false;

	if (data->GetDataType() != DataTypeComplexFloat)
		return false;

	CDataHelper input_data(data);
	if (GetBool(L"random_subsampling"))
	{
		auto row_count = input_data.GetHeight();
		float pow = static_cast<float> (GetFloat(L"pow"));
		float sample_percent = static_cast<float> (GetFloat(L"sample_percent"));
		float radius = static_cast<float> (GetFloat(L"radius"));

		auto sampling_pattern = GetMinInterferenceSamplingPattern(row_count, pow, sample_percent, radius);
		char * sampling_type = nullptr;
		try
		{
			sampling_type = new char[row_count];
		}
		catch(bad_alloc&)
		{
			return false;
		}
		memcpy(sampling_type, sampling_pattern.data(), row_count * sizeof(char));

		CDimensionsImp dimensions;
		dimensions(DimensionReadout, 0U, 1)
			(DimensionPhaseEncoding, 0U, row_count);
		CSmartPtr<CCharData> outdata(new CCharData(sampling_type, dimensions, nullptr, true));

		Feed(L"Output", outdata.get());
	}
	else
	{
		vector<unsigned char> sampling_pattern;
		unsigned int r = GetInt(L"Rate");
		unsigned int acs = GetInt(L"AcsCount");
		auto height = input_data.GetHeight();
		for (unsigned int i = 0; i <= height - r - 1; ++i)
		{
			if (i % r == 0)
			{
				sampling_pattern.push_back(1);
			}
			else
			{
				sampling_pattern.push_back(0);
			}
		}

		unsigned int first = static_cast<unsigned int>((floor((height - acs) / (2 * r))) * r + 1);
		unsigned int last = first + acs;
		sampling_pattern[first] = 1;
		while (first <= last)
		{
			++first;
			sampling_pattern[first] = 1;
		}

		char * sampling_type = nullptr;
		try
		{
			sampling_type = new char[height];
		}
		catch (bad_alloc&)
		{
			return false;
		}
		memcpy(sampling_type, sampling_pattern.data(), height * sizeof(char));

		CDimensionsImp dimensions;
		dimensions(DimensionReadout, 0U, 1)
			(DimensionPhaseEncoding, 0U, height);
		CSmartPtr<CCharData> outdata(new CCharData(sampling_type, dimensions, nullptr, true));

		Feed(L"Output", outdata.get());
	}
	return true;
}

std::vector<unsigned char> Yap::CSamplingTypeGenerator::GetMinInterferenceSamplingPattern(unsigned int row_count, float pow, float sample_percent, float radius)
{
	float min_peak_interference((float)INT_MAX);
	vector<float> pdf = GeneratePdf(row_count, pow, sample_percent, radius);

	vector<unsigned char> min_interference_pattern(pdf.size());
	vector<unsigned char> sampling_pattern(pdf.size());
	vector<complex<float>> normalized_sampling_pattern(pdf.size());
	vector<complex<float>> fft_result(pdf.size());

	fftwf_plan p = fftwf_plan_dft_1d(int(normalized_sampling_pattern.size()),
		(fftwf_complex*)normalized_sampling_pattern.data(),
		(fftwf_complex*)fft_result.data(),
		FFTW_BACKWARD, FFTW_ESTIMATE);	//kռ䵽ͼǷҶ任

	for (unsigned int i = 0; i < _try_count; ++i)
	{
		float sum_vector_element = 0;

		float sum_pdf = accumulate(pdf.begin(), pdf.end(), 0.0f);
		while (abs(sum_vector_element - sum_pdf) > _tolerance)
		{
			sum_vector_element = 0;
			for (unsigned int j = 0; j < pdf.size(); ++j)
			{
				sampling_pattern[j] = ((float)rand() / (RAND_MAX + 1) * 1) < pdf[j];
				sum_vector_element += sampling_pattern[j];
			}
		}

		//תΪʽ

		for (unsigned int t = 0; t < pdf.size(); t++)
		{
			normalized_sampling_pattern[t] = std::complex<float>(sampling_pattern[t] / pdf[t], 0);
		}
		// Ҷ任

		fftwf_execute(p);
		for (auto iter = fft_result.begin() + 1; iter != fft_result.end(); ++iter)
		{
			(*iter) /= float(sqrt(fft_result.size()));
		}
		*(fft_result.data()) = 0;
		float max_value = abs(fft_result[1]);
		for (auto it = fft_result.begin() + 1; it != fft_result.end(); ++it)
		{

			if (max_value < abs(*it))
			{
				max_value = abs(*it);
			}
		}

		if (max_value < min_peak_interference)
		{
			min_peak_interference = max_value;
			min_interference_pattern = sampling_pattern;
		}
	}
	//
	fftwf_destroy_plan(p);

	return min_interference_pattern;
}

std::vector<float> Yap::CSamplingTypeGenerator::GeneratePdf(unsigned int row_count, float p, float sample_percent, float radius)
{
	float minval = 0.0;
	float maxval = 1.0;
	float val = 0.5;
	unsigned int line_count = (unsigned int)floor(sample_percent * row_count);    // PCTG = 0.35 * 512 in Matlab
	float gap = float(2.0 / (row_count - 1));

	std::vector<float> pdf;

	pdf = LineSpace(-1, 1, row_count);
	std::vector<unsigned int> pdf_index(row_count);
	for (unsigned int i = 0; i < pdf.size(); ++i)
	{
		pdf_index[i] = 0;
		if (abs(pdf[i]) < radius)
		{
			pdf_index[i] = i;
		}
	}

	for (unsigned int i = 0; i < pdf.size(); ++i)
	{
		pdf[i] = pow(1 - abs(pdf[i]), p);
		if (i == pdf_index[i])
		{
			pdf[i] = 1;
		}
	}

	float sum = accumulate(pdf.begin(), pdf.end(), 0.0f);

	std::vector<float> pdf_temp;
	while (1)
	{
		val = minval / 2 + maxval / 2;
		pdf_temp.erase(pdf_temp.begin(), pdf_temp.end());
		for (unsigned int i = 0; i < row_count; ++i)
		{
			float pdf_elem = pdf[i] + val;
			if (pdf_elem > 1.0)
			{
				pdf_elem = 1.0;
			}
			pdf_temp.push_back(pdf_elem);
		}

		sum = floor(accumulate(pdf_temp.begin(), pdf_temp.end(), 0.0f));

		if (floor(sum) > line_count)
		{
			return vector<float>();  //pֵƫС
		}

		if (sum > line_count)
		{
			maxval = val;
		}
		else if (sum < line_count)
		{
			minval = val;
		}
		else
			break;
	}
	return pdf_temp;
}

std::vector<float> Yap::CSamplingTypeGenerator::LineSpace(float begin, float end, unsigned int count)
{
	std::vector<float> vec;
	float current_value = begin;
	float gap = float(2.0 / (count - 1));

	while (current_value <= end)
	{
		vec.push_back(current_value);
		current_value += gap;
	}
	while (vec.size() < count)
	{
		vec.push_back(end);
	}

	return vec;
}
<|endoftext|>


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

#include <folly/MemoryMapping.h>

#include <algorithm>
#include <functional>
#include <utility>

#include <folly/Format.h>
#include <folly/portability/GFlags.h>
#include <folly/portability/SysMman.h>

#ifdef __linux__
#include <folly/experimental/io/HugePages.h>
#endif

#include <fcntl.h>
#include <sys/types.h>
#include <system_error>

DEFINE_int64(mlock_chunk_size, 1 << 20,  // 1MB
             "Maximum bytes to mlock/munlock/munmap at once "
             "(will be rounded up to PAGESIZE)");

#ifndef MAP_POPULATE
#define MAP_POPULATE 0
#endif

namespace folly {

MemoryMapping::MemoryMapping(MemoryMapping&& other) noexcept {
  swap(other);
}

MemoryMapping::MemoryMapping(File file, off_t offset, off_t length,
                             Options options)
  : file_(std::move(file)),
    options_(std::move(options)) {
  CHECK(file_);
  init(offset, length);
}

MemoryMapping::MemoryMapping(const char* name, off_t offset, off_t length,
                             Options options)
    : MemoryMapping(File(name, options.writable ? O_RDWR : O_RDONLY),
                    offset,
                    length,
                    options) { }

MemoryMapping::MemoryMapping(int fd, off_t offset, off_t length,
                             Options options)
  : MemoryMapping(File(fd), offset, length, options) { }

MemoryMapping::MemoryMapping(AnonymousType, off_t length, Options options)
  : options_(std::move(options)) {
  init(0, length);
}

namespace {

#ifdef __linux__
void getDeviceOptions(dev_t device, off_t& pageSize, bool& autoExtend) {
  auto ps = getHugePageSizeForDevice(device);
  if (ps) {
    pageSize = ps->size;
    autoExtend = true;
  }
}
#else
inline void getDeviceOptions(dev_t device, off_t& pageSize,
                             bool& autoExtend) { }
#endif

}  // namespace

void MemoryMapping::init(off_t offset, off_t length) {
  const bool grow = options_.grow;
  const bool anon = !file_;
  CHECK(!(grow && anon));

  off_t& pageSize = options_.pageSize;

  struct stat st;

  // On Linux, hugetlbfs file systems don't require ftruncate() to grow the
  // file, and (on kernels before 2.6.24) don't even allow it. Also, the file
  // size is always a multiple of the page size.
  bool autoExtend = false;

  if (!anon) {
    // Stat the file
    CHECK_ERR(fstat(file_.fd(), &st));

    if (pageSize == 0) {
      getDeviceOptions(st.st_dev, pageSize, autoExtend);
    }
  } else {
    DCHECK(!file_);
    DCHECK_EQ(offset, 0);
    CHECK_EQ(pageSize, 0);
    CHECK_GE(length, 0);
  }

  if (pageSize == 0) {
    pageSize = sysconf(_SC_PAGESIZE);
  }

  CHECK_GT(pageSize, 0);
  CHECK_EQ(pageSize & (pageSize - 1), 0);  // power of two
  CHECK_GE(offset, 0);

  // Round down the start of the mapped region
  size_t skipStart = offset % pageSize;
  offset -= skipStart;

  mapLength_ = length;
  if (mapLength_ != -1) {
    mapLength_ += skipStart;

    // Round up the end of the mapped region
    mapLength_ = (mapLength_ + pageSize - 1) / pageSize * pageSize;
  }

  off_t remaining = anon ? length : st.st_size - offset;

  if (mapLength_ == -1) {
    length = mapLength_ = remaining;
  } else {
    if (length > remaining) {
      if (grow) {
        if (!autoExtend) {
          PCHECK(0 == ftruncate(file_.fd(), offset + length))
            << "ftruncate() failed, couldn't grow file to "
            << offset + length;
          remaining = length;
        } else {
          // Extend mapping to multiple of page size, don't use ftruncate
          remaining = mapLength_;
        }
      } else {
        length = remaining;
      }
    }
    if (mapLength_ > remaining) {
      mapLength_ = remaining;
    }
  }

  if (length == 0) {
    mapLength_ = 0;
    mapStart_ = nullptr;
  } else {
    int flags = options_.shared ? MAP_SHARED : MAP_PRIVATE;
    if (anon) flags |= MAP_ANONYMOUS;
    if (options_.prefault) flags |= MAP_POPULATE;

    // The standard doesn't actually require PROT_NONE to be zero...
    int prot = PROT_NONE;
    if (options_.readable || options_.writable) {
      prot = ((options_.readable ? PROT_READ : 0) |
              (options_.writable ? PROT_WRITE : 0));
    }

    unsigned char* start = static_cast<unsigned char*>(
      mmap(options_.address, mapLength_, prot, flags, file_.fd(), offset));
    PCHECK(start != MAP_FAILED)
      << " offset=" << offset
      << " length=" << mapLength_;
    mapStart_ = start;
    data_.reset(start + skipStart, length);
  }
}

namespace {

off_t memOpChunkSize(off_t length, off_t pageSize) {
  off_t chunkSize = length;
  if (FLAGS_mlock_chunk_size <= 0) {
    return chunkSize;
  }

  chunkSize = FLAGS_mlock_chunk_size;
  off_t r = chunkSize % pageSize;
  if (r) {
    chunkSize += (pageSize - r);
  }
  return chunkSize;
}

/**
 * Run @op in chunks over the buffer @mem of @bufSize length.
 *
 * Return:
 * - success: true + amountSucceeded == bufSize (op success on whole buffer)
 * - failure: false + amountSucceeded == nr bytes on which op succeeded.
 */
bool memOpInChunks(std::function<int(void*, size_t)> op,
                   void* mem, size_t bufSize, off_t pageSize,
                   size_t& amountSucceeded) {
#ifdef _MSC_VER
  // MSVC doesn't have this problem, and calling munmap many times
  // with the same address is a bad idea with the windows implementation.
  int ret = op(mem, bufSize);
  if (ret == 0) {
    amountSucceeded = bufSize;
  }
  return ret == 0;
#else
  // unmap/mlock/munlock take a kernel semaphore and block other threads from
  // doing other memory operations. If the size of the buffer is big the
  // semaphore can be down for seconds (for benchmarks see
  // http://kostja-osipov.livejournal.com/42963.html).  Doing the operations in
  // chunks breaks the locking into intervals and lets other threads do memory
  // operations of their own.

  size_t chunkSize = memOpChunkSize(bufSize, pageSize);

  char* addr = static_cast<char*>(mem);
  amountSucceeded = 0;

  while (amountSucceeded < bufSize) {
    size_t size = std::min(chunkSize, bufSize - amountSucceeded);
    if (op(addr + amountSucceeded, size) != 0) {
      return false;
    }
    amountSucceeded += size;
  }

  return true;
#endif
}

}  // anonymous namespace

bool MemoryMapping::mlock(LockMode lock) {
  size_t amountSucceeded = 0;
  locked_ = memOpInChunks(::mlock, mapStart_, mapLength_, options_.pageSize,
                          amountSucceeded);
  if (locked_) {
    return true;
  }

  auto msg =
    folly::sformat("mlock({}) failed at {}", mapLength_, amountSucceeded);

  if (lock == LockMode::TRY_LOCK && (errno == EPERM || errno == ENOMEM)) {
    PLOG(WARNING) << msg;
  } else {
    PLOG(FATAL) << msg;
  }

#ifndef _MSC_VER
  // only part of the buffer was mlocked, unlock it back
  if (!memOpInChunks(::munlock, mapStart_, amountSucceeded, options_.pageSize,
                     amountSucceeded)) {
    PLOG(WARNING) << "munlock()";
  }
#endif

  return false;
}

void MemoryMapping::munlock(bool dontneed) {
  if (!locked_) return;

  size_t amountSucceeded = 0;
  if (!memOpInChunks(::munlock, mapStart_, mapLength_, options_.pageSize,
                     amountSucceeded)) {
    PLOG(WARNING) << "munlock()";
  }
  if (mapLength_ && dontneed &&
      ::madvise(mapStart_, mapLength_, MADV_DONTNEED)) {
    PLOG(WARNING) << "madvise()";
  }
  locked_ = false;
}

void MemoryMapping::hintLinearScan() {
  advise(MADV_SEQUENTIAL);
}

MemoryMapping::~MemoryMapping() {
  if (mapLength_) {
    size_t amountSucceeded = 0;
    if (!memOpInChunks(::munmap, mapStart_, mapLength_, options_.pageSize,
                       amountSucceeded)) {
      PLOG(FATAL) << folly::format("munmap({}) failed at {}",
                                   mapLength_, amountSucceeded);
    }
  }
}

void MemoryMapping::advise(int advice) const { advise(advice, 0, mapLength_); }

void MemoryMapping::advise(int advice, size_t offset, size_t length) const {
  CHECK_LE(offset + length, mapLength_)
    << " offset: " << offset
    << " length: " << length
    << " mapLength_: " << mapLength_;

  // Include the entire start page: round down to page boundary.
  const auto offMisalign = offset % options_.pageSize;
  offset -= offMisalign;
  length += offMisalign;

  // Round the last page down to page boundary.
  if (offset + length != size_t(mapLength_)) {
    length -= length % options_.pageSize;
  }

  if (length == 0) {
    return;
  }

  char* mapStart = static_cast<char*>(mapStart_) + offset;
  PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise";
}

MemoryMapping& MemoryMapping::operator=(MemoryMapping other) {
  swap(other);
  return *this;
}

void MemoryMapping::swap(MemoryMapping& other) noexcept {
  using std::swap;
  swap(this->file_, other.file_);
  swap(this->mapStart_, other.mapStart_);
  swap(this->mapLength_, other.mapLength_);
  swap(this->options_, other.options_);
  swap(this->locked_, other.locked_);
  swap(this->data_, other.data_);
}

void swap(MemoryMapping& a, MemoryMapping& b) noexcept { a.swap(b); }

void alignedForwardMemcpy(void* dst, const void* src, size_t size) {
  assert(reinterpret_cast<uintptr_t>(src) % alignof(unsigned long) == 0);
  assert(reinterpret_cast<uintptr_t>(dst) % alignof(unsigned long) == 0);

  auto srcl = static_cast<const unsigned long*>(src);
  auto dstl = static_cast<unsigned long*>(dst);

  while (size >= sizeof(unsigned long)) {
    *dstl++ = *srcl++;
    size -= sizeof(unsigned long);
  }

  auto srcc = reinterpret_cast<const unsigned char*>(srcl);
  auto dstc = reinterpret_cast<unsigned char*>(dstl);

  while (size != 0) {
    *dstc++ = *srcc++;
    --size;
  }
}

void mmapFileCopy(const char* src, const char* dest, mode_t mode) {
  MemoryMapping srcMap(src);
  srcMap.hintLinearScan();

  MemoryMapping destMap(
      File(dest, O_RDWR | O_CREAT | O_TRUNC, mode),
      0,
      srcMap.range().size(),
      MemoryMapping::writable());

  alignedForwardMemcpy(destMap.writableRange().data(),
                       srcMap.range().data(),
                       srcMap.range().size());
}

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

#include <folly/MemoryMapping.h>

#include <algorithm>
#include <functional>
#include <utility>

#include <folly/Format.h>
#include <folly/portability/GFlags.h>
#include <folly/portability/SysMman.h>

#ifdef __linux__
#include <folly/experimental/io/HugePages.h>
#endif

#include <fcntl.h>
#include <sys/types.h>
#include <system_error>

static constexpr ssize_t kDefaultMlockChunkSize =
#ifndef _MSC_VER
    // Linux implementations of unmap/mlock/munlock take a kernel
    // semaphore and block other threads from doing other memory
    // operations. Split the operations in chunks.
    (1 << 20) // 1MB
#else // _MSC_VER
    // MSVC doesn't have this problem, and calling munmap many times
    // with the same address is a bad idea with the windows implementation.
    (-1)
#endif // _MSC_VER
    ;

DEFINE_int64(mlock_chunk_size, kDefaultMlockChunkSize,
             "Maximum bytes to mlock/munlock/munmap at once "
             "(will be rounded up to PAGESIZE). Ignored if negative.");

#ifndef MAP_POPULATE
#define MAP_POPULATE 0
#endif

namespace folly {

MemoryMapping::MemoryMapping(MemoryMapping&& other) noexcept {
  swap(other);
}

MemoryMapping::MemoryMapping(File file, off_t offset, off_t length,
                             Options options)
  : file_(std::move(file)),
    options_(std::move(options)) {
  CHECK(file_);
  init(offset, length);
}

MemoryMapping::MemoryMapping(const char* name, off_t offset, off_t length,
                             Options options)
    : MemoryMapping(File(name, options.writable ? O_RDWR : O_RDONLY),
                    offset,
                    length,
                    options) { }

MemoryMapping::MemoryMapping(int fd, off_t offset, off_t length,
                             Options options)
  : MemoryMapping(File(fd), offset, length, options) { }

MemoryMapping::MemoryMapping(AnonymousType, off_t length, Options options)
  : options_(std::move(options)) {
  init(0, length);
}

namespace {

#ifdef __linux__
void getDeviceOptions(dev_t device, off_t& pageSize, bool& autoExtend) {
  auto ps = getHugePageSizeForDevice(device);
  if (ps) {
    pageSize = ps->size;
    autoExtend = true;
  }
}
#else
inline void getDeviceOptions(dev_t device, off_t& pageSize,
                             bool& autoExtend) { }
#endif

}  // namespace

void MemoryMapping::init(off_t offset, off_t length) {
  const bool grow = options_.grow;
  const bool anon = !file_;
  CHECK(!(grow && anon));

  off_t& pageSize = options_.pageSize;

  struct stat st;

  // On Linux, hugetlbfs file systems don't require ftruncate() to grow the
  // file, and (on kernels before 2.6.24) don't even allow it. Also, the file
  // size is always a multiple of the page size.
  bool autoExtend = false;

  if (!anon) {
    // Stat the file
    CHECK_ERR(fstat(file_.fd(), &st));

    if (pageSize == 0) {
      getDeviceOptions(st.st_dev, pageSize, autoExtend);
    }
  } else {
    DCHECK(!file_);
    DCHECK_EQ(offset, 0);
    CHECK_EQ(pageSize, 0);
    CHECK_GE(length, 0);
  }

  if (pageSize == 0) {
    pageSize = sysconf(_SC_PAGESIZE);
  }

  CHECK_GT(pageSize, 0);
  CHECK_EQ(pageSize & (pageSize - 1), 0);  // power of two
  CHECK_GE(offset, 0);

  // Round down the start of the mapped region
  size_t skipStart = offset % pageSize;
  offset -= skipStart;

  mapLength_ = length;
  if (mapLength_ != -1) {
    mapLength_ += skipStart;

    // Round up the end of the mapped region
    mapLength_ = (mapLength_ + pageSize - 1) / pageSize * pageSize;
  }

  off_t remaining = anon ? length : st.st_size - offset;

  if (mapLength_ == -1) {
    length = mapLength_ = remaining;
  } else {
    if (length > remaining) {
      if (grow) {
        if (!autoExtend) {
          PCHECK(0 == ftruncate(file_.fd(), offset + length))
            << "ftruncate() failed, couldn't grow file to "
            << offset + length;
          remaining = length;
        } else {
          // Extend mapping to multiple of page size, don't use ftruncate
          remaining = mapLength_;
        }
      } else {
        length = remaining;
      }
    }
    if (mapLength_ > remaining) {
      mapLength_ = remaining;
    }
  }

  if (length == 0) {
    mapLength_ = 0;
    mapStart_ = nullptr;
  } else {
    int flags = options_.shared ? MAP_SHARED : MAP_PRIVATE;
    if (anon) flags |= MAP_ANONYMOUS;
    if (options_.prefault) flags |= MAP_POPULATE;

    // The standard doesn't actually require PROT_NONE to be zero...
    int prot = PROT_NONE;
    if (options_.readable || options_.writable) {
      prot = ((options_.readable ? PROT_READ : 0) |
              (options_.writable ? PROT_WRITE : 0));
    }

    unsigned char* start = static_cast<unsigned char*>(
      mmap(options_.address, mapLength_, prot, flags, file_.fd(), offset));
    PCHECK(start != MAP_FAILED)
      << " offset=" << offset
      << " length=" << mapLength_;
    mapStart_ = start;
    data_.reset(start + skipStart, length);
  }
}

namespace {

off_t memOpChunkSize(off_t length, off_t pageSize) {
  off_t chunkSize = length;
  if (FLAGS_mlock_chunk_size <= 0) {
    return chunkSize;
  }

  chunkSize = FLAGS_mlock_chunk_size;
  off_t r = chunkSize % pageSize;
  if (r) {
    chunkSize += (pageSize - r);
  }
  return chunkSize;
}

/**
 * Run @op in chunks over the buffer @mem of @bufSize length.
 *
 * Return:
 * - success: true + amountSucceeded == bufSize (op success on whole buffer)
 * - failure: false + amountSucceeded == nr bytes on which op succeeded.
 */
bool memOpInChunks(std::function<int(void*, size_t)> op,
                   void* mem, size_t bufSize, off_t pageSize,
                   size_t& amountSucceeded) {
  // Linux' unmap/mlock/munlock take a kernel semaphore and block other threads
  // from doing other memory operations. If the size of the buffer is big the
  // semaphore can be down for seconds (for benchmarks see
  // http://kostja-osipov.livejournal.com/42963.html).  Doing the operations in
  // chunks breaks the locking into intervals and lets other threads do memory
  // operations of their own.

  size_t chunkSize = memOpChunkSize(bufSize, pageSize);

  char* addr = static_cast<char*>(mem);
  amountSucceeded = 0;

  while (amountSucceeded < bufSize) {
    size_t size = std::min(chunkSize, bufSize - amountSucceeded);
    if (op(addr + amountSucceeded, size) != 0) {
      return false;
    }
    amountSucceeded += size;
  }

  return true;
}

}  // anonymous namespace

bool MemoryMapping::mlock(LockMode lock) {
  size_t amountSucceeded = 0;
  locked_ = memOpInChunks(::mlock, mapStart_, mapLength_, options_.pageSize,
                          amountSucceeded);
  if (locked_) {
    return true;
  }

  auto msg =
    folly::sformat("mlock({}) failed at {}", mapLength_, amountSucceeded);

  if (lock == LockMode::TRY_LOCK && (errno == EPERM || errno == ENOMEM)) {
    PLOG(WARNING) << msg;
  } else {
    PLOG(FATAL) << msg;
  }

  // only part of the buffer was mlocked, unlock it back
  if (!memOpInChunks(::munlock, mapStart_, amountSucceeded, options_.pageSize,
                     amountSucceeded)) {
    PLOG(WARNING) << "munlock()";
  }

  return false;
}

void MemoryMapping::munlock(bool dontneed) {
  if (!locked_) return;

  size_t amountSucceeded = 0;
  if (!memOpInChunks(::munlock, mapStart_, mapLength_, options_.pageSize,
                     amountSucceeded)) {
    PLOG(WARNING) << "munlock()";
  }
  if (mapLength_ && dontneed &&
      ::madvise(mapStart_, mapLength_, MADV_DONTNEED)) {
    PLOG(WARNING) << "madvise()";
  }
  locked_ = false;
}

void MemoryMapping::hintLinearScan() {
  advise(MADV_SEQUENTIAL);
}

MemoryMapping::~MemoryMapping() {
  if (mapLength_) {
    size_t amountSucceeded = 0;
    if (!memOpInChunks(::munmap, mapStart_, mapLength_, options_.pageSize,
                       amountSucceeded)) {
      PLOG(FATAL) << folly::format("munmap({}) failed at {}",
                                   mapLength_, amountSucceeded);
    }
  }
}

void MemoryMapping::advise(int advice) const { advise(advice, 0, mapLength_); }

void MemoryMapping::advise(int advice, size_t offset, size_t length) const {
  CHECK_LE(offset + length, mapLength_)
    << " offset: " << offset
    << " length: " << length
    << " mapLength_: " << mapLength_;

  // Include the entire start page: round down to page boundary.
  const auto offMisalign = offset % options_.pageSize;
  offset -= offMisalign;
  length += offMisalign;

  // Round the last page down to page boundary.
  if (offset + length != size_t(mapLength_)) {
    length -= length % options_.pageSize;
  }

  if (length == 0) {
    return;
  }

  char* mapStart = static_cast<char*>(mapStart_) + offset;
  PLOG_IF(WARNING, ::madvise(mapStart, length, advice)) << "madvise";
}

MemoryMapping& MemoryMapping::operator=(MemoryMapping other) {
  swap(other);
  return *this;
}

void MemoryMapping::swap(MemoryMapping& other) noexcept {
  using std::swap;
  swap(this->file_, other.file_);
  swap(this->mapStart_, other.mapStart_);
  swap(this->mapLength_, other.mapLength_);
  swap(this->options_, other.options_);
  swap(this->locked_, other.locked_);
  swap(this->data_, other.data_);
}

void swap(MemoryMapping& a, MemoryMapping& b) noexcept { a.swap(b); }

void alignedForwardMemcpy(void* dst, const void* src, size_t size) {
  assert(reinterpret_cast<uintptr_t>(src) % alignof(unsigned long) == 0);
  assert(reinterpret_cast<uintptr_t>(dst) % alignof(unsigned long) == 0);

  auto srcl = static_cast<const unsigned long*>(src);
  auto dstl = static_cast<unsigned long*>(dst);

  while (size >= sizeof(unsigned long)) {
    *dstl++ = *srcl++;
    size -= sizeof(unsigned long);
  }

  auto srcc = reinterpret_cast<const unsigned char*>(srcl);
  auto dstc = reinterpret_cast<unsigned char*>(dstl);

  while (size != 0) {
    *dstc++ = *srcc++;
    --size;
  }
}

void mmapFileCopy(const char* src, const char* dest, mode_t mode) {
  MemoryMapping srcMap(src);
  srcMap.hintLinearScan();

  MemoryMapping destMap(
      File(dest, O_RDWR | O_CREAT | O_TRUNC, mode),
      0,
      srcMap.range().size(),
      MemoryMapping::writable());

  alignedForwardMemcpy(destMap.writableRange().data(),
                       srcMap.range().data(),
                       srcMap.range().size());
}

}  // namespace folly
<|endoftext|>


<commit_before>/*$Id$
 *
 * This source file is a part of the Berlin Project.
 * Copyright (C) 1999 Stefan Seefeld <stefan@berlin-consortium.org>
 * http://www.berlin-consortium.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */
#ifndef _PolyGraphic_hh
#define _PolyGraphic_hh

#include <Berlin/GraphicImpl.hh>
#include <Berlin/Pool.hh>
#include <vector>

class PolyGraphic : public GraphicImpl
{
  class Iterator;
  friend class Iterator;
public:
  PolyGraphic();
  virtual ~PolyGraphic();

  virtual void append_graphic(Warsaw::Graphic_ptr);
  virtual void prepend_graphic(Warsaw::Graphic_ptr);
  virtual void remove_graphic(Warsaw::Tag);
  virtual void remove_child_graphic(Warsaw::Tag);
  virtual Warsaw::Graphic::Iterator_ptr first_child_graphic();
  virtual Warsaw::Graphic::Iterator_ptr last_child_graphic();

  virtual void need_resize();
  virtual void need_resize(Warsaw::Tag);
protected:
  CORBA::Long num_children();
  Warsaw::Tag unique_child_id();
  glist_t::iterator child_id_to_iterator(Warsaw::Tag);
  CORBA::Long child_id_to_index(Warsaw::Tag);
  Warsaw::Graphic::Requisition *children_requests();
  void deallocate_requisitions(Warsaw::Graphic::Requisition *);
  void child_extension(size_t, const Warsaw::Allocation::Info &, Warsaw::Region_ptr);
// private:
  static Pool<Warsaw::Graphic::Requisition> _pool;
  glist_t _children;
  Prague::Mutex _mutex;
};

/*
 * the following methods are inlined for speed.
 * Attention : they must be used within a PolyGraphic::childMutex locked section !
 */
inline Warsaw::Tag PolyGraphic::unique_child_id()
{
  Warsaw::Tag localId = 0;
  do
    if (find_if(_children.begin(), _children.end(), localId_eq(localId)) == _children.end())
      return localId;
  while(++localId);
}

inline PolyGraphic::glist_t::iterator PolyGraphic::child_id_to_iterator(Warsaw::Tag localId)
{
  return find_if(_children.begin(), _children.end(), localId_eq(localId));
}

inline CORBA::Long PolyGraphic::child_id_to_index(Warsaw::Tag localId)
{
  return find_if(_children.begin(), _children.end(), localId_eq(localId)) - _children.begin();
}

#endif
<commit_msg>(unique_child_id): Rewritten to silence a compiler warning about control reaching the end of non-void function.<commit_after>/*$Id$
 *
 * This source file is a part of the Berlin Project.
 * Copyright (C) 1999 Stefan Seefeld <stefan@berlin-consortium.org>
 * http://www.berlin-consortium.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
 * MA 02139, USA.
 */
#ifndef _PolyGraphic_hh
#define _PolyGraphic_hh

#include <Berlin/GraphicImpl.hh>
#include <Berlin/Pool.hh>
#include <vector>

class PolyGraphic : public GraphicImpl
{
  class Iterator;
  friend class Iterator;
public:
  PolyGraphic();
  virtual ~PolyGraphic();

  virtual void append_graphic(Warsaw::Graphic_ptr);
  virtual void prepend_graphic(Warsaw::Graphic_ptr);
  virtual void remove_graphic(Warsaw::Tag);
  virtual void remove_child_graphic(Warsaw::Tag);
  virtual Warsaw::Graphic::Iterator_ptr first_child_graphic();
  virtual Warsaw::Graphic::Iterator_ptr last_child_graphic();

  virtual void need_resize();
  virtual void need_resize(Warsaw::Tag);
protected:
  CORBA::Long num_children();
  Warsaw::Tag unique_child_id();
  glist_t::iterator child_id_to_iterator(Warsaw::Tag);
  CORBA::Long child_id_to_index(Warsaw::Tag);
  Warsaw::Graphic::Requisition *children_requests();
  void deallocate_requisitions(Warsaw::Graphic::Requisition *);
  void child_extension(size_t, const Warsaw::Allocation::Info &, Warsaw::Region_ptr);
// private:
  static Pool<Warsaw::Graphic::Requisition> _pool;
  glist_t _children;
  Prague::Mutex _mutex;
};

/*
 * the following methods are inlined for speed.
 * Attention : they must be used within a PolyGraphic::childMutex locked section !
 */
inline Warsaw::Tag PolyGraphic::unique_child_id()
{
  Warsaw::Tag localId;
  for (localId = 0;
       find_if (_children.begin(), _children.end(), localId_eq(localId)) != _children.end();
       localId++);
      return localId;
}

inline PolyGraphic::glist_t::iterator PolyGraphic::child_id_to_iterator(Warsaw::Tag localId)
{
  return find_if(_children.begin(), _children.end(), localId_eq(localId));
}

inline CORBA::Long PolyGraphic::child_id_to_index(Warsaw::Tag localId)
{
  return find_if(_children.begin(), _children.end(), localId_eq(localId)) - _children.begin();
}

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <set>
#include <string>
#include <vector>

#include "object_search_msgs/Label.h"
#include "object_search_msgs/Task.h"
#include "pcl/point_cloud.h"
#include "pcl/point_types.h"
#include "rapid_db/name_db.hpp"
#include "rapid_msgs/LandmarkInfo.h"
#include "rapid_perception/conversions.h"
#include "rapid_perception/pose_estimation.h"
#include "rapid_perception/random_heat_mapper.h"
#include "rapid_ros/publisher.h"
#include "ros/ros.h"
#include "sensor_msgs/PointCloud2.h"
#include "visualization_msgs/Marker.h"

#include "object_search/experiment.h"
#include "object_search/object_search.h"

using object_search::ExperimentDbs;
using rapid::perception::PoseEstimationMatch;
using rapid::perception::PoseEstimator;
using sensor_msgs::PointCloud2;
using visualization_msgs::Marker;
using pcl::PointCloud;
using pcl::PointXYZRGB;

typedef PointCloud<PointXYZRGB> PointC;

void RunExperiment(PoseEstimator* estimator,
                   const std::vector<std::string>& task_list,
                   const ExperimentDbs& dbs);

int main(int argc, char** argv) {
  ros::init(argc, argv, "object_search_experiment");
  ros::NodeHandle nh;

  // Build DBs
  rapid::db::NameDb task_db(nh, "custom_landmarks", "tasks");
  rapid::db::NameDb scene_db(nh, "custom_landmarks", "scenes");
  rapid::db::NameDb scene_cloud_db(nh, "custom_landmarks", "scene_clouds");
  rapid::db::NameDb landmark_db(nh, "custom_landmarks", "landmarks");
  rapid::db::NameDb landmark_cloud_db(nh, "custom_landmarks",
                                      "landmark_clouds");
  ExperimentDbs dbs;
  dbs.task_db = &task_db;
  dbs.scene_db = &scene_db;
  dbs.scene_cloud_db = &scene_cloud_db;
  dbs.landmark_db = &landmark_db;
  dbs.landmark_cloud_db = &landmark_cloud_db;

  // Build estimator
  // Visualization publishers
  ros::Publisher landmark_pub = nh.advertise<PointCloud2>("/landmark", 1, true);
  ros::Publisher scene_pub = nh.advertise<PointCloud2>("/scene", 1, true);
  ros::Publisher heatmap_pub = nh.advertise<PointCloud2>("/heatmap", 1, true);
  ros::Publisher candidates_pub =
      nh.advertise<PointCloud2>("/candidate_samples", 1, true);
  ros::Publisher alignment_pub =
      nh.advertise<PointCloud2>("/alignment", 1, true);
  ros::Publisher output_pub = nh.advertise<PointCloud2>("/output", 1, true);
  rapid_ros::Publisher<Marker> marker_pub(
      nh.advertise<Marker>("/visualization_markers", 1, true));

  rapid::perception::RandomHeatMapper heat_mapper;
  heat_mapper.set_name("random");
  heat_mapper.set_heatmap_publisher(heatmap_pub);
  rapid::perception::PoseEstimator custom(&heat_mapper);
  custom.set_candidates_publisher(candidates_pub);
  custom.set_alignment_publisher(alignment_pub);
  custom.set_marker_publisher(&marker_pub);

  // Read tasks from the parameter server
  std::vector<std::string> task_list;
  nh.getParam("experiment_tasks", task_list);

  RunExperiment(&custom, task_list, dbs);

  ros::spin();
  return 0;
}

void RunExperiment(PoseEstimator* estimator,
                   const std::vector<std::string>& task_list,
                   const ExperimentDbs& dbs) {
  for (size_t task_i = 0; task_i < task_list.size(); ++task_i) {
    const std::string& task_name = task_list[task_i];
    object_search_msgs::Task task;
    if (!dbs.task_db->Get(task_name, &task)) {
      std::cerr << "Error getting task \"" << task_name << "\", skipping."
                << std::endl;
      continue;
    }

    sensor_msgs::PointCloud2 scene_cloud;
    if (!dbs.scene_cloud_db->Get(task.scene_name, &scene_cloud)) {
      std::cerr << "Error getting scene cloud \"" << task.scene_name
                << "\" for task \"" << task_name << "\", skipping."
                << std::endl;
      continue;
    }

    std::set<std::string> landmarks;
    for (size_t li = 0; li < task.labels.size(); ++li) {
      const object_search_msgs::Label& label = task.labels[li];
      landmarks.insert(label.landmark_name);
    }

    for (std::set<std::string>::iterator landmark_name = landmarks.begin();
         landmark_name != landmarks.end(); ++landmark_name) {
      rapid_msgs::LandmarkInfo landmark_info;
      if (!dbs.landmark_db->Get(*landmark_name, &landmark_info)) {
        std::cerr << "Error getting landmark info \"" << *landmark_name
                  << "\" for task \"" << task_name << "\", skipping."
                  << std::endl;
        continue;
      }

      sensor_msgs::PointCloud2 landmark_cloud;
      if (!dbs.landmark_cloud_db->Get(*landmark_name, &landmark_cloud)) {
        std::cerr << "Error getting landmark cloud \"" << *landmark_name
                  << "\" for task \"" << task_name << "\", skipping."
                  << std::endl;
        continue;
      }

      object_search::UpdateEstimatorParams(estimator);

      PointC::Ptr scene = rapid::perception::PclFromRos(scene_cloud);
      estimator->set_scene(scene);
      PointC::Ptr landmark = rapid::perception::PclFromRos(landmark_cloud);
      estimator->set_object(landmark);
      estimator->set_roi(landmark_info.roi);

      std::vector<rapid::perception::PoseEstimationMatch> matches;
      estimator->Find(&matches);

      // Compute precision/recall
      // TODO: complete this
    }
  }
}
<commit_msg>Compute precision/recall of experiment.<commit_after>#include <iostream>
#include <set>
#include <string>
#include <vector>

#include "object_search_msgs/Label.h"
#include "object_search_msgs/Task.h"
#include "pcl/point_cloud.h"
#include "pcl/point_types.h"
#include "rapid_db/name_db.hpp"
#include "rapid_msgs/LandmarkInfo.h"
#include "rapid_perception/conversions.h"
#include "rapid_perception/pose_estimation.h"
#include "rapid_perception/random_heat_mapper.h"
#include "rapid_ros/publisher.h"
#include "ros/ros.h"
#include "sensor_msgs/PointCloud2.h"
#include "visualization_msgs/Marker.h"

#include "object_search/experiment.h"
#include "object_search/object_search.h"

using object_search::ExperimentDbs;
using rapid::perception::PoseEstimationMatch;
using rapid::perception::PoseEstimator;
using sensor_msgs::PointCloud2;
using visualization_msgs::Marker;
using pcl::PointCloud;
using pcl::PointXYZRGB;

typedef PointCloud<PointXYZRGB> PointC;

void RunExperiment(PoseEstimator* estimator,
                   const std::vector<std::string>& task_list,
                   const ExperimentDbs& dbs);
int MatchLabels(const std::vector<object_search_msgs::Label>& labels,
                const PoseEstimationMatch& match);

int main(int argc, char** argv) {
  ros::init(argc, argv, "object_search_experiment");
  ros::NodeHandle nh;

  // Build DBs
  rapid::db::NameDb task_db(nh, "custom_landmarks", "tasks");
  rapid::db::NameDb scene_db(nh, "custom_landmarks", "scenes");
  rapid::db::NameDb scene_cloud_db(nh, "custom_landmarks", "scene_clouds");
  rapid::db::NameDb landmark_db(nh, "custom_landmarks", "landmarks");
  rapid::db::NameDb landmark_cloud_db(nh, "custom_landmarks",
                                      "landmark_clouds");
  ExperimentDbs dbs;
  dbs.task_db = &task_db;
  dbs.scene_db = &scene_db;
  dbs.scene_cloud_db = &scene_cloud_db;
  dbs.landmark_db = &landmark_db;
  dbs.landmark_cloud_db = &landmark_cloud_db;

  // Build estimator
  // Visualization publishers
  ros::Publisher landmark_pub = nh.advertise<PointCloud2>("/landmark", 1, true);
  ros::Publisher scene_pub = nh.advertise<PointCloud2>("/scene", 1, true);
  ros::Publisher heatmap_pub = nh.advertise<PointCloud2>("/heatmap", 1, true);
  ros::Publisher candidates_pub =
      nh.advertise<PointCloud2>("/candidate_samples", 1, true);
  ros::Publisher alignment_pub =
      nh.advertise<PointCloud2>("/alignment", 1, true);
  ros::Publisher output_pub = nh.advertise<PointCloud2>("/output", 1, true);
  rapid_ros::Publisher<Marker> marker_pub(
      nh.advertise<Marker>("/visualization_markers", 1, true));

  rapid::perception::RandomHeatMapper heat_mapper;
  heat_mapper.set_name("random");
  heat_mapper.set_heatmap_publisher(heatmap_pub);
  rapid::perception::PoseEstimator custom(&heat_mapper);
  custom.set_candidates_publisher(candidates_pub);
  custom.set_alignment_publisher(alignment_pub);
  custom.set_marker_publisher(&marker_pub);

  // Read tasks from the parameter server
  std::vector<std::string> task_list;
  nh.getParam("experiment_tasks", task_list);

  RunExperiment(&custom, task_list, dbs);

  return 0;
}

void RunExperiment(PoseEstimator* estimator,
                   const std::vector<std::string>& task_list,
                   const ExperimentDbs& dbs) {
  object_search::ConfusionMatrix results;
  for (size_t task_i = 0; task_i < task_list.size(); ++task_i) {
    const std::string& task_name = task_list[task_i];
    object_search_msgs::Task task;
    if (!dbs.task_db->Get(task_name, &task)) {
      std::cerr << "Error getting task \"" << task_name << "\", skipping."
                << std::endl;
      continue;
    }

    sensor_msgs::PointCloud2 scene_cloud;
    if (!dbs.scene_cloud_db->Get(task.scene_name, &scene_cloud)) {
      std::cerr << "Error getting scene cloud \"" << task.scene_name
                << "\" for task \"" << task_name << "\", skipping."
                << std::endl;
      continue;
    }

    std::set<std::string> landmarks;
    for (size_t li = 0; li < task.labels.size(); ++li) {
      const object_search_msgs::Label& label = task.labels[li];
      landmarks.insert(label.landmark_name);
    }

    object_search::ConfusionMatrix task_results;
    for (std::set<std::string>::iterator landmark_name = landmarks.begin();
         landmark_name != landmarks.end(); ++landmark_name) {
      rapid_msgs::LandmarkInfo landmark_info;
      if (!dbs.landmark_db->Get(*landmark_name, &landmark_info)) {
        std::cerr << "Error getting landmark info \"" << *landmark_name
                  << "\" for task \"" << task_name << "\", skipping."
                  << std::endl;
        continue;
      }

      sensor_msgs::PointCloud2 landmark_cloud;
      if (!dbs.landmark_cloud_db->Get(*landmark_name, &landmark_cloud)) {
        std::cerr << "Error getting landmark cloud \"" << *landmark_name
                  << "\" for task \"" << task_name << "\", skipping."
                  << std::endl;
        continue;
      }

      object_search::UpdateEstimatorParams(estimator);

      double leaf_size = 0.01;
      ros::param::param<double>("leaf_size", leaf_size, 0.01);
      PointC::Ptr scene = rapid::perception::PclFromRos(scene_cloud);
      PointC::Ptr scene_cropped(new PointC);
      object_search::CropScene(scene, scene_cropped);
      PointC::Ptr scene_downsampled(new PointC);
      object_search::Downsample(leaf_size, scene_cropped, scene_downsampled);
      estimator->set_scene(scene_downsampled);

      PointC::Ptr landmark = rapid::perception::PclFromRos(landmark_cloud);
      PointC::Ptr landmark_downsampled(new PointC);
      object_search::Downsample(leaf_size, landmark, landmark_downsampled);
      estimator->set_object(landmark_downsampled);
      estimator->set_roi(landmark_info.roi);

      std::vector<PoseEstimationMatch> matches;
      estimator->Find(&matches);

      // Compute precision/recall
      object_search::ConfusionMatrix landmark_results;
      std::vector<int> found(task.labels.size(), 0);
      for (size_t mi = 0; mi < matches.size(); ++mi) {
        const PoseEstimationMatch& match = matches[mi];
        int label_i = MatchLabels(task.labels, match);
        if (label_i != -1) {
          found[label_i] = 1;
        } else {
          ++landmark_results.fp;
        }
      }

      for (size_t fi = 0; fi < found.size(); ++fi) {
        if (found[fi] == 1) {
          ++landmark_results.tp;
        } else {
          ++landmark_results.fn;
        }
      }
      task_results.Merge(landmark_results);
      std::cout << "  Results for task \"" << task_name << "\", landmark \""
                << *landmark_name << "\"" << std::endl;
      std::cout << " Precision: " << landmark_results.Precision()
                << ", Recall: " << landmark_results.Recall()
                << ", F1: " << landmark_results.F1() << std::endl;
    }
    results.Merge(task_results);
    std::cout << " Task results for \"" << task_name << "\"" << std::endl;
    std::cout << " Precision: " << task_results.Precision()
              << ", Recall: " << task_results.Recall()
              << ", F1: " << task_results.F1() << std::endl;
  }

  std::cout << "Final results:" << std::endl;
  std::cout << "Precision: " << results.Precision()
            << ", Recall: " << results.Recall() << ", F1: " << results.F1()
            << std::endl;
}

int MatchLabels(const std::vector<object_search_msgs::Label>& labels,
                const PoseEstimationMatch& match) {
  const double position_tolerance = 0.01;
  const double orientation_tolerance = 0.04;  // Approx 2 degrees
  for (size_t i = 0; i < labels.size(); ++i) {
    const object_search_msgs::Label& label = labels[i];
    double x_diff = label.pose.position.x - match.pose().position.x;
    double y_diff = label.pose.position.y - match.pose().position.y;
    double z_diff = label.pose.position.z - match.pose().position.z;
    double pos_diff =
        sqrt((x_diff * x_diff) + (y_diff * y_diff) + (z_diff * z_diff));
    Eigen::Quaterniond label_q;
    label_q.w() = label.pose.orientation.w;
    label_q.x() = label.pose.orientation.x;
    label_q.y() = label.pose.orientation.y;
    label_q.z() = label.pose.orientation.z;
    Eigen::Quaterniond match_q;
    match_q.w() = match.pose().orientation.w;
    match_q.x() = match.pose().orientation.x;
    match_q.y() = match.pose().orientation.y;
    match_q.z() = match.pose().orientation.z;
    double ang_diff = label_q.angularDistance(match_q);
    if (pos_diff < position_tolerance && ang_diff < orientation_tolerance) {
      return i;
    }
  }
  return -1;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "mutation.hh"

class mutation_assertion {
    mutation _m;
public:
    mutation_assertion(mutation m)
        : _m(std::move(m))
    { }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_assertion& is_equal_to(const mutation& other, const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        if (ck_ranges) {
            mutation_assertion(_m.sliced(*ck_ranges)).is_equal_to(other.sliced(*ck_ranges));
            return *this;
        }
        if (_m != other) {
            BOOST_FAIL(sprint("Mutations differ, expected %s\n ...but got: %s", other, _m));
        }
        if (other != _m) {
            BOOST_FAIL(sprint("Mutation inequality is not symmetric for %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& is_not_equal_to(const mutation& other) {
        if (_m == other) {
            BOOST_FAIL(sprint("Mutations equal but expected to differ: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& has_schema(schema_ptr s) {
        if (_m.schema() != s) {
            BOOST_FAIL(sprint("Expected mutation of schema %s, but got %s", *s, *_m.schema()));
        }
        return *this;
    }

    mutation_assertion& has_same_continuity(const mutation& other) {
        if (!_m.partition().equal_continuity(*_m.schema(), other.partition())) {
            BOOST_FAIL(sprint("Continuity doesn't match: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    // Verifies that mutation data remains unchanged when upgraded to the new schema
    void is_upgrade_equivalent(schema_ptr new_schema) {
        mutation m2 = _m;
        m2.upgrade(new_schema);
        BOOST_REQUIRE(m2.schema() == new_schema);
        mutation_assertion(m2).is_equal_to(_m);

        mutation m3 = m2;
        m3.upgrade(_m.schema());
        BOOST_REQUIRE(m3.schema() == _m.schema());
        mutation_assertion(m3).is_equal_to(_m);
        mutation_assertion(m3).is_equal_to(m2);
    }
};

static inline
mutation_assertion assert_that(mutation m) {
    return { std::move(m) };
}

static inline
mutation_assertion assert_that(streamed_mutation sm) {
    auto mo = mutation_from_streamed_mutation(std::move(sm)).get0();
    return { std::move(*mo) };
}

class mutation_opt_assertions {
    mutation_opt _mo;
public:
    mutation_opt_assertions(mutation_opt mo) : _mo(std::move(mo)) {}

    mutation_assertion has_mutation() {
        if (!_mo) {
            BOOST_FAIL("Expected engaged mutation_opt, but found not");
        }
        return { *_mo };
    }

    void has_no_mutation() {
        if (_mo) {
            BOOST_FAIL("Expected disengaged mutation_opt");
        }
    }
};

static inline
mutation_opt_assertions assert_that(mutation_opt mo) {
    return { std::move(mo) };
}

static inline
mutation_opt_assertions assert_that(streamed_mutation_opt smo) {
    auto mo = mutation_from_streamed_mutation(std::move(smo)).get0();
    return { std::move(mo) };
}

class streamed_mutation_assertions {
    streamed_mutation _sm;
    clustering_key::equality _ck_eq;
public:
    streamed_mutation_assertions(streamed_mutation sm)
        : _sm(std::move(sm)), _ck_eq(*_sm.schema()) { }

    streamed_mutation_assertions& produces_static_row() {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL("Expected static row, got end of stream");
        }
        if (mfopt->mutation_fragment_kind() != mutation_fragment::kind::static_row) {
            BOOST_FAIL(sprint("Expected static row, got: %s", mfopt->mutation_fragment_kind()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment::kind k, std::vector<int> ck_elements) {
        std::vector<bytes> ck_bytes;
        for (auto&& e : ck_elements) {
            ck_bytes.emplace_back(int32_type->decompose(e));
        }
        auto ck = clustering_key_prefix::from_exploded(*_sm.schema(), std::move(ck_bytes));

        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", ck));
        }
        if (mfopt->mutation_fragment_kind() != k) {
            BOOST_FAIL(sprint("Expected mutation fragment kind %s, got: %s", k, mfopt->mutation_fragment_kind()));
        }
        if (!_ck_eq(mfopt->key(), ck)) {
            BOOST_FAIL(sprint("Expected key %s, got: %s", ck, mfopt->key()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment mf) {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", mf));
        }
        if (!mfopt->equal(*_sm.schema(), mf)) {
            BOOST_FAIL(sprint("Expected %s, but got %s", mf, *mfopt));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(const mutation& m) {
        assert_that(mutation_from_streamed_mutation(_sm).get0()).is_equal_to(m);
        return *this;
    }

    streamed_mutation_assertions& produces_only(const std::deque<mutation_fragment>& fragments) {
        for (auto&& f : fragments) {
            produces(f);
        }
        produces_end_of_stream();
        return *this;
    }

    streamed_mutation_assertions& produces_row_with_key(const clustering_key& ck) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", ck));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected row with key %s, but got end of stream", ck));
        }
        if (!mfo->is_clustering_row()) {
            BOOST_FAIL(sprint("Expected row with key %s, but got %s", ck, *mfo));
        }
        auto& actual = mfo->as_clustering_row().key();
        if (!actual.equal(*_sm.schema(), ck)) {
            BOOST_FAIL(sprint("Expected row with key %s, but key is %s", ck, actual));
        }
        return *this;
    }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    streamed_mutation_assertions& produces_range_tombstone(const range_tombstone& rt, const query::clustering_row_ranges& ck_ranges = {}) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", rt));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got end of stream", rt));
        }
        if (!mfo->is_range_tombstone()) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got %s", rt, *mfo));
        }
        auto& actual = mfo->as_range_tombstone();
        const schema& s = *_sm.schema();
        if (!ck_ranges.empty()) {
            range_tombstone_list actual_list(s);
            range_tombstone_list expected_list(s);
            actual_list.apply(s, actual);
            expected_list.apply(s, rt);
            actual_list.trim(s, ck_ranges);
            expected_list.trim(s, ck_ranges);
            if (!actual_list.equal(s, expected_list)) {
                BOOST_FAIL(sprint("Expected %s, but got %s", expected_list, actual_list));
            }
        } else if (!actual.equal(s, rt)) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got %s", rt, actual));
        }
        return *this;
    }

    streamed_mutation_assertions& fwd_to(const clustering_key& ck1, const clustering_key& ck2) {
        return fwd_to(position_range{
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck1),
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck2)
        });
    }

    streamed_mutation_assertions& fwd_to(position_range range) {
        BOOST_TEST_MESSAGE(sprint("Forwarding to %s", range));
        _sm.fast_forward_to(std::move(range)).get();
        return *this;
    }

    streamed_mutation_assertions& produces_end_of_stream() {
        auto mfopt = _sm().get0();
        if (mfopt) {
            BOOST_FAIL(sprint("Expected end of stream, got: %s", *mfopt));
        }
        return *this;
    }

    void has_monotonic_positions() {
        position_in_partition::less_compare less(*_sm.schema());
        mutation_fragment_opt prev;
        for (;;) {
            mutation_fragment_opt mfo = _sm().get0();
            if (!mfo) {
                break;
            }
            if (prev) {
                if (!less(prev->position(), mfo->position())) {
                    BOOST_FAIL(sprint("previous fragment has greater position: prev=%s, current=%s", *prev, *mfo));
                }
            }
            prev = std::move(mfo);
        }
    }
};

static inline streamed_mutation_assertions assert_that_stream(streamed_mutation sm)
{
    return streamed_mutation_assertions(std::move(sm));
}
<commit_msg>tests: mutation_assertion: Introduce is_continuous()<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "mutation.hh"

class mutation_assertion {
    mutation _m;
public:
    mutation_assertion(mutation m)
        : _m(std::move(m))
    { }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    mutation_assertion& is_equal_to(const mutation& other, const stdx::optional<query::clustering_row_ranges>& ck_ranges = {}) {
        if (ck_ranges) {
            mutation_assertion(_m.sliced(*ck_ranges)).is_equal_to(other.sliced(*ck_ranges));
            return *this;
        }
        if (_m != other) {
            BOOST_FAIL(sprint("Mutations differ, expected %s\n ...but got: %s", other, _m));
        }
        if (other != _m) {
            BOOST_FAIL(sprint("Mutation inequality is not symmetric for %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& is_not_equal_to(const mutation& other) {
        if (_m == other) {
            BOOST_FAIL(sprint("Mutations equal but expected to differ: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& has_schema(schema_ptr s) {
        if (_m.schema() != s) {
            BOOST_FAIL(sprint("Expected mutation of schema %s, but got %s", *s, *_m.schema()));
        }
        return *this;
    }

    mutation_assertion& has_same_continuity(const mutation& other) {
        if (!_m.partition().equal_continuity(*_m.schema(), other.partition())) {
            BOOST_FAIL(sprint("Continuity doesn't match: %s\n ...and: %s", other, _m));
        }
        return *this;
    }

    mutation_assertion& is_continuous(const position_range& r, is_continuous cont = is_continuous::yes) {
        if (!_m.partition().check_continuity(*_m.schema(), r, cont)) {
            BOOST_FAIL(sprint("Expected range %s to be %s in %s", r, cont ? "continuous" : "discontinuous", _m));
        }
        return *this;
    }

    // Verifies that mutation data remains unchanged when upgraded to the new schema
    void is_upgrade_equivalent(schema_ptr new_schema) {
        mutation m2 = _m;
        m2.upgrade(new_schema);
        BOOST_REQUIRE(m2.schema() == new_schema);
        mutation_assertion(m2).is_equal_to(_m);

        mutation m3 = m2;
        m3.upgrade(_m.schema());
        BOOST_REQUIRE(m3.schema() == _m.schema());
        mutation_assertion(m3).is_equal_to(_m);
        mutation_assertion(m3).is_equal_to(m2);
    }
};

static inline
mutation_assertion assert_that(mutation m) {
    return { std::move(m) };
}

static inline
mutation_assertion assert_that(streamed_mutation sm) {
    auto mo = mutation_from_streamed_mutation(std::move(sm)).get0();
    return { std::move(*mo) };
}

class mutation_opt_assertions {
    mutation_opt _mo;
public:
    mutation_opt_assertions(mutation_opt mo) : _mo(std::move(mo)) {}

    mutation_assertion has_mutation() {
        if (!_mo) {
            BOOST_FAIL("Expected engaged mutation_opt, but found not");
        }
        return { *_mo };
    }

    void has_no_mutation() {
        if (_mo) {
            BOOST_FAIL("Expected disengaged mutation_opt");
        }
    }
};

static inline
mutation_opt_assertions assert_that(mutation_opt mo) {
    return { std::move(mo) };
}

static inline
mutation_opt_assertions assert_that(streamed_mutation_opt smo) {
    auto mo = mutation_from_streamed_mutation(std::move(smo)).get0();
    return { std::move(mo) };
}

class streamed_mutation_assertions {
    streamed_mutation _sm;
    clustering_key::equality _ck_eq;
public:
    streamed_mutation_assertions(streamed_mutation sm)
        : _sm(std::move(sm)), _ck_eq(*_sm.schema()) { }

    streamed_mutation_assertions& produces_static_row() {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL("Expected static row, got end of stream");
        }
        if (mfopt->mutation_fragment_kind() != mutation_fragment::kind::static_row) {
            BOOST_FAIL(sprint("Expected static row, got: %s", mfopt->mutation_fragment_kind()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment::kind k, std::vector<int> ck_elements) {
        std::vector<bytes> ck_bytes;
        for (auto&& e : ck_elements) {
            ck_bytes.emplace_back(int32_type->decompose(e));
        }
        auto ck = clustering_key_prefix::from_exploded(*_sm.schema(), std::move(ck_bytes));

        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", ck));
        }
        if (mfopt->mutation_fragment_kind() != k) {
            BOOST_FAIL(sprint("Expected mutation fragment kind %s, got: %s", k, mfopt->mutation_fragment_kind()));
        }
        if (!_ck_eq(mfopt->key(), ck)) {
            BOOST_FAIL(sprint("Expected key %s, got: %s", ck, mfopt->key()));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(mutation_fragment mf) {
        auto mfopt = _sm().get0();
        if (!mfopt) {
            BOOST_FAIL(sprint("Expected mutation fragment %s, got end of stream", mf));
        }
        if (!mfopt->equal(*_sm.schema(), mf)) {
            BOOST_FAIL(sprint("Expected %s, but got %s", mf, *mfopt));
        }
        return *this;
    }

    streamed_mutation_assertions& produces(const mutation& m) {
        assert_that(mutation_from_streamed_mutation(_sm).get0()).is_equal_to(m);
        return *this;
    }

    streamed_mutation_assertions& produces_only(const std::deque<mutation_fragment>& fragments) {
        for (auto&& f : fragments) {
            produces(f);
        }
        produces_end_of_stream();
        return *this;
    }

    streamed_mutation_assertions& produces_row_with_key(const clustering_key& ck) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", ck));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected row with key %s, but got end of stream", ck));
        }
        if (!mfo->is_clustering_row()) {
            BOOST_FAIL(sprint("Expected row with key %s, but got %s", ck, *mfo));
        }
        auto& actual = mfo->as_clustering_row().key();
        if (!actual.equal(*_sm.schema(), ck)) {
            BOOST_FAIL(sprint("Expected row with key %s, but key is %s", ck, actual));
        }
        return *this;
    }

    // If ck_ranges is passed, verifies only that information relevant for ck_ranges matches.
    streamed_mutation_assertions& produces_range_tombstone(const range_tombstone& rt, const query::clustering_row_ranges& ck_ranges = {}) {
        BOOST_TEST_MESSAGE(sprint("Expect %s", rt));
        auto mfo = _sm().get0();
        if (!mfo) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got end of stream", rt));
        }
        if (!mfo->is_range_tombstone()) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got %s", rt, *mfo));
        }
        auto& actual = mfo->as_range_tombstone();
        const schema& s = *_sm.schema();
        if (!ck_ranges.empty()) {
            range_tombstone_list actual_list(s);
            range_tombstone_list expected_list(s);
            actual_list.apply(s, actual);
            expected_list.apply(s, rt);
            actual_list.trim(s, ck_ranges);
            expected_list.trim(s, ck_ranges);
            if (!actual_list.equal(s, expected_list)) {
                BOOST_FAIL(sprint("Expected %s, but got %s", expected_list, actual_list));
            }
        } else if (!actual.equal(s, rt)) {
            BOOST_FAIL(sprint("Expected range tombstone %s, but got %s", rt, actual));
        }
        return *this;
    }

    streamed_mutation_assertions& fwd_to(const clustering_key& ck1, const clustering_key& ck2) {
        return fwd_to(position_range{
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck1),
            position_in_partition(position_in_partition::clustering_row_tag_t(), ck2)
        });
    }

    streamed_mutation_assertions& fwd_to(position_range range) {
        BOOST_TEST_MESSAGE(sprint("Forwarding to %s", range));
        _sm.fast_forward_to(std::move(range)).get();
        return *this;
    }

    streamed_mutation_assertions& produces_end_of_stream() {
        auto mfopt = _sm().get0();
        if (mfopt) {
            BOOST_FAIL(sprint("Expected end of stream, got: %s", *mfopt));
        }
        return *this;
    }

    void has_monotonic_positions() {
        position_in_partition::less_compare less(*_sm.schema());
        mutation_fragment_opt prev;
        for (;;) {
            mutation_fragment_opt mfo = _sm().get0();
            if (!mfo) {
                break;
            }
            if (prev) {
                if (!less(prev->position(), mfo->position())) {
                    BOOST_FAIL(sprint("previous fragment has greater position: prev=%s, current=%s", *prev, *mfo));
                }
            }
            prev = std::move(mfo);
        }
    }
};

static inline streamed_mutation_assertions assert_that_stream(streamed_mutation sm)
{
    return streamed_mutation_assertions(std::move(sm));
}
<|endoftext|>