<commit_before>#include "itkCommandLineArgumentParser.h"
#include "CommandLineArgumentHelper.h"

#include "itkImage.h"
#include "itkResampleImageFilter.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkBSplineInterpolateImageFunction.h"

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

//-------------------------------------------------------------------------------------

/** run: A macro to call a function. */
#define run(function,type,dim) \
if ( PixelType == #type && Dimension == dim ) \
{ \
    typedef itk::Image< type, dim > InputImageType; \
    function< InputImageType >( inputFileName, outputFileName, factorOrSpacing, isFactor, interpolationOrder ); \
}

//-------------------------------------------------------------------------------------

/** Declare ResizeImage. */
template< class InputImageType >
void ResizeImage( std::string inputFileName, std::string outputFileName,
	std::vector<double> factorOrSpacing, bool isFactor,
  unsigned int interpolationOrder );

/** Declare PrintHelp. */
void PrintHelp(void);

//-------------------------------------------------------------------------------------

int main( int argc, char **argv )
{
	/** Check arguments for help. */
	if ( argc < 5 || argc > 13 )
	{
		PrintHelp();
		return 1;
	}

	/** Create a command line argument parser. */
	itk::CommandLineArgumentParser::Pointer parser = itk::CommandLineArgumentParser::New();
	parser->SetCommandLineArguments( argc, argv );

	/** Get arguments. */
	std::string	inputFileName = "";
	bool retin = parser->GetCommandLineArgument( "-in", inputFileName );

	std::string	outputFileName = inputFileName.substr( 0, inputFileName.rfind( "." ) );
	outputFileName += "RESIZED.mhd";
	bool retout = parser->GetCommandLineArgument( "-out", outputFileName );

	std::vector<double> factor;
	bool retf = parser->GetCommandLineArgument( "-f", factor );
	bool isFactor = retf;

	std::vector<double> spacing;
	bool retsp = parser->GetCommandLineArgument( "-sp", spacing );

	unsigned int Dimension = 3;
	bool retdim = parser->GetCommandLineArgument( "-dim", Dimension );

	std::string	PixelType = "short";
	bool retpt = parser->GetCommandLineArgument( "-pt", PixelType );

  unsigned int interpolationOrder = 1;
  bool retio = parser->GetCommandLineArgument( "-io", interpolationOrder );

	/** Check if the required arguments are given. */
	if ( !retin )
	{
		std::cerr << "ERROR: You should specify \"-in\"." << std::endl;
		return 1;
	}
	if ( !( retf ^ retsp ) )
	{
		std::cerr << "ERROR: You should specify either \"-f\" or \"-sp\"." << std::endl;
		return 1;
	}

	/** Get rid of the possible "_" in PixelType. */
	ReplaceUnderscoreWithSpace( PixelType );

	/** Check factor and spacing. */
	if ( retf )
	{
		if( factor.size() != Dimension && factor.size() != 1 )
		{
			std::cout << "ERROR: The number of factors should be 1 or Dimension." << std::endl;
			return 1;
		}
	}
	if ( retsp )
	{
		if( spacing.size() != Dimension && spacing.size() != 1 )
		{
			std::cout << "ERROR: The number of spacings should be 1 or Dimension." << std::endl;
			return 1;
		}
	}

	/** Get the factor or spacing. */
	double vector0 = ( retf ? factor[ 0 ] : spacing[ 0 ] );
	std::vector<double> factorOrSpacing( Dimension, vector0 );
	if ( retf && factor.size() == Dimension )
	{
		for ( unsigned int i = 1; i < Dimension; i++ )
		{
			factorOrSpacing[ i ] = factor[ i ];
		}
	}
	if ( retsp && spacing.size() == Dimension )
	{
		for ( unsigned int i = 1; i < Dimension; i++ )
		{
			factorOrSpacing[ i ] = spacing[ i ];
		}
	}

	/** Check factorOrSpacing for nonpositive numbers. */
	for ( unsigned int i = 0; i < Dimension; i++ )
	{
		if ( factorOrSpacing[ i ] < 0.00001 )
		{
			std::cout << "ERROR: No negative numbers are allowed in factor or spacing." << std::endl;
			return 1;
		}
	}

	/** Run the program. */
	try
	{
		run(ResizeImage,unsigned char,2);
		run(ResizeImage,char,2);
		run(ResizeImage,unsigned short,2);
		run(ResizeImage,short,2);

    run(ResizeImage,unsigned char,3);
		run(ResizeImage,char,3);
		run(ResizeImage,unsigned short,3);
		run(ResizeImage,short,3);

	}
	catch( itk::ExceptionObject &e )
	{
		std::cerr << "Caught ITK exception: " << e << std::endl;
		return 1;
	}

	/** End program. */
	return 0;

} // end main

	/**
	 * ******************* ResizeImage *******************
	 *
	 * The resize function templated over the input pixel type.
	 */

template< class InputImageType >
void ResizeImage( std::string inputFileName, std::string outputFileName,
	std::vector<double> factorOrSpacing, bool isFactor,
  unsigned int interpolationOrder )
{
	/** Typedefs. */
	typedef itk::ResampleImageFilter< InputImageType, InputImageType >	ResamplerType;
	typedef itk::ImageFileReader< InputImageType >			ReaderType;
	typedef itk::ImageFileWriter< InputImageType >			WriterType;
  typedef itk::NearestNeighborInterpolateImageFunction<
    InputImageType, double >                          NNInterpolatorType;
  typedef itk::BSplineInterpolateImageFunction<
    InputImageType >                                  BSplineInterpolatorType;

	typedef typename InputImageType::SizeType					SizeType;
	typedef typename InputImageType::SpacingType			SpacingType;

	const unsigned int Dimension = InputImageType::ImageDimension;

	/** Declarations. */
	typename InputImageType::Pointer inputImage;
	typename ResamplerType::Pointer resampler = ResamplerType::New();
	typename ReaderType::Pointer reader = ReaderType::New();
	typename WriterType::Pointer writer = WriterType::New();
  typename NNInterpolatorType::Pointer nnInterpolator
    = NNInterpolatorType::New();
  typename BSplineInterpolatorType::Pointer bsInterpolator
    = BSplineInterpolatorType::New();

	/** Read in the inputImage. */
	reader->SetFileName( inputFileName.c_str() );
	inputImage = reader->GetOutput();
	inputImage->Update();

	/** Prepare stuff. */
	SpacingType	inputSpacing	= inputImage->GetSpacing();
	SizeType		inputSize			= inputImage->GetLargestPossibleRegion().GetSize();
	SpacingType outputSpacing	= inputSpacing;
	SizeType		outputSize		= inputSize;
	if ( isFactor )
	{
		for ( unsigned int i = 0; i < Dimension; i++ )
		{
			outputSpacing[ i ] /= factorOrSpacing[ i ];
			outputSize[ i ] = static_cast<unsigned int>( outputSize[ i ] * factorOrSpacing[ i ] );
		}
	}
	else
	{
		for ( unsigned int i = 0; i < Dimension; i++ )
		{
			outputSpacing[ i ] = factorOrSpacing[ i ];
			outputSize[ i ] = static_cast<unsigned int>( inputSpacing[ i ] * inputSize[ i ] / factorOrSpacing[ i ] );
		}
	}

	/** Setup the pipeline. */
	resampler->SetInput( inputImage );
	resampler->SetSize( outputSize );
	resampler->SetDefaultPixelValue( 0 );
	resampler->SetOutputStartIndex( inputImage->GetLargestPossibleRegion().GetIndex() );
	resampler->SetOutputSpacing( outputSpacing );
	resampler->SetOutputOrigin( inputImage->GetOrigin() );
  /* The interpolator: the resampler has by default a LinearInterpolateImageFunction
   * as interpolator. */
  if ( interpolationOrder == 0 )
  {
    resampler->SetInterpolator( nnInterpolator );
  }
  else if ( interpolationOrder > 1 )
  {
    bsInterpolator->SetSplineOrder( interpolationOrder );
    resampler->SetInterpolator( bsInterpolator );
  }

	/** Write the output image. */
	writer->SetFileName( outputFileName.c_str() );
	writer->SetInput( resampler->GetOutput() );
	writer->Update();

} // end ResizeImage

	/**
	 * ******************* PrintHelp *******************
	 */
void PrintHelp()
{
	std::cout << "Usage:" << std::endl << "pxresizeimage" << std::endl;
	std::cout << "  -in     inputFilename" << std::endl;
	std::cout << "  [-out]  outputFilename, default in + RESIZED.mhd" << std::endl;
	std::cout << "  [-f]    factor" << std::endl;
	std::cout << "  [-sp]   spacing" << std::endl;
  std::cout << "  [-io]   interpolation order, default 1" << std::endl;
	std::cout << "  [-dim]  dimension, default 3" << std::endl;
	std::cout << "  [-pt]   pixelType, default short" << std::endl;
	std::cout << "One of -f and -sp should be given." << std::endl;
	std::cout << "Supported: 2D, 3D, (unsigned) short, (unsigned) char." << std::endl;
} // end PrintHelp

<commit_msg>MS:<commit_after>#include "itkCommandLineArgumentParser.h"
#include "CommandLineArgumentHelper.h"

#include "itkImage.h"
#include "itkResampleImageFilter.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkBSplineInterpolateImageFunction.h"

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

//-------------------------------------------------------------------------------------

/** run: A macro to call a function. */
#define run(function,type,dim) \
if ( PixelType == #type && Dimension == dim ) \
{ \
    typedef itk::Image< type, dim > InputImageType; \
    function< InputImageType >( inputFileName, outputFileName, factorOrSpacing, isFactor, interpolationOrder ); \
}

//-------------------------------------------------------------------------------------

/** Declare ResizeImage. */
template< class InputImageType >
void ResizeImage( std::string inputFileName, std::string outputFileName,
	std::vector<double> factorOrSpacing, bool isFactor,
  unsigned int interpolationOrder );

/** Declare PrintHelp. */
void PrintHelp(void);

//-------------------------------------------------------------------------------------

int main( int argc, char **argv )
{
	/** Check arguments for help. */
	if ( argc < 5 || argc > 13 )
	{
		PrintHelp();
		return 1;
	}

	/** Create a command line argument parser. */
	itk::CommandLineArgumentParser::Pointer parser = itk::CommandLineArgumentParser::New();
	parser->SetCommandLineArguments( argc, argv );

	/** Get arguments. */
	std::string	inputFileName = "";
	bool retin = parser->GetCommandLineArgument( "-in", inputFileName );

	std::string	outputFileName = inputFileName.substr( 0, inputFileName.rfind( "." ) );
	outputFileName += "RESIZED.mhd";
	bool retout = parser->GetCommandLineArgument( "-out", outputFileName );

	std::vector<double> factor;
	bool retf = parser->GetCommandLineArgument( "-f", factor );
	bool isFactor = retf;

	std::vector<double> spacing;
	bool retsp = parser->GetCommandLineArgument( "-sp", spacing );

	unsigned int Dimension = 3;
	bool retdim = parser->GetCommandLineArgument( "-dim", Dimension );

	std::string	PixelType = "short";
	bool retpt = parser->GetCommandLineArgument( "-pt", PixelType );

  unsigned int interpolationOrder = 1;
  bool retio = parser->GetCommandLineArgument( "-io", interpolationOrder );

	/** Check if the required arguments are given. */
	if ( !retin )
	{
		std::cerr << "ERROR: You should specify \"-in\"." << std::endl;
		return 1;
	}
	if ( !( retf ^ retsp ) )
	{
		std::cerr << "ERROR: You should specify either \"-f\" or \"-sp\"." << std::endl;
		return 1;
	}

	/** Get rid of the possible "_" in PixelType. */
	ReplaceUnderscoreWithSpace( PixelType );

	/** Check factor and spacing. */
	if ( retf )
	{
		if( factor.size() != Dimension && factor.size() != 1 )
		{
			std::cout << "ERROR: The number of factors should be 1 or Dimension." << std::endl;
			return 1;
		}
	}
	if ( retsp )
	{
		if( spacing.size() != Dimension && spacing.size() != 1 )
		{
			std::cout << "ERROR: The number of spacings should be 1 or Dimension." << std::endl;
			return 1;
		}
	}

	/** Get the factor or spacing. */
	double vector0 = ( retf ? factor[ 0 ] : spacing[ 0 ] );
	std::vector<double> factorOrSpacing( Dimension, vector0 );
	if ( retf && factor.size() == Dimension )
	{
		for ( unsigned int i = 1; i < Dimension; i++ )
		{
			factorOrSpacing[ i ] = factor[ i ];
		}
	}
	if ( retsp && spacing.size() == Dimension )
	{
		for ( unsigned int i = 1; i < Dimension; i++ )
		{
			factorOrSpacing[ i ] = spacing[ i ];
		}
	}

	/** Check factorOrSpacing for nonpositive numbers. */
	for ( unsigned int i = 0; i < Dimension; i++ )
	{
		if ( factorOrSpacing[ i ] < 0.00001 )
		{
			std::cout << "ERROR: No negative numbers are allowed in factor or spacing." << std::endl;
			return 1;
		}
	}

	/** Run the program. */
	try
	{
		run( ResizeImage, unsigned char, 2 );
		run( ResizeImage, char, 2 );
		run( ResizeImage, unsigned short, 2 );
		run( ResizeImage, short, 2 );
    run( ResizeImage, unsigned int, 2 );
		run( ResizeImage, int, 2 );
    run( ResizeImage, unsigned long, 2 );
		run( ResizeImage, long, 2 );
    run( ResizeImage, float, 2 );
    run( ResizeImage, double, 2 );

    run( ResizeImage, unsigned char, 3 );
		run( ResizeImage, char, 3 );
		run( ResizeImage, unsigned short, 3 );
		run( ResizeImage, short, 3 );
    run( ResizeImage, unsigned int, 3 );
		run( ResizeImage, int, 3 );
    run( ResizeImage, unsigned long, 3 );
		run( ResizeImage, long, 3 );
    run( ResizeImage, float, 3 );
    run( ResizeImage, double, 3 );

	}
	catch( itk::ExceptionObject &e )
	{
		std::cerr << "Caught ITK exception: " << e << std::endl;
		return 1;
	}

	/** End program. */
	return 0;

} // end main

	/**
	 * ******************* ResizeImage *******************
	 *
	 * The resize function templated over the input pixel type.
	 */

template< class InputImageType >
void ResizeImage( std::string inputFileName, std::string outputFileName,
	std::vector<double> factorOrSpacing, bool isFactor,
  unsigned int interpolationOrder )
{
	/** Typedefs. */
	typedef itk::ResampleImageFilter< InputImageType, InputImageType >	ResamplerType;
	typedef itk::ImageFileReader< InputImageType >			ReaderType;
	typedef itk::ImageFileWriter< InputImageType >			WriterType;
  typedef itk::NearestNeighborInterpolateImageFunction<
    InputImageType, double >                          NNInterpolatorType;
  typedef itk::BSplineInterpolateImageFunction<
    InputImageType >                                  BSplineInterpolatorType;

	typedef typename InputImageType::SizeType					SizeType;
	typedef typename InputImageType::SpacingType			SpacingType;

	const unsigned int Dimension = InputImageType::ImageDimension;

	/** Declarations. */
	typename InputImageType::Pointer inputImage;
	typename ResamplerType::Pointer resampler = ResamplerType::New();
	typename ReaderType::Pointer reader = ReaderType::New();
	typename WriterType::Pointer writer = WriterType::New();
  typename NNInterpolatorType::Pointer nnInterpolator
    = NNInterpolatorType::New();
  typename BSplineInterpolatorType::Pointer bsInterpolator
    = BSplineInterpolatorType::New();

	/** Read in the inputImage. */
	reader->SetFileName( inputFileName.c_str() );
	inputImage = reader->GetOutput();
	inputImage->Update();

	/** Prepare stuff. */
	SpacingType	inputSpacing	= inputImage->GetSpacing();
	SizeType		inputSize			= inputImage->GetLargestPossibleRegion().GetSize();
	SpacingType outputSpacing	= inputSpacing;
	SizeType		outputSize		= inputSize;
	if ( isFactor )
	{
		for ( unsigned int i = 0; i < Dimension; i++ )
		{
			outputSpacing[ i ] /= factorOrSpacing[ i ];
			outputSize[ i ] = static_cast<unsigned int>( outputSize[ i ] * factorOrSpacing[ i ] );
		}
	}
	else
	{
		for ( unsigned int i = 0; i < Dimension; i++ )
		{
			outputSpacing[ i ] = factorOrSpacing[ i ];
			outputSize[ i ] = static_cast<unsigned int>( inputSpacing[ i ] * inputSize[ i ] / factorOrSpacing[ i ] );
		}
	}

	/** Setup the pipeline. */
	resampler->SetInput( inputImage );
	resampler->SetSize( outputSize );
	resampler->SetDefaultPixelValue( 0 );
	resampler->SetOutputStartIndex( inputImage->GetLargestPossibleRegion().GetIndex() );
	resampler->SetOutputSpacing( outputSpacing );
	resampler->SetOutputOrigin( inputImage->GetOrigin() );
  /* The interpolator: the resampler has by default a LinearInterpolateImageFunction
   * as interpolator. */
  if ( interpolationOrder == 0 )
  {
    resampler->SetInterpolator( nnInterpolator );
  }
  else if ( interpolationOrder > 1 )
  {
    bsInterpolator->SetSplineOrder( interpolationOrder );
    resampler->SetInterpolator( bsInterpolator );
  }

	/** Write the output image. */
	writer->SetFileName( outputFileName.c_str() );
	writer->SetInput( resampler->GetOutput() );
	writer->Update();

} // end ResizeImage

	/**
	 * ******************* PrintHelp *******************
	 */
void PrintHelp()
{
	std::cout << "Usage:" << std::endl << "pxresizeimage" << std::endl;
	std::cout << "  -in     inputFilename" << std::endl;
	std::cout << "  [-out]  outputFilename, default in + RESIZED.mhd" << std::endl;
	std::cout << "  [-f]    factor" << std::endl;
	std::cout << "  [-sp]   spacing" << std::endl;
  std::cout << "  [-io]   interpolation order, default 1" << std::endl;
	std::cout << "  [-dim]  dimension, default 3" << std::endl;
	std::cout << "  [-pt]   pixelType, default short" << std::endl;
	std::cout << "One of -f and -sp should be given." << std::endl;
	std::cout << "Supported: 2D, 3D, (unsigned) char, (unsigned) short, (unsigned) int, (unsigned) long, float, double." << std::endl;
} // end PrintHelp

<|endoftext|>


<commit_before>// Copyright (c) 2014-2015 The Dash developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "main.h"
#include "masternode-sync.h"
#include "masternode-payments.h"
#include "masternode.h"
#include "masternodeman.h"
#include "util.h"
#include "addrman.h"

class CMasternodeSync;
CMasternodeSync masternodeSync;

CMasternodeSync::CMasternodeSync()
{
    lastMasternodeList = 0;
    lastMasternodeWinner = 0;
    lastBudgetItem = 0;
    RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
    RequestedMasternodeAttempt = 0;
}

bool CMasternodeSync::IsSynced()
{
    return RequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED;
}

void CMasternodeSync::AddedMasternodeList()
{
    lastMasternodeList = GetTime();
}

void CMasternodeSync::AddedMasternodeWinner()
{
    lastMasternodeWinner = GetTime();
}

void CMasternodeSync::AddedBudgetItem()
{
    lastBudgetItem = GetTime();
}

void CMasternodeSync::GetNextAsset()
{
    switch(RequestedMasternodeAssets)
    {
        case(MASTERNODE_SYNC_INITIAL):
            lastMasternodeList = 0;
            lastMasternodeWinner = 0;
            lastBudgetItem = 0;
            RequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS;
            break;
        case(MASTERNODE_SYNC_SPORKS):
            RequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
            break;
        case(MASTERNODE_SYNC_LIST):
            RequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
            break;
        case(MASTERNODE_SYNC_MNW):
            RequestedMasternodeAssets = MASTERNODE_SYNC_BUDGET;
            break;
        case(MASTERNODE_SYNC_BUDGET):
            LogPrintf("CMasternodeSync::GetNextAsset - Sync has finished\n");
            RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
            break;
    }
    RequestedMasternodeAttempt = 0;
}

void CMasternodeSync::Process()
{
    static int tick = 0;

    if(tick++ % MASTERNODE_SYNC_TIMEOUT != 0) return;

    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return;

    if(IsSynced()) {
        /*
            Resync if we lose all masternodes from sleep/wake or failure to sync originally
        */
        if(mnodeman.CountEnabled() == 0) {
            LOCK(cs_vNodes);
            BOOST_FOREACH(CNode* pnode, vNodes)
            {
                pnode->ClearFulfilledRequest("getspork");
                pnode->ClearFulfilledRequest("mnsync");
                pnode->ClearFulfilledRequest("mnwsync");
                pnode->ClearFulfilledRequest("busync");
            }

            RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
        } else
            return;
    }

    if(fDebug) LogPrintf("CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d\n", tick, RequestedMasternodeAssets);

    if(RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) GetNextAsset();

    LOCK(cs_vNodes);
    BOOST_FOREACH(CNode* pnode, vNodes)
    {
        if(Params().NetworkID() == CBaseChainParams::REGTEST){
            if(RequestedMasternodeAttempt <= 2) {
                pnode->PushMessage("getsporks"); //get current network sporks
            } else if(RequestedMasternodeAttempt < 4) {
                mnodeman.DsegUpdate(pnode);
            } else if(RequestedMasternodeAttempt < 6) {
                int nMnCount = mnodeman.CountEnabled()*2;
                pnode->PushMessage("mnget", nMnCount); //sync payees
                uint256 n = 0;
                pnode->PushMessage("mnvs", n); //sync masternode votes
            } else {
                RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
            }
            RequestedMasternodeAttempt++;
            return;
        }

        //set to synced
        if(RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS){
            if(pnode->HasFulfilledRequest("getspork")) continue;
            pnode->FulfilledRequest("getspork");

            pnode->PushMessage("getsporks"); //get current network sporks
            if(RequestedMasternodeAttempt >= 2) GetNextAsset();
            RequestedMasternodeAttempt++;

            return;
        }

        //don't begin syncing until we're almost at a recent block
        if(pindexPrev->nHeight + 4 < pindexBestHeader->nHeight && pindexPrev->nTime + 600 < GetTime()) return;

        if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) {

            if(RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
                if(fDebug) LogPrintf("CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld\n", lastMasternodeList, GetTime() - MASTERNODE_SYNC_TIMEOUT);
                if(lastMasternodeList > 0 && lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
                    GetNextAsset();
                    return;
                }

                // If it's already more then MASTERNODE_SYNC_TIMEOUT seconds passed since we asked
                // and we still have nothing, assume there is nothing to sync but give it another
                // MASTERNODE_SYNC_TIMEOUT seconds until we move further
                static int64_t lastTimeAsked = 0;
                if(lastMasternodeList == 0  && lastTimeAsked  > 0 && lastTimeAsked < GetTime() - MASTERNODE_SYNC_TIMEOUT) {
                        lastMasternodeList = GetTime();
                }

                if(pnode->HasFulfilledRequest("mnsync")) continue;
                pnode->FulfilledRequest("mnsync");

                if((lastMasternodeList == 0 || lastMasternodeList > GetTime() - MASTERNODE_SYNC_TIMEOUT)
                        && RequestedMasternodeAttempt <= 2){
                    mnodeman.DsegUpdate(pnode);
                    RequestedMasternodeAttempt++;
                    lastTimeAsked = GetTime();
                }
                return;
            }

            if(RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
                if(lastMasternodeWinner > 0 && lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
                    GetNextAsset();
                    return;
                }

                // If it's already more then MASTERNODE_SYNC_TIMEOUT seconds passed since we asked
                // and we still have nothing, assume there is nothing to sync but give it another
                // MASTERNODE_SYNC_TIMEOUT seconds until we move further
                static int64_t lastTimeAsked = 0;
                if(lastMasternodeWinner == 0  && lastTimeAsked  > 0 && lastTimeAsked < GetTime() - MASTERNODE_SYNC_TIMEOUT) {
                        lastMasternodeWinner = GetTime();
                }

                if(pnode->HasFulfilledRequest("mnwsync")) continue;
                pnode->FulfilledRequest("mnwsync");

                if((lastMasternodeWinner == 0 || lastMasternodeWinner > GetTime() - MASTERNODE_SYNC_TIMEOUT)
                        && RequestedMasternodeAttempt <= 4){

                    CBlockIndex* pindexPrev = chainActive.Tip();
                    if(pindexPrev == NULL) return;

                    int nMnCount = mnodeman.CountEnabled()*2;
                    pnode->PushMessage("mnget", nMnCount); //sync payees
                    RequestedMasternodeAttempt++;
                    lastTimeAsked = GetTime();
                }
                return;
            }
        }

        if (pnode->nVersion >= MIN_BUDGET_PEER_PROTO_VERSION) {

            if(RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET){
                if(lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
                    GetNextAsset();
                    return;
                }

                // If it's already more then MASTERNODE_SYNC_TIMEOUT seconds passed since we asked
                // and we still have nothing, assume there is nothing to sync but give it another
                // MASTERNODE_SYNC_TIMEOUT seconds until we move further
                static int64_t lastTimeAsked = 0;
                if(lastBudgetItem == 0  && lastTimeAsked  > 0 && lastTimeAsked < GetTime() - MASTERNODE_SYNC_TIMEOUT) {
                        lastBudgetItem = GetTime();
                }

                if(pnode->HasFulfilledRequest("busync")) continue;
                pnode->FulfilledRequest("busync");

                if((lastBudgetItem == 0 || lastBudgetItem > GetTime() - MASTERNODE_SYNC_TIMEOUT)
                        && RequestedMasternodeAttempt <= 4){
                    uint256 n = 0;
                    pnode->PushMessage("mnvs", n); //sync masternode votes
                    RequestedMasternodeAttempt++;
                    lastTimeAsked = GetTime();
                }
                return;
            }

        }
    }
}
<commit_msg>do not sync while IBD<commit_after>// Copyright (c) 2014-2015 The Dash developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "main.h"
#include "masternode-sync.h"
#include "masternode-payments.h"
#include "masternode.h"
#include "masternodeman.h"
#include "util.h"
#include "addrman.h"

class CMasternodeSync;
CMasternodeSync masternodeSync;

CMasternodeSync::CMasternodeSync()
{
    lastMasternodeList = 0;
    lastMasternodeWinner = 0;
    lastBudgetItem = 0;
    RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
    RequestedMasternodeAttempt = 0;
}

bool CMasternodeSync::IsSynced()
{
    return RequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED;
}

void CMasternodeSync::AddedMasternodeList()
{
    lastMasternodeList = GetTime();
}

void CMasternodeSync::AddedMasternodeWinner()
{
    lastMasternodeWinner = GetTime();
}

void CMasternodeSync::AddedBudgetItem()
{
    lastBudgetItem = GetTime();
}

void CMasternodeSync::GetNextAsset()
{
    switch(RequestedMasternodeAssets)
    {
        case(MASTERNODE_SYNC_INITIAL):
            lastMasternodeList = 0;
            lastMasternodeWinner = 0;
            lastBudgetItem = 0;
            RequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS;
            break;
        case(MASTERNODE_SYNC_SPORKS):
            RequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
            break;
        case(MASTERNODE_SYNC_LIST):
            RequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
            break;
        case(MASTERNODE_SYNC_MNW):
            RequestedMasternodeAssets = MASTERNODE_SYNC_BUDGET;
            break;
        case(MASTERNODE_SYNC_BUDGET):
            LogPrintf("CMasternodeSync::GetNextAsset - Sync has finished\n");
            RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
            break;
    }
    RequestedMasternodeAttempt = 0;
}

void CMasternodeSync::Process()
{
    static int tick = 0;

    if(tick++ % MASTERNODE_SYNC_TIMEOUT != 0) return;

    CBlockIndex* pindexPrev = chainActive.Tip();
    if(pindexPrev == NULL) return;

    if(IsSynced()) {
        /*
            Resync if we lose all masternodes from sleep/wake or failure to sync originally
        */
        if(mnodeman.CountEnabled() == 0) {
            LOCK(cs_vNodes);
            BOOST_FOREACH(CNode* pnode, vNodes)
            {
                pnode->ClearFulfilledRequest("getspork");
                pnode->ClearFulfilledRequest("mnsync");
                pnode->ClearFulfilledRequest("mnwsync");
                pnode->ClearFulfilledRequest("busync");
            }

            RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
        } else
            return;
    }

    if(fDebug) LogPrintf("CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d\n", tick, RequestedMasternodeAssets);

    if(RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) GetNextAsset();

    LOCK(cs_vNodes);
    BOOST_FOREACH(CNode* pnode, vNodes)
    {
        if(Params().NetworkID() == CBaseChainParams::REGTEST){
            if(RequestedMasternodeAttempt <= 2) {
                pnode->PushMessage("getsporks"); //get current network sporks
            } else if(RequestedMasternodeAttempt < 4) {
                mnodeman.DsegUpdate(pnode);
            } else if(RequestedMasternodeAttempt < 6) {
                int nMnCount = mnodeman.CountEnabled()*2;
                pnode->PushMessage("mnget", nMnCount); //sync payees
                uint256 n = 0;
                pnode->PushMessage("mnvs", n); //sync masternode votes
            } else {
                RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
            }
            RequestedMasternodeAttempt++;
            return;
        }

        //set to synced
        if(RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS){
            if(pnode->HasFulfilledRequest("getspork")) continue;
            pnode->FulfilledRequest("getspork");

            pnode->PushMessage("getsporks"); //get current network sporks
            if(RequestedMasternodeAttempt >= 2) GetNextAsset();
            RequestedMasternodeAttempt++;

            return;
        }

        if(IsInitialBlockDownload()) return;

        //don't begin syncing until we're almost at a recent block
        if(pindexPrev->nHeight + 4 < pindexBestHeader->nHeight && pindexPrev->nTime + 600 < GetTime()) return;

        if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) {

            if(RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
                if(fDebug) LogPrintf("CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld\n", lastMasternodeList, GetTime() - MASTERNODE_SYNC_TIMEOUT);
                if(lastMasternodeList > 0 && lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
                    GetNextAsset();
                    return;
                }

                // If it's already more then MASTERNODE_SYNC_TIMEOUT seconds passed since we asked
                // and we still have nothing, assume there is nothing to sync but give it another
                // MASTERNODE_SYNC_TIMEOUT seconds until we move further
                static int64_t lastTimeAsked = 0;
                if(lastMasternodeList == 0  && lastTimeAsked  > 0 && lastTimeAsked < GetTime() - MASTERNODE_SYNC_TIMEOUT) {
                        lastMasternodeList = GetTime();
                }

                if(pnode->HasFulfilledRequest("mnsync")) continue;
                pnode->FulfilledRequest("mnsync");

                if((lastMasternodeList == 0 || lastMasternodeList > GetTime() - MASTERNODE_SYNC_TIMEOUT)
                        && RequestedMasternodeAttempt <= 2){
                    mnodeman.DsegUpdate(pnode);
                    RequestedMasternodeAttempt++;
                    lastTimeAsked = GetTime();
                }
                return;
            }

            if(RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
                if(lastMasternodeWinner > 0 && lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
                    GetNextAsset();
                    return;
                }

                // If it's already more then MASTERNODE_SYNC_TIMEOUT seconds passed since we asked
                // and we still have nothing, assume there is nothing to sync but give it another
                // MASTERNODE_SYNC_TIMEOUT seconds until we move further
                static int64_t lastTimeAsked = 0;
                if(lastMasternodeWinner == 0  && lastTimeAsked  > 0 && lastTimeAsked < GetTime() - MASTERNODE_SYNC_TIMEOUT) {
                        lastMasternodeWinner = GetTime();
                }

                if(pnode->HasFulfilledRequest("mnwsync")) continue;
                pnode->FulfilledRequest("mnwsync");

                if((lastMasternodeWinner == 0 || lastMasternodeWinner > GetTime() - MASTERNODE_SYNC_TIMEOUT)
                        && RequestedMasternodeAttempt <= 4){

                    CBlockIndex* pindexPrev = chainActive.Tip();
                    if(pindexPrev == NULL) return;

                    int nMnCount = mnodeman.CountEnabled()*2;
                    pnode->PushMessage("mnget", nMnCount); //sync payees
                    RequestedMasternodeAttempt++;
                    lastTimeAsked = GetTime();
                }
                return;
            }
        }

        if (pnode->nVersion >= MIN_BUDGET_PEER_PROTO_VERSION) {

            if(RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET){
                if(lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
                    GetNextAsset();
                    return;
                }

                // If it's already more then MASTERNODE_SYNC_TIMEOUT seconds passed since we asked
                // and we still have nothing, assume there is nothing to sync but give it another
                // MASTERNODE_SYNC_TIMEOUT seconds until we move further
                static int64_t lastTimeAsked = 0;
                if(lastBudgetItem == 0  && lastTimeAsked  > 0 && lastTimeAsked < GetTime() - MASTERNODE_SYNC_TIMEOUT) {
                        lastBudgetItem = GetTime();
                }

                if(pnode->HasFulfilledRequest("busync")) continue;
                pnode->FulfilledRequest("busync");

                if((lastBudgetItem == 0 || lastBudgetItem > GetTime() - MASTERNODE_SYNC_TIMEOUT)
                        && RequestedMasternodeAttempt <= 4){
                    uint256 n = 0;
                    pnode->PushMessage("mnvs", n); //sync masternode votes
                    RequestedMasternodeAttempt++;
                    lastTimeAsked = GetTime();
                }
                return;
            }

        }
    }
}
<|endoftext|>


<commit_before>/* Copyright 2012-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#include "make_unique.h"

static int proc_pid;
static uint64_t proc_start_time;

void w_clockspec_init(void) {
  struct timeval tv;

  proc_pid = (int)getpid();
  if (gettimeofday(&tv, NULL) == -1) {
    w_log(W_LOG_FATAL, "gettimeofday failed: %s\n", strerror(errno));
  }
  proc_start_time = (uint64_t)tv.tv_sec;
}

std::unique_ptr<w_clockspec> w_clockspec_new_clock(
    uint32_t root_number,
    uint32_t ticks) {
  auto spec = watchman::make_unique<w_clockspec>();
  spec->tag = w_cs_clock;
  spec->clock.start_time = proc_start_time;
  spec->clock.pid = proc_pid;
  spec->clock.root_number = root_number;
  spec->clock.ticks = ticks;
  return spec;
}

std::unique_ptr<w_clockspec> w_clockspec_parse(json_t* value) {
  const char *str;
  uint64_t start_time;
  int pid;
  uint32_t root_number;
  uint32_t ticks;

  auto spec = watchman::make_unique<w_clockspec>();

  if (json_is_integer(value)) {
    spec->tag = w_cs_timestamp;
    spec->timestamp = (time_t)json_integer_value(value);
    return spec;
  }

  str = json_string_value(value);
  if (!str) {
    return nullptr;
  }

  if (str[0] == 'n' && str[1] == ':') {
    spec->tag = w_cs_named_cursor;
    // spec owns the ref to the string
    spec->named_cursor.cursor = json_to_w_string(value);
    return spec;
  }

  if (sscanf(str, "c:%" PRIu64 ":%d:%" PRIu32 ":%" PRIu32,
             &start_time, &pid, &root_number, &ticks) == 4) {
    spec->tag = w_cs_clock;
    spec->clock.start_time = start_time;
    spec->clock.pid = pid;
    spec->clock.root_number = root_number;
    spec->clock.ticks = ticks;
    return spec;
  }

  if (sscanf(str, "c:%d:%" PRIu32, &pid, &ticks) == 2) {
    // old-style clock value (<= 2.8.2) -- by setting clock time and root number
    // to 0 we guarantee that this is treated as a fresh instance
    spec->tag = w_cs_clock;
    spec->clock.start_time = 0;
    spec->clock.pid = pid;
    spec->clock.root_number = root_number;
    spec->clock.ticks = ticks;
    return spec;
  }

  return nullptr;
}

void w_clockspec_eval_readonly(struct read_locked_watchman_root *lock,
                               const struct w_clockspec *spec,
                               struct w_query_since *since) {
  if (spec == NULL) {
    since->is_timestamp = false;
    since->clock.is_fresh_instance = true;
    since->clock.ticks = 0;
    return;
  }

  if (spec->tag == w_cs_timestamp) {
    // just copy the values over
    since->is_timestamp = true;
    since->timestamp = spec->timestamp;
    return;
  }

  since->is_timestamp = false;

  if (spec->tag == w_cs_named_cursor) {
    w_string cursor = spec->named_cursor.cursor;

    {
      auto cursors = lock->root->inner.cursors.rlock();
      const auto& it = cursors->find(cursor);
      if (it == cursors->end()) {
        since->clock.is_fresh_instance = true;
        since->clock.ticks = 0;
      } else {
        since->clock.ticks = it->second;
        since->clock.is_fresh_instance = since->clock.ticks <
            lock->root->inner.view->getLastAgeOutTickValue();
      }
    }

    w_log(
        W_LOG_DBG,
        "resolved cursor %s -> %" PRIu32 "\n",
        cursor.c_str(),
        since->clock.ticks);
    return;
  }

  // spec->tag == w_cs_clock
  if (spec->clock.start_time == proc_start_time &&
      spec->clock.pid == proc_pid &&
      spec->clock.root_number == lock->root->inner.number) {
    since->clock.is_fresh_instance =
        spec->clock.ticks < lock->root->inner.view->getLastAgeOutTickValue();
    if (since->clock.is_fresh_instance) {
      since->clock.ticks = 0;
    } else {
      since->clock.ticks = spec->clock.ticks;
    }
    return;
  }

  // If the pid, start time or root number don't match, they asked a different
  // incarnation of the server or a different instance of this root, so we treat
  // them as having never spoken to us before
  since->clock.is_fresh_instance = true;
  since->clock.ticks = 0;
}

// must be called with the root locked
// spec can be null, in which case a fresh instance is assumed
void w_clockspec_eval(struct write_locked_watchman_root *lock,
                      const struct w_clockspec *spec,
                      struct w_query_since *since) {
  if (spec == NULL) {
    since->is_timestamp = false;
    since->clock.is_fresh_instance = true;
    since->clock.ticks = 0;
    return;
  }

  if (spec->tag == w_cs_timestamp) {
    // just copy the values over
    since->is_timestamp = true;
    since->timestamp = spec->timestamp;
    return;
  }

  since->is_timestamp = false;

  if (spec->tag == w_cs_named_cursor) {
    w_string cursor = spec->named_cursor.cursor;

    {
      auto wlock = lock->root->inner.cursors.wlock();
      auto& cursors = *wlock;
      auto it = cursors.find(cursor);

      if (it == cursors.end()) {
        since->clock.is_fresh_instance = true;
        since->clock.ticks = 0;
      } else {
        since->clock.ticks = it->second;
        since->clock.is_fresh_instance = since->clock.ticks <
            lock->root->inner.view->getLastAgeOutTickValue();
      }

      // Bump the tick value and record it against the cursor.
      // We need to bump the tick value so that repeated queries
      // when nothing has changed in the filesystem won't continue
      // to return the same set of files; we only want the first
      // of these to return the files and the rest to return nothing
      // until something subsequently changes
      cursors[cursor] = ++lock->root->inner.ticks;
    }

    w_log(
        W_LOG_DBG,
        "resolved cursor %s -> %" PRIu32 "\n",
        cursor.c_str(),
        since->clock.ticks);
    return;
  }

  // spec->tag == w_cs_clock
  if (spec->clock.start_time == proc_start_time &&
      spec->clock.pid == proc_pid &&
      spec->clock.root_number == lock->root->inner.number) {
    since->clock.is_fresh_instance =
        spec->clock.ticks < lock->root->inner.view->getLastAgeOutTickValue();
    if (since->clock.is_fresh_instance) {
      since->clock.ticks = 0;
    } else {
      since->clock.ticks = spec->clock.ticks;
    }
    if (spec->clock.ticks == lock->root->inner.ticks) {
      /* Force ticks to increment.  This avoids returning and querying the
       * same tick value over and over when no files have changed in the
       * meantime */
      lock->root->inner.ticks++;
    }
    return;
  }

  // If the pid, start time or root number don't match, they asked a different
  // incarnation of the server or a different instance of this root, so we treat
  // them as having never spoken to us before
  since->clock.is_fresh_instance = true;
  since->clock.ticks = 0;
}

w_clockspec::w_clockspec() : tag(w_cs_timestamp), timestamp(0) {}

w_clockspec::~w_clockspec() {
  if (tag == w_cs_named_cursor) {
    named_cursor.cursor.reset();
  }
}

bool clock_id_string(uint32_t root_number, uint32_t ticks, char *buf,
                     size_t bufsize) {
  int res = snprintf(buf, bufsize, "c:%" PRIu64 ":%d:%u:%" PRIu32,
                     proc_start_time, proc_pid, root_number, ticks);

  if (res == -1) {
    return false;
  }
  return (size_t)res < bufsize;
}

// Renders the current clock id string to the supplied buffer.
// Must be called with the root locked.
static bool current_clock_id_string(struct read_locked_watchman_root *lock,
                                    char *buf, size_t bufsize) {
  return clock_id_string(
      lock->root->inner.number, lock->root->inner.ticks, buf, bufsize);
}

/* Add the current clock value to the response.
 * must be called with the root locked */
void annotate_with_clock(struct read_locked_watchman_root *lock, json_t *resp) {
  char buf[128];

  if (current_clock_id_string(lock, buf, sizeof(buf))) {
    set_prop(resp, "clock", typed_string_to_json(buf, W_STRING_UNICODE));
  }
}

/* vim:ts=2:sw=2:et:
 */
<commit_msg>reduce dependency on write_locked roots in clockspec code<commit_after>/* Copyright 2012-present Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 */

#include "watchman.h"
#include "make_unique.h"

static int proc_pid;
static uint64_t proc_start_time;

void w_clockspec_init(void) {
  struct timeval tv;

  proc_pid = (int)getpid();
  if (gettimeofday(&tv, NULL) == -1) {
    w_log(W_LOG_FATAL, "gettimeofday failed: %s\n", strerror(errno));
  }
  proc_start_time = (uint64_t)tv.tv_sec;
}

std::unique_ptr<w_clockspec> w_clockspec_new_clock(
    uint32_t root_number,
    uint32_t ticks) {
  auto spec = watchman::make_unique<w_clockspec>();
  spec->tag = w_cs_clock;
  spec->clock.start_time = proc_start_time;
  spec->clock.pid = proc_pid;
  spec->clock.root_number = root_number;
  spec->clock.ticks = ticks;
  return spec;
}

std::unique_ptr<w_clockspec> w_clockspec_parse(json_t* value) {
  const char *str;
  uint64_t start_time;
  int pid;
  uint32_t root_number;
  uint32_t ticks;

  auto spec = watchman::make_unique<w_clockspec>();

  if (json_is_integer(value)) {
    spec->tag = w_cs_timestamp;
    spec->timestamp = (time_t)json_integer_value(value);
    return spec;
  }

  str = json_string_value(value);
  if (!str) {
    return nullptr;
  }

  if (str[0] == 'n' && str[1] == ':') {
    spec->tag = w_cs_named_cursor;
    // spec owns the ref to the string
    spec->named_cursor.cursor = json_to_w_string(value);
    return spec;
  }

  if (sscanf(str, "c:%" PRIu64 ":%d:%" PRIu32 ":%" PRIu32,
             &start_time, &pid, &root_number, &ticks) == 4) {
    spec->tag = w_cs_clock;
    spec->clock.start_time = start_time;
    spec->clock.pid = pid;
    spec->clock.root_number = root_number;
    spec->clock.ticks = ticks;
    return spec;
  }

  if (sscanf(str, "c:%d:%" PRIu32, &pid, &ticks) == 2) {
    // old-style clock value (<= 2.8.2) -- by setting clock time and root number
    // to 0 we guarantee that this is treated as a fresh instance
    spec->tag = w_cs_clock;
    spec->clock.start_time = 0;
    spec->clock.pid = pid;
    spec->clock.root_number = root_number;
    spec->clock.ticks = ticks;
    return spec;
  }

  return nullptr;
}

void w_clockspec_eval_readonly(struct read_locked_watchman_root *lock,
                               const struct w_clockspec *spec,
                               struct w_query_since *since) {
  if (spec == NULL) {
    since->is_timestamp = false;
    since->clock.is_fresh_instance = true;
    since->clock.ticks = 0;
    return;
  }

  if (spec->tag == w_cs_timestamp) {
    // just copy the values over
    since->is_timestamp = true;
    since->timestamp = spec->timestamp;
    return;
  }

  since->is_timestamp = false;

  if (spec->tag == w_cs_named_cursor) {
    w_string cursor = spec->named_cursor.cursor;

    {
      auto cursors = lock->root->inner.cursors.rlock();
      const auto& it = cursors->find(cursor);
      if (it == cursors->end()) {
        since->clock.is_fresh_instance = true;
        since->clock.ticks = 0;
      } else {
        since->clock.ticks = it->second;
        since->clock.is_fresh_instance = since->clock.ticks <
            lock->root->inner.view->getLastAgeOutTickValue();
      }
    }

    w_log(
        W_LOG_DBG,
        "resolved cursor %s -> %" PRIu32 "\n",
        cursor.c_str(),
        since->clock.ticks);
    return;
  }

  // spec->tag == w_cs_clock
  if (spec->clock.start_time == proc_start_time &&
      spec->clock.pid == proc_pid &&
      spec->clock.root_number == lock->root->inner.number) {
    since->clock.is_fresh_instance =
        spec->clock.ticks < lock->root->inner.view->getLastAgeOutTickValue();
    if (since->clock.is_fresh_instance) {
      since->clock.ticks = 0;
    } else {
      since->clock.ticks = spec->clock.ticks;
    }
    return;
  }

  // If the pid, start time or root number don't match, they asked a different
  // incarnation of the server or a different instance of this root, so we treat
  // them as having never spoken to us before
  since->clock.is_fresh_instance = true;
  since->clock.ticks = 0;
}

// must be called with the root locked
// spec can be null, in which case a fresh instance is assumed
void w_clockspec_eval(struct write_locked_watchman_root *lock,
                      const struct w_clockspec *spec,
                      struct w_query_since *since) {
  if (spec == NULL) {
    since->is_timestamp = false;
    since->clock.is_fresh_instance = true;
    since->clock.ticks = 0;
    return;
  }

  if (spec->tag == w_cs_timestamp) {
    // just copy the values over
    since->is_timestamp = true;
    since->timestamp = spec->timestamp;
    return;
  }

  since->is_timestamp = false;

  if (spec->tag == w_cs_named_cursor) {
    w_string cursor = spec->named_cursor.cursor;

    {
      auto wlock = lock->root->inner.cursors.wlock();
      auto& cursors = *wlock;
      auto it = cursors.find(cursor);

      if (it == cursors.end()) {
        since->clock.is_fresh_instance = true;
        since->clock.ticks = 0;
      } else {
        since->clock.ticks = it->second;
        since->clock.is_fresh_instance = since->clock.ticks <
            lock->root->inner.view->getLastAgeOutTickValue();
      }

      // record the current tick value against the cursor so that we use that
      // as the basis for a subsequent query.
      cursors[cursor] = lock->root->inner.view->getMostRecentTickValue();
    }

    w_log(
        W_LOG_DBG,
        "resolved cursor %s -> %" PRIu32 "\n",
        cursor.c_str(),
        since->clock.ticks);
    return;
  }

  // spec->tag == w_cs_clock
  if (spec->clock.start_time == proc_start_time &&
      spec->clock.pid == proc_pid &&
      spec->clock.root_number == lock->root->inner.number) {
    since->clock.is_fresh_instance =
        spec->clock.ticks < lock->root->inner.view->getLastAgeOutTickValue();
    if (since->clock.is_fresh_instance) {
      since->clock.ticks = 0;
    } else {
      since->clock.ticks = spec->clock.ticks;
    }
    return;
  }

  // If the pid, start time or root number don't match, they asked a different
  // incarnation of the server or a different instance of this root, so we treat
  // them as having never spoken to us before
  since->clock.is_fresh_instance = true;
  since->clock.ticks = 0;
}

w_clockspec::w_clockspec() : tag(w_cs_timestamp), timestamp(0) {}

w_clockspec::~w_clockspec() {
  if (tag == w_cs_named_cursor) {
    named_cursor.cursor.reset();
  }
}

bool clock_id_string(uint32_t root_number, uint32_t ticks, char *buf,
                     size_t bufsize) {
  int res = snprintf(buf, bufsize, "c:%" PRIu64 ":%d:%u:%" PRIu32,
                     proc_start_time, proc_pid, root_number, ticks);

  if (res == -1) {
    return false;
  }
  return (size_t)res < bufsize;
}

// Renders the current clock id string to the supplied buffer.
// Must be called with the root locked.
static bool current_clock_id_string(struct read_locked_watchman_root *lock,
                                    char *buf, size_t bufsize) {
  return clock_id_string(
      lock->root->inner.number, lock->root->inner.ticks, buf, bufsize);
}

/* Add the current clock value to the response.
 * must be called with the root locked */
void annotate_with_clock(struct read_locked_watchman_root *lock, json_t *resp) {
  char buf[128];

  if (current_clock_id_string(lock, buf, sizeof(buf))) {
    set_prop(resp, "clock", typed_string_to_json(buf, W_STRING_UNICODE));
  }
}

/* vim:ts=2:sw=2:et:
 */
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2020 Nagisa Sekiguchi
 *
 * 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.
 */

#ifndef YDSH_MISC_STRING_REF_HPP
#define YDSH_MISC_STRING_REF_HPP

#include <string>
#include <cstring>
#include <cassert>

#include "hash.hpp"

namespace ydsh {

/**
 * similar to std::string_view/llvm::StringRef
 */
template <bool T>
class StringRefBase {
public:
    static_assert(T, "not allow instantiation");

    using size_type = std::size_t;

    static constexpr const size_type npos = -1;

private:
    const char *ptr_{nullptr};
    size_type size_{0};

public:
    StringRefBase() noexcept : ptr_(nullptr), size_(0) {}

    StringRefBase(const StringRefBase &ref) noexcept = default;

    /**
     *
     * @param value
     * may be null. if not null, must be null-terminated string.
     */
    StringRefBase(const char *value) : ptr_(value), size_(0) { //NOLINT
        if(this->ptr_) {
            this->size_ = strlen(this->ptr_);
        }
    }

    StringRefBase(const char *value, size_type size) noexcept : ptr_(value), size_(size) {}

    StringRefBase(const std::string &value) noexcept : ptr_(value.c_str()), size_(value.size()) {} //NOLINT

    size_type size() const {
        return this->size_;
    }

    bool empty() const {
        return this->size() == 0;
    }

    const char *data() const {
        return this->ptr_;
    }

    const char *take() {
        const char *tmp = nullptr;
        std::swap(this->ptr_, tmp);
        this->size_ = 0;
        return tmp;
    }

    int compare(StringRefBase ref) const noexcept {
        size_t size = std::min(this->size_, ref.size_);
        int ret = memcmp(this->ptr_, ref.ptr_, size);
        if(ret) {
            return ret;
        }
        if(this->size_ < ref.size_) {
            return -1;
        }
        return this->size_ == ref.size_ ? 0 : 1;
    }

    const char *begin() const {
        return this->ptr_;
    }

    const char *end() const {
        return this->ptr_ + this->size_;
    }

    char operator[](size_type index) const {
        assert(index < this->size_);
        return this->ptr_[index];
    }

    char front() const {
        return (*this)[0];
    }

    char back() const {
        return (*this)[this->size_ - 1];
    }

    StringRefBase substr(size_type pos = 0, size_type size = npos) const {
        assert(pos < this->size());
        size = std::min(this->size() - pos, size);
        return StringRefBase(this->data() + pos, size);
    }

    /**
     *
     * @param startIndex
     * inclusive
     * @param stopIndex
     * exclusive
     * @return
     */
    StringRefBase slice(size_type startIndex, size_type stopIndex) const {
        assert(startIndex <= stopIndex);
        assert(startIndex < this->size_);
        return this->substr(startIndex, stopIndex - startIndex);
    }

    size_type find(StringRefBase ref, size_type pos = 0) const {
        if(pos > this->size_) {
            return npos;
        }
        if(ref.size_ == 0) {
            return pos;
        }
        auto *ret = memmem(this->ptr_ + pos, this->size_ - pos, ref.ptr_, ref.size_);
        return ret != nullptr ? static_cast<const char *>(ret) - this->ptr_ : npos;
    }

    size_type indexOf(StringRefBase ref) const {
        return this->find(ref, 0);
    }

    size_type lastIndexOf(StringRefBase ref) const {
        size_type ret = npos;
        size_type pos = 0;
        do {
            auto tmp = this->find(ref, pos);
            if(tmp == npos) {
                break;
            }
            ret = tmp;
        } while(++pos != this->size_);
        return ret;
    }

    bool startsWith(StringRefBase ref) const {
        return this->size_ >= ref.size_ && memcmp(this->ptr_, ref.ptr_, ref.size_) == 0;
    }

    bool endsWith(StringRefBase ref) const {
        return this->size_ >= ref.size_ &&
            memcmp(this->ptr_ + (this->size_ - ref.size_), ref.ptr_, ref.size_) == 0;
    }

    std::string toString() const {
        return std::string(this->data(), this->size());
    }
};

template <bool T>
constexpr const typename StringRefBase<T>::size_type StringRefBase<T>::npos;

using StringRef = StringRefBase<true>;

inline bool operator==(StringRef left, StringRef right) {
    return left.size() == right.size() && memcmp(left.data(), right.data(), left.size()) == 0;
}

inline bool operator!=(StringRef left, StringRef right) {
    return !(left == right);
}

inline bool operator<(StringRef left, StringRef right) {
    return left.compare(right) < 0;
}

inline bool operator>(StringRef left, StringRef right) {
    return left.compare(right) > 0;
}

inline bool operator<=(StringRef left, StringRef right) {
    return left.compare(right) <= 0;
}

inline bool operator>=(StringRef left, StringRef right) {
    return left.compare(right) >= 0;
}

} // namespace ydsh

namespace std {

template <>
struct hash<ydsh::StringRef> {
    std::size_t operator()(const ydsh::StringRef &ref) const {
        return ydsh::FNVHash64::compute(ref.begin(), ref.end());
    }
};

} // namespace std

#endif //YDSH_MISC_STRING_REF_HPP
<commit_msg>bugfix<commit_after>/*
 * Copyright (C) 2020 Nagisa Sekiguchi
 *
 * 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.
 */

#ifndef YDSH_MISC_STRING_REF_HPP
#define YDSH_MISC_STRING_REF_HPP

#include <string>
#include <cstring>
#include <cassert>

#include "hash.hpp"

namespace ydsh {

/**
 * similar to std::string_view/llvm::StringRef
 */
template <bool T>
class StringRefBase {
public:
    static_assert(T, "not allow instantiation");

    using size_type = std::size_t;

    static constexpr const size_type npos = -1;

private:
    const char *ptr_{nullptr};
    size_type size_{0};

public:
    StringRefBase() noexcept : ptr_(nullptr), size_(0) {}

    StringRefBase(const StringRefBase &ref) noexcept = default;

    /**
     *
     * @param value
     * may be null. if not null, must be null-terminated string.
     */
    StringRefBase(const char *value) : ptr_(value), size_(0) { //NOLINT
        if(this->ptr_) {
            this->size_ = strlen(this->ptr_);
        }
    }

    StringRefBase(const char *value, size_type size) noexcept : ptr_(value), size_(size) {}

    StringRefBase(const std::string &value) noexcept : ptr_(value.c_str()), size_(value.size()) {} //NOLINT

    size_type size() const {
        return this->size_;
    }

    bool empty() const {
        return this->size() == 0;
    }

    const char *data() const {
        return this->ptr_;
    }

    const char *take() {
        const char *tmp = nullptr;
        std::swap(this->ptr_, tmp);
        this->size_ = 0;
        return tmp;
    }

    int compare(StringRefBase ref) const noexcept {
        size_t size = std::min(this->size_, ref.size_);
        int ret = memcmp(this->ptr_, ref.ptr_, size);
        if(ret) {
            return ret;
        }
        if(this->size_ < ref.size_) {
            return -1;
        }
        return this->size_ == ref.size_ ? 0 : 1;
    }

    const char *begin() const {
        return this->ptr_;
    }

    const char *end() const {
        return this->ptr_ + this->size_;
    }

    char operator[](size_type index) const {
        assert(index < this->size_);
        return this->ptr_[index];
    }

    char front() const {
        return (*this)[0];
    }

    char back() const {
        return (*this)[this->size_ - 1];
    }

    StringRefBase substr(size_type pos = 0, size_type size = npos) const {
        assert(pos <= this->size());
        size = std::min(this->size() - pos, size);
        return StringRefBase(this->data() + pos, size);
    }

    /**
     *
     * @param startIndex
     * inclusive
     * @param stopIndex
     * exclusive
     * @return
     */
    StringRefBase slice(size_type startIndex, size_type stopIndex) const {
        assert(startIndex <= stopIndex);
        assert(startIndex <= this->size_);
        return this->substr(startIndex, stopIndex - startIndex);
    }

    size_type find(StringRefBase ref, size_type pos = 0) const {
        if(pos > this->size_) {
            return npos;
        }
        if(ref.size_ == 0) {
            return pos;
        }
        auto *ret = memmem(this->ptr_ + pos, this->size_ - pos, ref.ptr_, ref.size_);
        return ret != nullptr ? static_cast<const char *>(ret) - this->ptr_ : npos;
    }

    size_type indexOf(StringRefBase ref) const {
        return this->find(ref, 0);
    }

    size_type lastIndexOf(StringRefBase ref) const {
        size_type ret = npos;
        size_type pos = 0;
        do {
            auto tmp = this->find(ref, pos);
            if(tmp == npos) {
                break;
            }
            ret = tmp;
        } while(++pos != this->size_);
        return ret;
    }

    bool startsWith(StringRefBase ref) const {
        return this->size_ >= ref.size_ && memcmp(this->ptr_, ref.ptr_, ref.size_) == 0;
    }

    bool endsWith(StringRefBase ref) const {
        return this->size_ >= ref.size_ &&
            memcmp(this->ptr_ + (this->size_ - ref.size_), ref.ptr_, ref.size_) == 0;
    }

    std::string toString() const {
        return std::string(this->data(), this->size());
    }
};

template <bool T>
constexpr const typename StringRefBase<T>::size_type StringRefBase<T>::npos;

using StringRef = StringRefBase<true>;

inline bool operator==(StringRef left, StringRef right) {
    return left.size() == right.size() && memcmp(left.data(), right.data(), left.size()) == 0;
}

inline bool operator!=(StringRef left, StringRef right) {
    return !(left == right);
}

inline bool operator<(StringRef left, StringRef right) {
    return left.compare(right) < 0;
}

inline bool operator>(StringRef left, StringRef right) {
    return left.compare(right) > 0;
}

inline bool operator<=(StringRef left, StringRef right) {
    return left.compare(right) <= 0;
}

inline bool operator>=(StringRef left, StringRef right) {
    return left.compare(right) >= 0;
}

} // namespace ydsh

namespace std {

template <>
struct hash<ydsh::StringRef> {
    std::size_t operator()(const ydsh::StringRef &ref) const {
        return ydsh::FNVHash64::compute(ref.begin(), ref.end());
    }
};

} // namespace std

#endif //YDSH_MISC_STRING_REF_HPP
<|endoftext|>


<commit_before>
/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity compiler.
 */

#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>

using namespace std;
using namespace dev::eth;

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{

bytes compileContract(const string& _sourceCode)
{
	Parser parser;
	ASTPointer<ContractDefinition> contract;
	BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
	NameAndTypeResolver resolver;
	BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));

	Compiler compiler;
	compiler.compileContract(*contract);
	// debug
	//compiler.streamAssembly(cout);
	return compiler.getAssembledBytecode();
}

/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
/// This is necessary since the compiler will add boilerplate add the beginning that is not
/// tested here.
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset)
{
	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size());
	auto checkStart = _compiledCode.begin() + _offset;
	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(),
								  _expectation.begin(), _expectation.end());
}

} // end anonymous namespace

BOOST_AUTO_TEST_SUITE(SolidityCompiler)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { var x = 2; }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 39;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::SWAP1),
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(different_argument_numbers)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a, uint b, uint c) returns(uint d) { return b; }\n"
							 "  function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 76;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize return variable d
					   byte(Instruction::DUP3),
					   byte(Instruction::SWAP1), // assign b to d
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0xa + boilerplateSize, // jump to return
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP4), // store d and fetch return address
					   byte(Instruction::SWAP3), // store return address
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP), // end of f
					   byte(Instruction::JUMPDEST), // beginning of g
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1), // initialized e and h
					   byte(Instruction::PUSH1), 0x20 + boilerplateSize, // ret address
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::PUSH1), 0x1 + boilerplateSize,
					   // stack here: ret e h 0x20 1 2 3 0x1
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   // stack here: ret e h f(1,2,3)
					   byte(Instruction::DUP2),
					   byte(Instruction::POP),
					   byte(Instruction::SWAP1),
					   // stack here: ret e f(1,2,3) h
					   byte(Instruction::POP),
					   byte(Instruction::DUP1), // retrieve it again as "value of expression"
					   byte(Instruction::POP), // end of assignment
					   // stack here: ret e f(1,2,3)
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP1),
					   // ret e f(1,2,3)
					   byte(Instruction::SWAP2),
					   // f(1,2,3) e ret
					   byte(Instruction::JUMP) // end of g
					   });
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(ifStatement)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 39;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1),
					   byte(Instruction::PUSH1), 0x1b + boilerplateSize, // "true" target
					   byte(Instruction::JUMPI),
					   // new check "else if" condition
					   byte(Instruction::DUP1),
					   byte(Instruction::NOT),
					   byte(Instruction::PUSH1), 0x13 + boilerplateSize,
					   byte(Instruction::JUMPI),
					   // "else" body
					   byte(Instruction::PUSH1), 0x4f,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x17 + boilerplateSize, // exit path of second part
					   byte(Instruction::JUMP),
					   // "else if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4e,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1f + boilerplateSize,
					   byte(Instruction::JUMP),
					   // "if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4d,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(loops)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { while(true){1;break;2;continue;3;return;4;} }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 39;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::NOT),
					   byte(Instruction::PUSH1), 0x21 + boilerplateSize,
					   byte(Instruction::JUMPI),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x21 + boilerplateSize,
					   byte(Instruction::JUMP), // break
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x2 + boilerplateSize,
					   byte(Instruction::JUMP), // continue
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x22 + boilerplateSize,
					   byte(Instruction::JUMP), // return
					   byte(Instruction::PUSH1), 0x4,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x2 + boilerplateSize,
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMP)});

	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<commit_msg>Actual contract creator and add solidity to AlethZero interface.<commit_after>
/*
	This file is part of cpp-ethereum.

	cpp-ethereum 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.

	cpp-ethereum 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 cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity compiler.
 */

#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>

using namespace std;
using namespace dev::eth;

namespace dev
{
namespace solidity
{
namespace test
{

namespace
{

bytes compileContract(const string& _sourceCode)
{
	Parser parser;
	ASTPointer<ContractDefinition> contract;
	BOOST_REQUIRE_NO_THROW(contract = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
	NameAndTypeResolver resolver;
	BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));

	Compiler compiler;
	compiler.compileContract(*contract);
	// debug
	//compiler.streamAssembly(cout);
	return compiler.getAssembledBytecode();
}

/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
/// This is necessary since the compiler will add boilerplate add the beginning that is not
/// tested here.
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset)
{
	BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size());
	auto checkStart = _compiledCode.begin() + _offset;
	BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(),
								  _expectation.begin(), _expectation.end());
}

} // end anonymous namespace

BOOST_AUTO_TEST_SUITE(SolidityCompiler)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { var x = 2; }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned boilerplateSize = 51;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize local variable x
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::SWAP1),
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(different_argument_numbers)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a, uint b, uint c) returns(uint d) { return b; }\n"
							 "  function g() returns (uint e, uint h) { h = f(1, 2, 3); }\n"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 76;
	unsigned boilerplateSize = 88;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0, // initialize return variable d
					   byte(Instruction::DUP3),
					   byte(Instruction::SWAP1), // assign b to d
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0xa + shift, // jump to return
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP4), // store d and fetch return address
					   byte(Instruction::SWAP3), // store return address
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP), // end of f
					   byte(Instruction::JUMPDEST), // beginning of g
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1), // initialized e and h
					   byte(Instruction::PUSH1), 0x20 + shift, // ret address
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::PUSH1), 0x1 + shift,
					   // stack here: ret e h 0x20 1 2 3 0x1
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   // stack here: ret e h f(1,2,3)
					   byte(Instruction::DUP2),
					   byte(Instruction::POP),
					   byte(Instruction::SWAP1),
					   // stack here: ret e f(1,2,3) h
					   byte(Instruction::POP),
					   byte(Instruction::DUP1), // retrieve it again as "value of expression"
					   byte(Instruction::POP), // end of assignment
					   // stack here: ret e f(1,2,3)
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::SWAP1),
					   // ret e f(1,2,3)
					   byte(Instruction::SWAP2),
					   // f(1,2,3) e ret
					   byte(Instruction::JUMP) // end of g
					   });
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(ifStatement)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { bool x; if (x) 77; else if (!x) 78; else 79; }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 39;
	unsigned boilerplateSize = 51;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x0,
					   byte(Instruction::DUP1),
					   byte(Instruction::PUSH1), 0x1b + shift, // "true" target
					   byte(Instruction::JUMPI),
					   // new check "else if" condition
					   byte(Instruction::DUP1),
					   byte(Instruction::NOT),
					   byte(Instruction::PUSH1), 0x13 + shift,
					   byte(Instruction::JUMPI),
					   // "else" body
					   byte(Instruction::PUSH1), 0x4f,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x17 + shift, // exit path of second part
					   byte(Instruction::JUMP),
					   // "else if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4e,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1f + shift,
					   byte(Instruction::JUMP),
					   // "if" body
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x4d,
					   byte(Instruction::POP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::POP),
					   byte(Instruction::JUMP)});
	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_CASE(loops)
{
	char const* sourceCode = "contract test {\n"
							 "  function f() { while(true){1;break;2;continue;3;return;4;} }"
							 "}\n";
	bytes code = compileContract(sourceCode);

	unsigned shift = 39;
	unsigned boilerplateSize = 51;
	bytes expectation({byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::NOT),
					   byte(Instruction::PUSH1), 0x21 + shift,
					   byte(Instruction::JUMPI),
					   byte(Instruction::PUSH1), 0x1,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x21 + shift,
					   byte(Instruction::JUMP), // break
					   byte(Instruction::PUSH1), 0x2,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x2 + shift,
					   byte(Instruction::JUMP), // continue
					   byte(Instruction::PUSH1), 0x3,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x22 + shift,
					   byte(Instruction::JUMP), // return
					   byte(Instruction::PUSH1), 0x4,
					   byte(Instruction::POP),
					   byte(Instruction::PUSH1), 0x2 + shift,
					   byte(Instruction::JUMP),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMPDEST),
					   byte(Instruction::JUMP)});

	checkCodePresentAt(code, expectation, boilerplateSize);
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<|endoftext|>


<commit_before>namespace LongestPalindromicSubstring {

    // this is a dp solution, both time and space complexity are O(n^2)
    class Solution1 {
    public:
        string longestPalindrome(string s) {

            int len = s.size();
            bool dp[len][len];
            memset(dp, 0, len * len * sizeof(bool));
            int maxL = 0, start = 0, end = 0;
            for(int i = 0; i< len; i++) {
                for(int j = 0; j < i; j++) {
                    dp[j][i] = (s[j] == s[i] && (i - j < 2 || dp[j + 1][i - 1]));
                    if(dp[j][i] && maxL < (i - j + 1)) {
                        maxL = i - j + 1;
                        start = j;
                        end = i;
                    }
                }
                dp[i][i] =1;
            }
            return s.substr(start, end - start + 1);
        }
    };

    // This solution enumerates every possible center and try to expand it to a palindrome
    // time complexity is O(n^2), space complexity is O(1)
    class Solution {
    public:

        // search palindrome from a center
        void searchPalindrome(string& s, int startPos1, int startPos2, int& start, int& end) {
            int i = startPos1, j = startPos2;
            while (i >= 0 && j < s.size()) {
                if (s[i] == s[j]) {
                    i--;
                    j++;
                } else {
                    break;
                }
            }
            start = (i + 1);
            end = (j - 1);
        }

        string longestPalindrome(string s) {
            if (s.empty()) return s;
            int start, end;
            int maxStart = 0, maxEnd = 0;
            for (int i = 0; i < s.size(); i++) {
                searchPalindrome(s, i, i, start, end); // try search by center s[i]
                if (end - start > maxEnd - maxStart) {
                    maxStart = start;
                    maxEnd = end;
                }

                searchPalindrome(s, i, i + 1, start, end); // try search by gap between s[i], s[i + 1]
                if (end - start > maxEnd - maxStart) {
                    maxStart = start;
                    maxEnd = end;
                }
            }
            return s.substr(maxStart, maxEnd - maxStart + 1);
        }
    };
}

<commit_msg>add Manacher’s Algorithm to find longest palindromic substring<commit_after>namespace LongestPalindromicSubstring {

    // this is a dp solution, both time and space complexity are O(n^2)
    class Solution1 {
    public:
        string longestPalindrome(string s) {

            int len = s.size();
            bool dp[len][len];
            memset(dp, 0, len * len * sizeof(bool));
            int maxL = 0, start = 0, end = 0;
            for(int i = 0; i< len; i++) {
                for(int j = 0; j < i; j++) {
                    dp[j][i] = (s[j] == s[i] && (i - j < 2 || dp[j + 1][i - 1]));
                    if(dp[j][i] && maxL < (i - j + 1)) {
                        maxL = i - j + 1;
                        start = j;
                        end = i;
                    }
                }
                dp[i][i] =1;
            }
            return s.substr(start, end - start + 1);
        }
    };

    // This solution enumerates every possible center and try to expand it to a palindrome
    // time complexity is O(n^2), space complexity is O(1)
    class Solution2 {
    public:

        // search palindrome from a center
        void searchPalindrome(string& s, int startPos1, int startPos2, int& start, int& end) {
            int i = startPos1, j = startPos2;
            while (i >= 0 && j < s.size()) {
                if (s[i] == s[j]) {
                    i--;
                    j++;
                } else {
                    break;
                }
            }
            start = (i + 1);
            end = (j - 1);
        }

        string longestPalindrome(string s) {
            if (s.empty()) return s;
            int start, end;
            int maxStart = 0, maxEnd = 0;
            for (int i = 0; i < s.size(); i++) {
                searchPalindrome(s, i, i, start, end); // try search by center s[i]
                if (end - start > maxEnd - maxStart) {
                    maxStart = start;
                    maxEnd = end;
                }

                searchPalindrome(s, i, i + 1, start, end); // try search by gap between s[i], s[i + 1]
                if (end - start > maxEnd - maxStart) {
                    maxStart = start;
                    maxEnd = end;
                }
            }
            return s.substr(maxStart, maxEnd - maxStart + 1);
        }
    };

    // Manacher’s Algorithm, time complexity is O(n), space complexity is O(n)
    class Solution3 {
    public:

        // Transform S into T.
        // For example, S = "abba", T = "^#a#b#b#a#$".
        // ^ and $ signs are sentinels appended to each end to avoid bounds checking
        string preProcess(string s) {
            int n = s.length();
            if (n == 0) return "^$";
            string ret = "^";
            for (int i = 0; i < n; i++)
            ret += "#" + s.substr(i, 1);

            ret += "#$";
            return ret;
        }

        string longestPalindrome(string s) {
            string T = preProcess(s);
            int n = T.length();
            int *P = new int[n];
            int C = 0, R = 0;
            for (int i = 1; i < n-1; i++) {
                int i_mirror = 2*C-i; // equals to i' = C - (i-C)

                P[i] = (R > i) ? min(R-i, P[i_mirror]) : 0;

                // Attempt to expand palindrome centered at i
                while (T[i + 1 + P[i]] == T[i - 1 - P[i]])
                P[i]++;

                // If palindrome centered at i expand past R,
                // adjust center based on expanded palindrome.
                if (i + P[i] > R) {
                    C = i;
                    R = i + P[i];
                }
            }

            // Find the maximum element in P.
            int maxLen = 0;
            int centerIndex = 0;
            for (int i = 1; i < n-1; i++) {
                if (P[i] > maxLen) {
                    maxLen = P[i];
                    centerIndex = i;
                }
            }
            delete[] P;

            return s.substr((centerIndex - 1 - maxLen)/2, maxLen);
        }
    };
}

<|endoftext|>


<commit_before>#include "apfMPAS.h"
#include <apfMesh2.h>
#include <apfNumbering.h>
#include <diffMC/src/parma_ghostOwner.h>
#include <netcdf>

namespace apf {

using namespace netCDF;

struct MpasFile
{
  ~MpasFile()
  {
    delete [] x;
    delete [] y;
    delete [] z;
    delete [] conn;
  }
  int elements;
  int nodes;
  int nodesPerElement;
  double* x;
  double* y;
  double* z;
/* conn[i * vertexDegree + j] - 1
   is the index of the j'th node
   of element i */
  int* conn;
};

static int readDim(NcFile& f, const char* name)
{
  return f.getDim(name).getSize();
}

static double* readDoubles(NcFile& f, const char* name, int n)
{
  double* a = new double[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

static int* readInts(NcFile& f, const char* name, int n)
{
  int* a = new int[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

void readMpasFile(MpasFile& out, const char* filename)
{
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  out.nodes = readDim(in, "nCells");
  printf("%d nodes\n", out.nodes);
  out.elements = readDim(in, "nVertices");
  printf("%d elements\n", out.elements);
  out.nodesPerElement = readDim(in, "vertexDegree");
  out.x = readDoubles(in, "xCell", out.nodes);
  out.y = readDoubles(in, "yCell", out.nodes);
  out.z = readDoubles(in, "zCell", out.nodes);
  out.conn = readInts(in, "cellsOnVertex", out.elements * out.nodesPerElement);
}

static int getType(int nodesPerElement)
{
  if (nodesPerElement == 3)
    return apf::Mesh::TRIANGLE;
  if (nodesPerElement == 4)
    return apf::Mesh::QUAD;
  abort();
  return 0;
}

void numberInitialNodes(MpasFile& in, apf::Mesh2* out,
    apf::MeshEntity** v)
{
  apf::Numbering* n = apf::createNumbering(out, "mpas_id", out->getShape(), 1);
  for (int i = 0; i < in.nodes; ++i)
    apf::number(n, v[i], 0, 0, i);
}

void buildInitialMesh(MpasFile& in, apf::Mesh2* out)
{
  apf::MeshEntity** v = new apf::MeshEntity* [in.nodes];
/* fake classification for now, deriveMdsModel will fix this up */
  apf::ModelEntity* c = out->findModelEntity(2, 0);
  int t = getType(in.nodesPerElement);
  for (int i = 0; i < in.nodes; ++i)
    v[i] = out->createVert(c);
  for (int i = 0; i < in.nodes; ++i) {
    apf::Vector3 x(in.x[i], in.y[i], in.z[i]);
    out->setPoint(v[i], 0, x);
  }
  for (int i = 0; i < in.elements; ++i) {
    apf::Downward ev;
    for (int j = 0; j < in.nodesPerElement; ++j) {
      int vi = in.conn[i * in.nodesPerElement + j] - 1;
/* zero indices (-1 after conversion) indicate that an MPAS
   vertex does not have an adjacent cell in that direction
   (it is a boundary vertex). In our dual mesh, we simply
   omit that dual element. This is correct and should not
   cause problems. */
      if (vi < 0)
        goto bad_vi;
      assert(vi < in.nodes);
      ev[j] = v[vi];
    }
    apf::buildElement(out, c, t, ev);
bad_vi:
    continue;
  }
  numberInitialNodes(in, out, v);
  delete [] v;
}

void removeIsolatedNodes(apf::Mesh2* m)
{
/* another problem with the dual: MPAS cells without adjacent
   cells become vertices with no adjacent elements in the
   dual mesh, which our codes don't handle.
   We have to give up on these cells, but tell the user about it.
   We also need to be aware of these omitted cells going forward */
  //apf::Numbering* nums = apf::createNumbering(m, "mpas_id", m->getShape(), 1);
  apf::MeshIterator* it = m->begin(0);
  int n = 0;
  apf::MeshEntity* e;
  while ((e = m->iterate(it)))
    if ( ! m->countUpward(e)) {
      /*int num =getNumber(nums, e, 0, 0);
        fprintf(stdout, "Missing vertex with number %d\n",num);
      */
      m->destroy(e);
      ++n;
    }
  m->end(it);
  if (n)
    fprintf(stderr,
        "warning: removed %d isolated nodes from MPAS dual mesh\n",
        n);
}

void loadMpasMesh(apf::Mesh2* m, const char* filename)
{
  assert(PCU_Comm_Peers() == 1);
  MpasFile f;
  readMpasFile(f, filename);
  buildInitialMesh(f, m);
  removeIsolatedNodes(m);
}

void writeMpasAssignments(apf::Mesh2* m, const char* filename) {
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  int numMpasVtx = readDim(in, "nCells");

  apf::Numbering* n = apf::createNumbering(m, "mpas_id", m->getShape(), 1);

  /* collect N/#parts contiguous vertex assignments on each process
     (and deal with any remainders) */
  int numPerPart = numMpasVtx / PCU_Comm_Peers();
  apf::MeshIterator* itr = m->begin(0);
  apf::MeshEntity* e;
  int size;
  if (PCU_Comm_Self()==PCU_Comm_Peers()-1) {
    size=numMpasVtx%numPerPart+numPerPart;
    fprintf(stdout,"mysize: %d, size: %d\n",size,numPerPart);
  }
  else
    size=numPerPart;
  std::vector<int> vtxs(size,-1);
  PCU_Comm_Begin();
  while ((e = m->iterate(itr))) {
    if (!parma::isOwned(m, e))
      continue;
    int num = getNumber(n, e, 0, 0);
    int target = num / numPerPart;
    if (target>=PCU_Comm_Peers())
      target = PCU_Comm_Peers()-1;
    if (target == PCU_Comm_Self())
      vtxs[num%size] = PCU_Comm_Self();
    else
      PCU_COMM_PACK(target,num);
  }
  m->end(itr);

  PCU_Comm_Send();
  while (PCU_Comm_Receive()) {
    int owner =PCU_Comm_Sender();
    int num;
    PCU_COMM_UNPACK(num);
    vtxs[num%size]=owner;
  }

  // assign missing vertices to a random part id
  int count = 0;
  for (int i = 0;
       (i < size);
       i++)
    if (vtxs[i]==-1) {
      vtxs[i] = 0; //to be random
      //fprintf(stdout,"missing vertex %d\n",i+numPerPart*PCU_Comm_Self());
      count++;
    }
  if (count)
    fprintf(stdout,"missing vertices found %d on part %d\n",count,PCU_Comm_Self());

  // use MPI IO to write the contiguous blocks to a single graph.info.part.<#parts> file
  // see https://gist.github.com/cwsmith/166d5beb400f3a8136f7 and the comments
  double startTime=MPI_Wtime();
  MPI_File file;
  char name[32];

  sprintf(name,"graph.info.part.%d",PCU_Comm_Peers());
  MPI_File_open(MPI_COMM_WORLD, name, MPI_MODE_CREATE|MPI_MODE_WRONLY,
		MPI_INFO_NULL, &file);
  MPI_Offset offset = numPerPart*PCU_Comm_Self()*16;
  MPI_File_seek(file, offset, MPI_SEEK_SET);
  MPI_Datatype filetype;
  MPI_Type_contiguous(size,MPI_CHAR,&filetype);
  MPI_Type_commit(&filetype);
  MPI_File_set_view(file,offset,MPI_CHAR,MPI_CHAR,"internal",MPI_INFO_NULL);
  char* str = new char[16*size+1];
  for (int i=0;
       i<size;
       i++) {
    sprintf(str,"%s%-7d %-7d\n",str,vtxs[i],PCU_Comm_Self());
  }
  MPI_Status status;
  MPI_File_write(file,str,strlen(str),MPI_CHAR,&status);

  delete [] str;
  MPI_File_close(&file);
  double totalTime= MPI_Wtime()-startTime;
  PCU_Max_Doubles(&totalTime,1);
  if (!PCU_Comm_Self())
    fprintf(stdout,"File writing time: %f seconds\n", totalTime);
}

}
<commit_msg>attempt to fix mpas_write<commit_after>#include "apfMPAS.h"
#include <apfMesh2.h>
#include <apfNumbering.h>
#include <diffMC/src/parma_ghostOwner.h>
#include <netcdf>

namespace apf {

using namespace netCDF;

struct MpasFile
{
  ~MpasFile()
  {
    delete [] x;
    delete [] y;
    delete [] z;
    delete [] conn;
  }
  int elements;
  int nodes;
  int nodesPerElement;
  double* x;
  double* y;
  double* z;
/* conn[i * vertexDegree + j] - 1
   is the index of the j'th node
   of element i */
  int* conn;
};

static int readDim(NcFile& f, const char* name)
{
  return f.getDim(name).getSize();
}

static double* readDoubles(NcFile& f, const char* name, int n)
{
  double* a = new double[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

static int* readInts(NcFile& f, const char* name, int n)
{
  int* a = new int[n];
  NcVar v = f.getVar(name);
  v.getVar(a);
  return a;
}

void readMpasFile(MpasFile& out, const char* filename)
{
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  out.nodes = readDim(in, "nCells");
  printf("%d nodes\n", out.nodes);
  out.elements = readDim(in, "nVertices");
  printf("%d elements\n", out.elements);
  out.nodesPerElement = readDim(in, "vertexDegree");
  out.x = readDoubles(in, "xCell", out.nodes);
  out.y = readDoubles(in, "yCell", out.nodes);
  out.z = readDoubles(in, "zCell", out.nodes);
  out.conn = readInts(in, "cellsOnVertex", out.elements * out.nodesPerElement);
}

static int getType(int nodesPerElement)
{
  if (nodesPerElement == 3)
    return apf::Mesh::TRIANGLE;
  if (nodesPerElement == 4)
    return apf::Mesh::QUAD;
  abort();
  return 0;
}

void numberInitialNodes(MpasFile& in, apf::Mesh2* out,
    apf::MeshEntity** v)
{
  apf::Numbering* n = apf::createNumbering(out, "mpas_id", out->getShape(), 1);
  for (int i = 0; i < in.nodes; ++i)
    apf::number(n, v[i], 0, 0, i);
}

void buildInitialMesh(MpasFile& in, apf::Mesh2* out)
{
  apf::MeshEntity** v = new apf::MeshEntity* [in.nodes];
/* fake classification for now, deriveMdsModel will fix this up */
  apf::ModelEntity* c = out->findModelEntity(2, 0);
  int t = getType(in.nodesPerElement);
  for (int i = 0; i < in.nodes; ++i)
    v[i] = out->createVert(c);
  for (int i = 0; i < in.nodes; ++i) {
    apf::Vector3 x(in.x[i], in.y[i], in.z[i]);
    out->setPoint(v[i], 0, x);
  }
  for (int i = 0; i < in.elements; ++i) {
    apf::Downward ev;
    for (int j = 0; j < in.nodesPerElement; ++j) {
      int vi = in.conn[i * in.nodesPerElement + j] - 1;
/* zero indices (-1 after conversion) indicate that an MPAS
   vertex does not have an adjacent cell in that direction
   (it is a boundary vertex). In our dual mesh, we simply
   omit that dual element. This is correct and should not
   cause problems. */
      if (vi < 0)
        goto bad_vi;
      assert(vi < in.nodes);
      ev[j] = v[vi];
    }
    apf::buildElement(out, c, t, ev);
bad_vi:
    continue;
  }
  numberInitialNodes(in, out, v);
  delete [] v;
}

void removeIsolatedNodes(apf::Mesh2* m)
{
/* another problem with the dual: MPAS cells without adjacent
   cells become vertices with no adjacent elements in the
   dual mesh, which our codes don't handle.
   We have to give up on these cells, but tell the user about it.
   We also need to be aware of these omitted cells going forward */
  //apf::Numbering* nums = apf::createNumbering(m, "mpas_id", m->getShape(), 1);
  apf::MeshIterator* it = m->begin(0);
  int n = 0;
  apf::MeshEntity* e;
  while ((e = m->iterate(it)))
    if ( ! m->countUpward(e)) {
      /*int num =getNumber(nums, e, 0, 0);
        fprintf(stdout, "Missing vertex with number %d\n",num);
      */
      m->destroy(e);
      ++n;
    }
  m->end(it);
  if (n)
    fprintf(stderr,
        "warning: removed %d isolated nodes from MPAS dual mesh\n",
        n);
}

void loadMpasMesh(apf::Mesh2* m, const char* filename)
{
  assert(PCU_Comm_Peers() == 1);
  MpasFile f;
  readMpasFile(f, filename);
  buildInitialMesh(f, m);
  removeIsolatedNodes(m);
}

void writeMpasAssignments(apf::Mesh2* m, const char* filename) {
  NcFile in(filename, NcFile::read);
  /* this is the dual of a hexagonal mesh,
     hence the reversing of terms */
  int numMpasVtx = readDim(in, "nCells");

  apf::Numbering* n = apf::createNumbering(m, "mpas_id", m->getShape(), 1);

  /* collect N/#parts contiguous vertex assignments on each process
     (and deal with any remainders) */
  int const self = PCU_Comm_Self();
  int const peers = PCU_Comm_Peers();
  int numPerPart = numMpasVtx / peers;
  int size = numPerPart;
  if (self == peers - 1) {
    size += numMpasVtx % numPerPart;
    printf("mysize: %d, size: %d\n", size, numPerPart);
  }
  std::vector<int> vtxs(size, -1);
  PCU_Comm_Begin();
  apf::MeshIterator* itr = m->begin(0);
  apf::MeshEntity* e;
  while ((e = m->iterate(itr))) {
    if (!parma::isOwned(m, e))
      continue;
    int num = getNumber(n, e, 0, 0);
    int target = num / numPerPart;
    assert(target >= 0);
    assert(target <= peers);
    if (target == peers)
      target = peers - 1;
    int local = num - (target * numPerPart);
    /* target may be self, PCU handles that */
    PCU_COMM_PACK(target, local);
  }
  m->end(itr);

  PCU_Comm_Send();
  while (PCU_Comm_Receive()) {
    int owner = PCU_Comm_Sender();
    int local;
    PCU_COMM_UNPACK(local);
    assert(local >= 0);
    assert(local < size);
    vtxs[local]=owner;
  }

  // assign missing vertices to a random part id
  int count = 0;
  for (int i = 0; i < size; i++)
    if (vtxs[i]==-1) {
      vtxs[i] = 0; //to be random
      //fprintf(stdout,"missing vertex %d\n",i+numPerPart*PCU_Comm_Self());
      count++;
    }
  if (count)
    fprintf(stdout,"missing vertices found %d on part %d\n",count,PCU_Comm_Self());

  // use MPI IO to write the contiguous blocks to a single graph.info.part.<#parts> file
  // see https://gist.github.com/cwsmith/166d5beb400f3a8136f7 and the comments
  double startTime=MPI_Wtime();
  MPI_File file;
  char name[32];

  sprintf(name,"graph.info.part.%d",PCU_Comm_Peers());
  MPI_File_open(MPI_COMM_WORLD, name, MPI_MODE_CREATE|MPI_MODE_WRONLY,
		MPI_INFO_NULL, &file);
  MPI_Offset offset = numPerPart*PCU_Comm_Self()*16;
  MPI_File_seek(file, offset, MPI_SEEK_SET);
  MPI_Datatype filetype;
  MPI_Type_contiguous(size,MPI_CHAR,&filetype);
  MPI_Type_commit(&filetype);
  MPI_File_set_view(file,offset,MPI_CHAR,MPI_CHAR,"internal",MPI_INFO_NULL);
  char* str = new char[16*size+1];
  char line[17];
  for (int i=0; i < size; i++) {
    int n = sprintf(line,"%-7d %-7d\n",vtxs[i],PCU_Comm_Self());
    assert(n == 16);
    memcpy(&str[16*i], line, 16);
  }
  MPI_Status status;
  MPI_File_write(file,str,16*size,MPI_CHAR,&status);

  delete [] str;
  MPI_File_close(&file);
  double totalTime= MPI_Wtime()-startTime;
  PCU_Max_Doubles(&totalTime,1);
  if (!PCU_Comm_Self())
    fprintf(stdout,"File writing time: %f seconds\n", totalTime);
}

}
<|endoftext|>