<commit_before>
#include "ofxCvGrayscaleImage.h"
#include "ofxCvColorImage.h"
#include "ofxCvFloatImage.h"

//--------------------------------------------------------------------------------
ofxCvGrayscaleImage::ofxCvGrayscaleImage( const ofxCvGrayscaleImage& mom ) {
    allocate(mom.width, mom.height);
    cvCopy( mom.getCvImage(), cvImage, 0 );
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::allocate( int w, int h ) {

	if (bAllocated == true){
		printf ("warning: reallocating cvImage in ofxCvGrayscaleImage\n");
		clear();
	}

	cvImage = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 1 );
	cvImageTemp	= cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 1 );
	pixels = new unsigned char[w*h];
	width = w;
	height = h;
	bAllocated = true;

    if( bUseTexture ) {
        tex.allocate( width, height, GL_LUMINANCE );
    }
}

// Set Pixel Data - Arrays
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::setFromPixels( unsigned char* _pixels, int w, int h ) {
	for( int i = 0; i < h; i++ ) {
		memcpy( cvImage->imageData+(i*cvImage->widthStep), _pixels+(i*w), w );
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( unsigned char* _pixels ) {
    setFromPixels( _pixels, width, height );
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( const ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
        cvCopy( mom.getCvImage(), cvImage, 0 );
	} else {
        cout << "error in =, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( const ofxCvColorImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvCvtColor( mom.getCvImage(), cvImage, CV_RGB2GRAY );
	} else {
        cout << "error in =, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( const ofxCvFloatImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvConvertScale( mom.getCvImage(), cvImage, 1.0f, 0);
        //cvConvert( mom.getCvImage(), cvImage );  //this should do the same thing
                                                   //and is optimized but cerupcat
                                                   //had problems with it
	} else {
        cout << "error in =, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator -= ( ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvSub( cvImage, mom.getCvImage(), cvImageTemp );
		swapTemp();
	} else {
        cout << "error in -=, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator += ( ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvAdd( cvImage, mom.getCvImage(), cvImageTemp );
		swapTemp();
	} else {
        cout << "error in +=, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator *= ( ofxCvGrayscaleImage& mom ) {
    float scalef = 1.0f / 255.0f;
	if( mom.width == width && mom.height == height ) {
		cvMul( cvImage, mom.getCvImage(), cvImageTemp, scalef );
		swapTemp();
	} else {
        cout << "error in *=, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator &= ( ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvAnd( cvImage, mom.getCvImage(), cvImageTemp );
		swapTemp();
	} else {
        cout << "error in &=, images are different sizes" << endl;
	}
}

//-------------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator -=	( float scalar ){
	cvSubS(cvImage, cvScalar(scalar), cvImageTemp);
	swapTemp();
}

//-------------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator +=	( float scalar ){
	cvAddS(cvImage, cvScalar(scalar), cvImageTemp);
	swapTemp();
}

//-------------------------------------------------------------------------------------
void ofxCvGrayscaleImage::set(int value){
	cvSet(cvImage, cvScalar(value));
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::absDiff( ofxCvGrayscaleImage& mom ) {
    if( mom.width == width && mom.height == height ) {
        cvAbsDiff( cvImage, mom.getCvImage(), cvImageTemp );
        swapTemp();
    } else {
        cout << "error in absDiff, images are different sizes" << endl;
    }
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::absDiff( ofxCvGrayscaleImage& mom,
                                  ofxCvGrayscaleImage& dad ) {
    if(( mom.width == width && mom.height == height ) &&
       ( dad.width == width && dad.height == height )){
        cvAbsDiff( mom.getCvImage(), dad.getCvImage(), cvImage );
    } else {
        cout << "error in absDiff, images are different sizes" << endl;
    }

}

// Get Pixel Data
//--------------------------------------------------------------------------------
unsigned char* ofxCvGrayscaleImage::getPixels() {
	for( int i = 0; i < height; i++ ) {
		memcpy( pixels+(i*width),
                cvImage->imageData+(i*cvImage->widthStep), width );
	}
	return pixels;
}

// Draw Image
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::draw( float x, float y ) {
    if( bUseTexture ) {
        // note, this is a bit ineficient, as we have to
        // copy the data out of the cvImage into the pixel array
        // and then upload to texture.  We should add
        // to the texture class an override for pixelstorei
        // that allows stepped-width image upload:
        tex.loadData(getPixels(), width, height, GL_LUMINANCE);
        tex.draw(x,y,width, height);

    } else {
        IplImage* o;
        o = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
        cvResize( cvImage, o, CV_INTER_NN );
        cvFlip( o, o, 0 );
        glRasterPos3f( x, y+height, 0.0 );
        glDrawPixels( o->width, o->height ,
                     GL_LUMINANCE, GL_UNSIGNED_BYTE, o->imageData );
        cvReleaseImage( &o );
        glRasterPos3f( -x, -(y+height), 0.0 );
    }
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::draw( float x, float y, float w, float h ) {
    if( bUseTexture ) {
        tex.loadData(getPixels(), width, height, GL_LUMINANCE);
        tex.draw(x,y, w,h);

    } else {
        // warning this is gonna be slow !
        IplImage* tempImg;
        tempImg = cvCreateImage( cvSize((int)w, (int)h), IPL_DEPTH_8U, 1 );
        cvResize( cvImage, tempImg, CV_INTER_NN );
        cvFlip( tempImg, tempImg, 0 );
        glRasterPos3f( x, y+h, 0.0 );
        glDrawPixels( tempImg->width, tempImg->height ,
                     GL_LUMINANCE, GL_UNSIGNED_BYTE, tempImg->imageData );
        cvReleaseImage( &tempImg );
        glRasterPos3f( -x, -(y+h), 0.0 );
    }
}

//--------------------------------------------------------------------------------
void  ofxCvGrayscaleImage::drawBlobIntoMe( ofxCvBlob &blob, int color ) {
       if( blob.pts.size() > 0 ) {
           CvPoint* pts = new CvPoint[blob.nPts];
           for( int i=0; i < blob.nPts ; i++ ) {
               pts[i].x = (int)blob.pts[i].x;
               pts[i].y = (int)blob.pts[i].y;
           }
           int nPts = blob.nPts;
           cvFillPoly( cvImage, &pts, &nPts, 1,
                       CV_RGB(color,color,color) );
           delete pts;
       }
}

// Image Filter Operations
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::contrastStretch() {
	double minVal, maxVal;
	cvMinMaxLoc( cvImage, &minVal, &maxVal, NULL, NULL, 0 );
	double scale=1.0f;
	double shift=0;
	if( (maxVal-minVal) != 0 ) {
		scale=255.0/(maxVal-minVal);
    	shift=-minVal*scale;
	}
	cvConvertScale( cvImage, cvImageTemp, scale, shift );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::threshold( int value, bool invert) {
	//http://lush.sourceforge.net/lush-manual/01a8321b.html
	if(invert) cvThreshold( cvImage, cvImageTemp, value, 255, CV_THRESH_BINARY_INV );
	else cvThreshold( cvImage, cvImageTemp, value, 255, CV_THRESH_BINARY );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::invert(){
    cvNot(cvImage, cvImage);
}

// Image Transformation Operations
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::resize( int w, int h ) {

    // note, one image copy operation could be ommitted by
    // reusing the temporal image storage

    IplImage* temp = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 1 );
    cvResize( cvImage, temp );
    clear();
    allocate( w, h );
    cvCopy( temp, cvImage );
    cvReleaseImage( &temp );
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::scaleIntoMe( ofxCvGrayscaleImage& mom, int interpolationMethod){

    if ((interpolationMethod != CV_INTER_NN) &&
        (interpolationMethod != CV_INTER_LINEAR) &&
        (interpolationMethod != CV_INTER_AREA) &&
        (interpolationMethod != CV_INTER_CUBIC) ){
        printf("error in scaleIntoMe / interpolationMethod, setting to CV_INTER_NN \n");
		interpolationMethod = CV_INTER_NN;
	}
    cvResize( mom.getCvImage(), cvImage, interpolationMethod );

    /*
    you can pass in:
    CV_INTER_NN - nearest-neigbor interpolation,
    CV_INTER_LINEAR - bilinear interpolation (used by default)
    CV_INTER_AREA - resampling using pixel area relation. It is preferred method for image decimation that gives moire-free results. In case of zooming it is similar to CV_INTER_NN method.
    CV_INTER_CUBIC - bicubic interpolation.
    ----> http://opencvlibrary.sourceforge.net/CvReference
    */

}

<commit_msg>performance fix: changed cvConvertScale( mom.getCvImage(), cvImage, 1.0f, 0);   TO   cvConvert( mom.getCvImage(), cvImage );  IN  ofxCvGrayscaleImage::operator =<commit_after>
#include "ofxCvGrayscaleImage.h"
#include "ofxCvColorImage.h"
#include "ofxCvFloatImage.h"

//--------------------------------------------------------------------------------
ofxCvGrayscaleImage::ofxCvGrayscaleImage( const ofxCvGrayscaleImage& mom ) {
    allocate(mom.width, mom.height);
    cvCopy( mom.getCvImage(), cvImage, 0 );
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::allocate( int w, int h ) {

	if (bAllocated == true){
		printf ("warning: reallocating cvImage in ofxCvGrayscaleImage\n");
		clear();
	}

	cvImage = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 1 );
	cvImageTemp	= cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 1 );
	pixels = new unsigned char[w*h];
	width = w;
	height = h;
	bAllocated = true;

    if( bUseTexture ) {
        tex.allocate( width, height, GL_LUMINANCE );
    }
}

// Set Pixel Data - Arrays
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::setFromPixels( unsigned char* _pixels, int w, int h ) {
	for( int i = 0; i < h; i++ ) {
		memcpy( cvImage->imageData+(i*cvImage->widthStep), _pixels+(i*w), w );
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( unsigned char* _pixels ) {
    setFromPixels( _pixels, width, height );
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( const ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
        cvCopy( mom.getCvImage(), cvImage, 0 );
	} else {
        cout << "error in =, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( const ofxCvColorImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvCvtColor( mom.getCvImage(), cvImage, CV_RGB2GRAY );
	} else {
        cout << "error in =, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator =	( const ofxCvFloatImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		//cvConvertScale( mom.getCvImage(), cvImage, 1.0f, 0);
        cvConvert( mom.getCvImage(), cvImage );
	} else {
        cout << "error in =, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator -= ( ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvSub( cvImage, mom.getCvImage(), cvImageTemp );
		swapTemp();
	} else {
        cout << "error in -=, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator += ( ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvAdd( cvImage, mom.getCvImage(), cvImageTemp );
		swapTemp();
	} else {
        cout << "error in +=, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator *= ( ofxCvGrayscaleImage& mom ) {
    float scalef = 1.0f / 255.0f;
	if( mom.width == width && mom.height == height ) {
		cvMul( cvImage, mom.getCvImage(), cvImageTemp, scalef );
		swapTemp();
	} else {
        cout << "error in *=, images are different sizes" << endl;
	}
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator &= ( ofxCvGrayscaleImage& mom ) {
	if( mom.width == width && mom.height == height ) {
		cvAnd( cvImage, mom.getCvImage(), cvImageTemp );
		swapTemp();
	} else {
        cout << "error in &=, images are different sizes" << endl;
	}
}

//-------------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator -=	( float scalar ){
	cvSubS(cvImage, cvScalar(scalar), cvImageTemp);
	swapTemp();
}

//-------------------------------------------------------------------------------------
void ofxCvGrayscaleImage::operator +=	( float scalar ){
	cvAddS(cvImage, cvScalar(scalar), cvImageTemp);
	swapTemp();
}

//-------------------------------------------------------------------------------------
void ofxCvGrayscaleImage::set(int value){
	cvSet(cvImage, cvScalar(value));
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::absDiff( ofxCvGrayscaleImage& mom ) {
    if( mom.width == width && mom.height == height ) {
        cvAbsDiff( cvImage, mom.getCvImage(), cvImageTemp );
        swapTemp();
    } else {
        cout << "error in absDiff, images are different sizes" << endl;
    }
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::absDiff( ofxCvGrayscaleImage& mom,
                                  ofxCvGrayscaleImage& dad ) {
    if(( mom.width == width && mom.height == height ) &&
       ( dad.width == width && dad.height == height )){
        cvAbsDiff( mom.getCvImage(), dad.getCvImage(), cvImage );
    } else {
        cout << "error in absDiff, images are different sizes" << endl;
    }

}

// Get Pixel Data
//--------------------------------------------------------------------------------
unsigned char* ofxCvGrayscaleImage::getPixels() {
	for( int i = 0; i < height; i++ ) {
		memcpy( pixels+(i*width),
                cvImage->imageData+(i*cvImage->widthStep), width );
	}
	return pixels;
}

// Draw Image
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::draw( float x, float y ) {
    if( bUseTexture ) {
        // note, this is a bit ineficient, as we have to
        // copy the data out of the cvImage into the pixel array
        // and then upload to texture.  We should add
        // to the texture class an override for pixelstorei
        // that allows stepped-width image upload:
        tex.loadData(getPixels(), width, height, GL_LUMINANCE);
        tex.draw(x,y,width, height);

    } else {
        IplImage* o;
        o = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1 );
        cvResize( cvImage, o, CV_INTER_NN );
        cvFlip( o, o, 0 );
        glRasterPos3f( x, y+height, 0.0 );
        glDrawPixels( o->width, o->height ,
                     GL_LUMINANCE, GL_UNSIGNED_BYTE, o->imageData );
        cvReleaseImage( &o );
        glRasterPos3f( -x, -(y+height), 0.0 );
    }
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::draw( float x, float y, float w, float h ) {
    if( bUseTexture ) {
        tex.loadData(getPixels(), width, height, GL_LUMINANCE);
        tex.draw(x,y, w,h);

    } else {
        // warning this is gonna be slow !
        IplImage* tempImg;
        tempImg = cvCreateImage( cvSize((int)w, (int)h), IPL_DEPTH_8U, 1 );
        cvResize( cvImage, tempImg, CV_INTER_NN );
        cvFlip( tempImg, tempImg, 0 );
        glRasterPos3f( x, y+h, 0.0 );
        glDrawPixels( tempImg->width, tempImg->height ,
                     GL_LUMINANCE, GL_UNSIGNED_BYTE, tempImg->imageData );
        cvReleaseImage( &tempImg );
        glRasterPos3f( -x, -(y+h), 0.0 );
    }
}

//--------------------------------------------------------------------------------
void  ofxCvGrayscaleImage::drawBlobIntoMe( ofxCvBlob &blob, int color ) {
       if( blob.pts.size() > 0 ) {
           CvPoint* pts = new CvPoint[blob.nPts];
           for( int i=0; i < blob.nPts ; i++ ) {
               pts[i].x = (int)blob.pts[i].x;
               pts[i].y = (int)blob.pts[i].y;
           }
           int nPts = blob.nPts;
           cvFillPoly( cvImage, &pts, &nPts, 1,
                       CV_RGB(color,color,color) );
           delete pts;
       }
}

// Image Filter Operations
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::contrastStretch() {
	double minVal, maxVal;
	cvMinMaxLoc( cvImage, &minVal, &maxVal, NULL, NULL, 0 );
	double scale=1.0f;
	double shift=0;
	if( (maxVal-minVal) != 0 ) {
		scale=255.0/(maxVal-minVal);
    	shift=-minVal*scale;
	}
	cvConvertScale( cvImage, cvImageTemp, scale, shift );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::threshold( int value, bool invert) {
	//http://lush.sourceforge.net/lush-manual/01a8321b.html
	if(invert) cvThreshold( cvImage, cvImageTemp, value, 255, CV_THRESH_BINARY_INV );
	else cvThreshold( cvImage, cvImageTemp, value, 255, CV_THRESH_BINARY );
	swapTemp();
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::invert(){
    cvNot(cvImage, cvImage);
}

// Image Transformation Operations
//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::resize( int w, int h ) {

    // note, one image copy operation could be ommitted by
    // reusing the temporal image storage

    IplImage* temp = cvCreateImage( cvSize(w,h), IPL_DEPTH_8U, 1 );
    cvResize( cvImage, temp );
    clear();
    allocate( w, h );
    cvCopy( temp, cvImage );
    cvReleaseImage( &temp );
}

//--------------------------------------------------------------------------------
void ofxCvGrayscaleImage::scaleIntoMe( ofxCvGrayscaleImage& mom, int interpolationMethod){

    if ((interpolationMethod != CV_INTER_NN) &&
        (interpolationMethod != CV_INTER_LINEAR) &&
        (interpolationMethod != CV_INTER_AREA) &&
        (interpolationMethod != CV_INTER_CUBIC) ){
        printf("error in scaleIntoMe / interpolationMethod, setting to CV_INTER_NN \n");
		interpolationMethod = CV_INTER_NN;
	}
    cvResize( mom.getCvImage(), cvImage, interpolationMethod );

    /*
    you can pass in:
    CV_INTER_NN - nearest-neigbor interpolation,
    CV_INTER_LINEAR - bilinear interpolation (used by default)
    CV_INTER_AREA - resampling using pixel area relation. It is preferred method for image decimation that gives moire-free results. In case of zooming it is similar to CV_INTER_NN method.
    CV_INTER_CUBIC - bicubic interpolation.
    ----> http://opencvlibrary.sourceforge.net/CvReference
    */

}

<|endoftext|>


<commit_before>#include "npc_system.h"
#include "../algos/algorithm.h"
#include "../algos/los_algorithm.h"
#include "../components/collider_component.h"
#include "../components/description_component.h"
#include "../components/npc_component.h"
#include "../components/player_component.h"
#include <cmath>
#include <glog/logging.h>
#include <iostream>

namespace {
auto getDistance = [](const Location& start, const Location& end, void* c = 0) {
    int xdist = start.x - end.x;
    int ydist = start.y - end.y;
    return (abs(xdist) + abs(ydist));
};

} // namespace

NpcSystem::NpcSystem() {
    createHumanStateMachine();
    createDogStateMachine();
}

void NpcSystem::createHumanStateMachine() {
    StateMachine human;

    State NoneState;
    Transition NoneToIdle;
    NoneToIdle.condition = [&](EntityId e, NpcComponent* n) { return true; };
    NoneToIdle.endState = "Idle";
    NoneState.transitions.push_back(NoneToIdle);
    human[""] = NoneState;

    State IdleState;
    Transition IdleToSeeking;
    IdleToSeeking.condition = [&](EntityId e, NpcComponent* n) { return true; };
    IdleToSeeking.endState = "Seeking";
    IdleState.transitions.push_back(IdleToSeeking);
    human["Idle"] = IdleState;

    State SeekingState;
    Transition SeekingToMoving;
    SeekingToMoving.condition = [&](EntityId e, NpcComponent* n) {
        return n->target != 0;
    };
    SeekingToMoving.endState = "Moving";
    SeekingState.transitions.push_back(SeekingToMoving);
    SeekingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        n->target = findNearestVisibleMatching(entities()->getLocation(e),
                                               n->losDistance,
                                               n->attribs["seek_target"]);
    };
    human["Seeking"] = SeekingState;

    State MovingState;
    Transition MovingToAttacking;
    MovingToAttacking.condition = [&](EntityId e, NpcComponent* n) {
        return canAttackTarget(e, n);
    };
    MovingToAttacking.endState = "Attacking";
    MovingState.transitions.push_back(MovingToAttacking);
    MovingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        setPathToTarget(e, n->target, n);
        if (!n->path.empty()) {
            events()->fire(std::make_shared<MoveEntityEvent>(e, n->path[0]));
            n->path.erase(n->path.begin());
        }
    };
    human["Moving"] = MovingState;

    State AttackingState;
    Transition AttackingNotPossible;
    AttackingNotPossible.condition = [&](EntityId e, NpcComponent* n) {
        return !canAttackTarget(e, n);
    };
    AttackingNotPossible.endState = "Seeking";
    AttackingState.transitions.push_back(AttackingNotPossible);
    AttackingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        events()->fire(std::make_shared<AttackEntityEvent>(e, n->target));
    };
    AttackingState.onLeave = [&](EntityId e, NpcComponent* n) {
        n->target = 0;
    };
    human["Attacking"] = AttackingState;
    m_stateMachines["human"] = human;
}

void NpcSystem::createDogStateMachine() {
    StateMachine dog;

    State NoneState;
    Transition NoneToIdle;
    NoneToIdle.condition = [](EntityId e, NpcComponent* n) { return true; };
    NoneToIdle.endState = "Idle";
    NoneState.transitions.push_back(NoneToIdle);
    dog[""] = NoneState;

    State IdleState;
    Transition IdleToSeeking;
    IdleToSeeking.condition = [&](EntityId e, NpcComponent* n) {
        // When human is too far away - 5 tiles
        return 0 == findNearestVisibleMatching(entities()->getLocation(e), 3,
                                               n->attribs["seek_target"]);
        ;
    };
    IdleToSeeking.endState = "Seeking";
    IdleState.transitions.push_back(IdleToSeeking);
    dog["Idle"] = IdleState;

    State SeekingState;
    Transition SeekingToMoving;
    SeekingToMoving.condition = [](EntityId e, NpcComponent* n) {
        return true;
    };
    SeekingToMoving.endState = "Moving";
    SeekingState.transitions.push_back(SeekingToMoving);
    SeekingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        n->target = findNearestVisibleMatching(entities()->getLocation(e),
                                               n->losDistance,
                                               n->attribs["seek_target"]);
    };
    dog["Seeking"] = SeekingState;

    State MovingState;
    Transition MovingToIdle;
    MovingToIdle.condition = [&](EntityId e, NpcComponent* n) {
        // When human is too far away - x tiles
        return 0 != findNearestVisibleMatching(entities()->getLocation(e), 3,
                                               n->attribs["seek_target"]);
        ;
    };
    MovingToIdle.endState = "Idle";
    MovingState.transitions.push_back(MovingToIdle);
    MovingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        setPathToTarget(e, n->target, n);
        if (!n->path.empty()) {
            events()->fire(std::make_shared<MoveEntityEvent>(e, n->path[0]));
            n->path.erase(n->path.begin());
        }
    };
    dog["Moving"] = MovingState;

    m_stateMachines["dog"] = dog;
}

void NpcSystem::onTurn() {
    for (EntityId entity : entities()->all()) {
        NpcComponent* npc = components()->get<NpcComponent>(entity);
        if (npc == 0)
            continue;

        State currentState = m_stateMachines[npc->stateMachine][npc->state];
        for (Transition& transition : currentState.transitions) {
            if (transition.condition(entity, npc)) {
                LOG(INFO) << "Changing state from <" << npc->state << "> to <"
                          << transition.endState << "> for " << entity
                          << std::endl;
                if (currentState.onLeave) {
                    currentState.onLeave(entity, npc);
                }
                npc->state = transition.endState;
                currentState = m_stateMachines[npc->stateMachine][npc->state];
                if (currentState.onEntry) {
                    currentState.onEntry(entity, npc);
                }
                break;
            }
        }
        if (currentState.onUpdate) {
            currentState.onUpdate(entity, npc);
        }
    }
}

EntityId NpcSystem::findNearestVisibleMatching(const Location& location,
                                               unsigned int radius,
                                               const std::string& name) {
    EntityId retval = 0;
    unsigned int minDist = 1000.0;
    EntityHolder entities = map()->findEntitiesNear(location, radius);
    for (EntityId entity : entities) {
        unsigned int dist =
            getDistance(location, this->entities()->getLocation(entity));
        auto* desc = components()->get<DescriptionComponent>(entity);
        if (desc == 0)
            continue;
        if (desc->title == name && dist < minDist) {
            retval = entity;
            minDist = dist;
        }
    }
    return retval;
}

void NpcSystem::setPathToTarget(EntityId entity, EntityId target,
                                NpcComponent* npc) {
    auto getPathCost = [&](const Location& location, void* c) {
        auto player = components()->getUnique<PlayerComponent>();

        for (EntityId entity : map()->getTile(location).entities()) {
            if (entity == player.id) {
                continue;
            }
            if (components()->get<ColliderComponent>(entity)) {
                return 99;
            }
        }
        return 1;
    };
    auto findNeighbours4 = [&](const Location& location, Location* neighbours,
                               void* c) {
        unsigned int count = 0;
        Location neighbour = location;
        int xAdj[] = {-1, 1, 0, 0};
        int yAdj[] = {0, 0, -1, 1};

        for (unsigned int ii = 0; ii < 4; ii++) {
            neighbour = location;
            neighbour.x += xAdj[ii];
            neighbour.y += yAdj[ii];
            if (map()->isValidTile(neighbour)) {
                if (getPathCost(neighbour, 0) > 0)
                    neighbours[count++] = neighbour;
            }
        }
        return count;
    };

    Algorithm algo;
    algo.setCostFunction(getPathCost);
    algo.setDistanceFunction(getDistance);
    algo.setNeighbourFunction(findNeighbours4);
    algo.setNumNeighbours(4);

    PathVector l_path;
    algo.findPath(entities()->getLocation(entity),
                  entities()->getLocation(target), l_path);

    if (l_path.empty()) {
        return;
    }

    // Reset path
    npc->path.clear();
    for (unsigned int ii = 0; ii < l_path.size(); ii++) {
        npc->path.push_back(l_path[ii]);
        // std::cout << "Step " << ii << ": " << tempLoc << std::endl;
    }
}

bool NpcSystem::canAttackTarget(EntityId entity, NpcComponent* npc) {
    Location location = entities()->getLocation(entity);
    for (EntityId iter : map()->findEntitiesNear(location, 1)) {
        // LOG(INFO) << "Potential: " << iter << " v " << npc->target <<
        // std::endl;
        if (iter == npc->target) { // TODO use std::find_if instead
            Location oLoc = entities()->getLocation(iter);
            if (location.x != oLoc.x && location.y != oLoc.y)
                continue;
            return true;
        }
    }
    return false;
}<commit_msg>use `find_if` for `canAttackTarget`<commit_after>#include "npc_system.h"
#include "../algos/algorithm.h"
#include "../algos/los_algorithm.h"
#include "../components/collider_component.h"
#include "../components/description_component.h"
#include "../components/npc_component.h"
#include "../components/player_component.h"
#include <algorithm>
#include <cmath>
#include <glog/logging.h>
#include <iostream>

namespace {
auto getDistance = [](const Location& start, const Location& end, void* c = 0) {
    int xdist = start.x - end.x;
    int ydist = start.y - end.y;
    return (abs(xdist) + abs(ydist));
};

} // namespace

NpcSystem::NpcSystem() {
    createHumanStateMachine();
    createDogStateMachine();
}

void NpcSystem::createHumanStateMachine() {
    StateMachine human;

    State NoneState;
    Transition NoneToIdle;
    NoneToIdle.condition = [&](EntityId e, NpcComponent* n) { return true; };
    NoneToIdle.endState = "Idle";
    NoneState.transitions.push_back(NoneToIdle);
    human[""] = NoneState;

    State IdleState;
    Transition IdleToSeeking;
    IdleToSeeking.condition = [&](EntityId e, NpcComponent* n) { return true; };
    IdleToSeeking.endState = "Seeking";
    IdleState.transitions.push_back(IdleToSeeking);
    human["Idle"] = IdleState;

    State SeekingState;
    Transition SeekingToMoving;
    SeekingToMoving.condition = [&](EntityId e, NpcComponent* n) {
        return n->target != 0;
    };
    SeekingToMoving.endState = "Moving";
    SeekingState.transitions.push_back(SeekingToMoving);
    SeekingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        n->target = findNearestVisibleMatching(entities()->getLocation(e),
                                               n->losDistance,
                                               n->attribs["seek_target"]);
    };
    human["Seeking"] = SeekingState;

    State MovingState;
    Transition MovingToAttacking;
    MovingToAttacking.condition = [&](EntityId e, NpcComponent* n) {
        return canAttackTarget(e, n);
    };
    MovingToAttacking.endState = "Attacking";
    MovingState.transitions.push_back(MovingToAttacking);
    MovingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        setPathToTarget(e, n->target, n);
        if (!n->path.empty()) {
            events()->fire(std::make_shared<MoveEntityEvent>(e, n->path[0]));
            n->path.erase(n->path.begin());
        }
    };
    human["Moving"] = MovingState;

    State AttackingState;
    Transition AttackingNotPossible;
    AttackingNotPossible.condition = [&](EntityId e, NpcComponent* n) {
        return !canAttackTarget(e, n);
    };
    AttackingNotPossible.endState = "Seeking";
    AttackingState.transitions.push_back(AttackingNotPossible);
    AttackingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        events()->fire(std::make_shared<AttackEntityEvent>(e, n->target));
    };
    AttackingState.onLeave = [&](EntityId e, NpcComponent* n) {
        n->target = 0;
    };
    human["Attacking"] = AttackingState;
    m_stateMachines["human"] = human;
}

void NpcSystem::createDogStateMachine() {
    StateMachine dog;

    State NoneState;
    Transition NoneToIdle;
    NoneToIdle.condition = [](EntityId e, NpcComponent* n) { return true; };
    NoneToIdle.endState = "Idle";
    NoneState.transitions.push_back(NoneToIdle);
    dog[""] = NoneState;

    State IdleState;
    Transition IdleToSeeking;
    IdleToSeeking.condition = [&](EntityId e, NpcComponent* n) {
        // When human is too far away - 5 tiles
        return 0 == findNearestVisibleMatching(entities()->getLocation(e), 3,
                                               n->attribs["seek_target"]);
        ;
    };
    IdleToSeeking.endState = "Seeking";
    IdleState.transitions.push_back(IdleToSeeking);
    dog["Idle"] = IdleState;

    State SeekingState;
    Transition SeekingToMoving;
    SeekingToMoving.condition = [](EntityId e, NpcComponent* n) {
        return true;
    };
    SeekingToMoving.endState = "Moving";
    SeekingState.transitions.push_back(SeekingToMoving);
    SeekingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        n->target = findNearestVisibleMatching(entities()->getLocation(e),
                                               n->losDistance,
                                               n->attribs["seek_target"]);
    };
    dog["Seeking"] = SeekingState;

    State MovingState;
    Transition MovingToIdle;
    MovingToIdle.condition = [&](EntityId e, NpcComponent* n) {
        // When human is too far away - x tiles
        return 0 != findNearestVisibleMatching(entities()->getLocation(e), 3,
                                               n->attribs["seek_target"]);
        ;
    };
    MovingToIdle.endState = "Idle";
    MovingState.transitions.push_back(MovingToIdle);
    MovingState.onUpdate = [&](EntityId e, NpcComponent* n) {
        setPathToTarget(e, n->target, n);
        if (!n->path.empty()) {
            events()->fire(std::make_shared<MoveEntityEvent>(e, n->path[0]));
            n->path.erase(n->path.begin());
        }
    };
    dog["Moving"] = MovingState;

    m_stateMachines["dog"] = dog;
}

void NpcSystem::onTurn() {
    for (EntityId entity : entities()->all()) {
        NpcComponent* npc = components()->get<NpcComponent>(entity);
        if (npc == 0)
            continue;

        State currentState = m_stateMachines[npc->stateMachine][npc->state];
        for (Transition& transition : currentState.transitions) {
            if (transition.condition(entity, npc)) {
                LOG(INFO) << "Changing state from <" << npc->state << "> to <"
                          << transition.endState << "> for " << entity
                          << std::endl;
                if (currentState.onLeave) {
                    currentState.onLeave(entity, npc);
                }
                npc->state = transition.endState;
                currentState = m_stateMachines[npc->stateMachine][npc->state];
                if (currentState.onEntry) {
                    currentState.onEntry(entity, npc);
                }
                break;
            }
        }
        if (currentState.onUpdate) {
            currentState.onUpdate(entity, npc);
        }
    }
}

EntityId NpcSystem::findNearestVisibleMatching(const Location& location,
                                               unsigned int radius,
                                               const std::string& name) {
    EntityId retval = 0;
    unsigned int minDist = 1000.0;
    EntityHolder entities = map()->findEntitiesNear(location, radius);
    for (EntityId entity : entities) {
        unsigned int dist =
            getDistance(location, this->entities()->getLocation(entity));
        auto* desc = components()->get<DescriptionComponent>(entity);
        if (desc == 0)
            continue;
        if (desc->title == name && dist < minDist) {
            retval = entity;
            minDist = dist;
        }
    }
    return retval;
}

void NpcSystem::setPathToTarget(EntityId entity, EntityId target,
                                NpcComponent* npc) {
    auto getPathCost = [&](const Location& location, void* c) {
        auto player = components()->getUnique<PlayerComponent>();

        for (EntityId entity : map()->getTile(location).entities()) {
            if (entity == player.id) {
                continue;
            }
            if (components()->get<ColliderComponent>(entity)) {
                return 99;
            }
        }
        return 1;
    };
    auto findNeighbours4 = [&](const Location& location, Location* neighbours,
                               void* c) {
        unsigned int count = 0;
        Location neighbour = location;
        int xAdj[] = {-1, 1, 0, 0};
        int yAdj[] = {0, 0, -1, 1};

        for (unsigned int ii = 0; ii < 4; ii++) {
            neighbour = location;
            neighbour.x += xAdj[ii];
            neighbour.y += yAdj[ii];
            if (map()->isValidTile(neighbour)) {
                if (getPathCost(neighbour, 0) > 0)
                    neighbours[count++] = neighbour;
            }
        }
        return count;
    };

    Algorithm algo;
    algo.setCostFunction(getPathCost);
    algo.setDistanceFunction(getDistance);
    algo.setNeighbourFunction(findNeighbours4);
    algo.setNumNeighbours(4);

    PathVector l_path;
    algo.findPath(entities()->getLocation(entity),
                  entities()->getLocation(target), l_path);

    if (l_path.empty()) {
        return;
    }

    // Reset path
    npc->path.clear();
    for (unsigned int ii = 0; ii < l_path.size(); ii++) {
        npc->path.push_back(l_path[ii]);
        // std::cout << "Step " << ii << ": " << tempLoc << std::endl;
    }
}

bool NpcSystem::canAttackTarget(EntityId entity, NpcComponent* npc) {
    Location location = entities()->getLocation(entity);
    EntityHolder entitiesNear = map()->findEntitiesNear(location, 1);

    auto entityInReach = [&](EntityId id) {
        // Check it's the target that's in reach
        if (id != npc->target) {
            return false;
        }
        // Check it's not at a diagonal
        Location oLoc = entities()->getLocation(id);
        return !(location.x != oLoc.x && location.y != oLoc.y);
    };

    return entitiesNear.end() != std::find_if(entitiesNear.begin(),
                                              entitiesNear.end(),
                                              entityInReach);
}<|endoftext|>


<commit_before>// HACK - lifted from https://github.com/harto/realpath-osx
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

int main (int argc, char** argv)
{
    using namespace std;
    size_t pathIdx             = 1;
    bool   canonicalizeMissing = false;
    if (argc == 3 && strcmp (argv[1], "--canonicalize-missing") == 0) {
        pathIdx += 1;
        canonicalizeMissing = true;
    }
    else if (argc != 2) {
        fprintf (stderr, "Usage: realpath <path>\n");
        return 1;
    }

    char* path = argv[pathIdx];
    char  result[PATH_MAX];

    if (canonicalizeMissing) {
        auto backTick = [](const string& cmd) -> string {
            char result[PATH_MAX] = "\0";
            // super-primitive impl - wont work with funny (quote) chars in pathnames
            FILE* in = nullptr;
            if ((in = popen (cmd.c_str (), "r")) != NULL) {
                fgets (result, sizeof (result) / sizeof (result[0]), in);
                pclose (in);
                size_t n = strlen (result);
                if (n > 0 and result[n - 1] == '\n') {
                    result[n - 1] = '\0';
                }
                return result;
            }
            fprintf (stderr, "backTick failed\n");
            ::exit (1);
            return {};
        };
        // super-primitive impl - wont work with funny (quote) chars in pathnames
        string dirName  = backTick ("dirname " + string (path));
        string basename = backTick ("basename " + string (path));
        if (dirName/length () != 0 && dirName[0] == '.') {
            dirName = backTick ("pwd") + "/" + dirName;
        }
        dirName += "/";
        printf ("%s\n", (dirName + basename).c_str ());
        return 0;
    }
    else if (realpath (path, result)) {
        printf ("%s\n", result);
        return 0;
    }
    else {
        fprintf (stderr, "Bad path: %s\n", result);
        return 2;
    }
}
<commit_msg>fix corner cases of macos realpath build helper<commit_after>// HACK - lifted from https://github.com/harto/realpath-osx
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

int main (int argc, char** argv)
{
    using namespace std;
    size_t pathIdx             = 1;
    bool   canonicalizeMissing = false;
    if (argc == 3 && strcmp (argv[1], "--canonicalize-missing") == 0) {
        pathIdx += 1;
        canonicalizeMissing = true;
    }
    else if (argc != 2) {
        fprintf (stderr, "Usage: realpath <path>\n");
        return 1;
    }

    char* path = argv[pathIdx];
    char  result[PATH_MAX];

    if (canonicalizeMissing) {
        auto backTick = [](const string& cmd) -> string {
            char result[PATH_MAX] = "\0";
            // super-primitive impl - wont work with funny (quote) chars in pathnames
            FILE* in = nullptr;
            if ((in = popen (cmd.c_str (), "r")) != NULL) {
                fgets (result, sizeof (result) / sizeof (result[0]), in);
                pclose (in);
                size_t n = strlen (result);
                if (n > 0 and result[n - 1] == '\n') {
                    result[n - 1] = '\0';
                }
                return result;
            }
            fprintf (stderr, "backTick failed\n");
            ::exit (1);
            return {};
        };
        // super-primitive impl - wont work with funny (quote) chars in pathnames
        string dirName  = backTick ("dirname " + string (path));
        string basename = backTick ("basename " + string (path));
        if (dirName.length () != 0 && dirName[0] == '.') {
            dirName = backTick ("pwd") + "/" + dirName;
        }
        dirName += "/";
        printf ("%s\n", (dirName + basename).c_str ());
        return 0;
    }
    else if (realpath (path, result)) {
        printf ("%s\n", result);
        return 0;
    }
    else {
        fprintf (stderr, "Bad path: %s\n", result);
        return 2;
    }
}
<|endoftext|>


<commit_before>#include "opt/ssa/phi_builder.h"

#include "design/design_tool.h"
#include "iroha/resource_class.h"
#include "iroha/stl_util.h"
#include "opt/bb_set.h"
#include "opt/data_flow.h"

namespace iroha {
namespace opt {
namespace ssa {

PhiBuilder::PhiBuilder(ITable *tab, DebugAnnotation *annotation)
  : table_(tab), annotation_(annotation), phi_(nullptr) {
}

PhiBuilder::~PhiBuilder() {
  STLDeleteValues(&phis_);
  STLDeleteSecondElements(&reg_info_);
}

void PhiBuilder::Perform() {
  bset_.reset(BBSet::Create(table_, false, annotation_));
  data_flow_.reset(DataFlow::Create(bset_.get(), annotation_));
  phi_ = DesignTool::GetOneResource(table_, resource::kPhi);

  for (BB *bb : bset_->bbs_) {
    CalculatePHIInputsForBB(bb);
  }

  for (PHI *phi : phis_) {
    UpdatePHIInputs(phi);
  }

  for (RegDef *reg_def : data_flow_->all_defs_) {
    insn_to_reg_defs_[reg_def->insn].insert(reg_def);
  }

  for (BB *bb : bset_->bbs_) {
    UpdateVersionsForBB(bb);
  }
}

void PhiBuilder::CalculatePHIInputsForBB(BB *bb) {
  set<IInsn *> phi_insns;
  for (IInsn *insn : bb->states_[0]->insns_) {
    if (insn->GetResource() == phi_) {
      phi_insns.insert(insn);
    }
  }
  vector<RegDef *> reaches;
  data_flow_->GetReachDefs(bb, &reaches);
  map<IRegister *, set<RegDef *> > per_reg_defs;
  for (RegDef *reg_def : reaches) {
    per_reg_defs[reg_def->reg].insert(reg_def);
  }
  for (IInsn *phi_insn : phi_insns) {
    IRegister *reg = *(phi_insn->outputs_.begin());
    set<RegDef *> &reaching = per_reg_defs[reg];
    PHI *phi = new PHI;
    phi->insn_ = phi_insn;
    phi->defs_ = reaching;
    phis_.push_back(phi);
  }
}

void PhiBuilder::UpdatePHIInputs(PHI *phi) {
  for (RegDef *reg_def : phi->defs_) {
    IRegister *reg = FindVersionedReg(reg_def);
    phi->insn_->inputs_.push_back(reg);
  }
}

void PhiBuilder::UpdateVersionsForBB(BB *bb) {
  vector<RegDef *> reaches;
  data_flow_->GetReachDefs(bb, &reaches);
  // map (instead of multimap) is sufficient since the graph is in SSA mode.
  map<IRegister *, RegDef *> reg_to_last_def;
  for (RegDef *reg_def : reaches) {
    reg_to_last_def[reg_def->reg] = reg_def;
  }
  for (IState *st : bb->states_) {
    for (IInsn *insn : st->insns_) {
      UpdateVersionsForInsn(&reg_to_last_def, insn);
    }
  }
}

void
PhiBuilder::UpdateVersionsForInsn(map<IRegister *, RegDef *> *reg_to_last_def,
				  IInsn *insn) {
  if (insn->GetResource() != phi_) {
    for (auto it = insn->inputs_.begin(); it != insn->inputs_.end(); ++it) {
      IRegister *ireg = *it;
      if (reg_to_last_def->find(ireg) != reg_to_last_def->end()) {
	RegDef *reg_def = (*reg_to_last_def)[ireg];
	*it = FindVersionedReg(reg_def);
      }
    }
  }
  for (auto it = insn->outputs_.begin(); it != insn->outputs_.end(); ++it) {
    set<RegDef *> &defs = insn_to_reg_defs_[insn];
    RegDef *reg_def = nullptr;
    for (RegDef *d : defs) {
      if (d->reg == *it) {
	reg_def = d;
      }
    }
    (*reg_to_last_def)[reg_def->reg] = reg_def;
    *it = FindVersionedReg(reg_def);
  }
}

int PhiBuilder::GetVersionFromDefInfo(RegDef *reg_def) {
  auto it = def_versions_.find(reg_def);
  if (it == def_versions_.end()) {
    int v = def_versions_.size() + 1;
    def_versions_[reg_def] = v;
    return v;
  }
  return it->second;
}

IRegister *PhiBuilder::FindVersionedReg(RegDef *reg_def) {
  PerRegister *pr = reg_info_[reg_def->reg];
  if (pr == nullptr) {
    pr = new PerRegister;
    reg_info_[reg_def->reg] = pr;
  }
  int version = GetVersionFromDefInfo(reg_def);
  IRegister *reg = pr->versions_[version];
  if (reg == nullptr) {
    reg = new IRegister(table_, reg_def->reg->GetName() + "_v" +
			Util::Itoa(version));
    reg->value_type_ = reg_def->reg->value_type_;
    if (reg_def->reg->HasInitialValue()) {
      Numeric n = reg_def->reg->GetInitialValue();
      reg->SetInitialValue(n);
    }
    table_->registers_.push_back(reg);
    pr->versions_[version] = reg;
  }
  return reg;
}

}  // namespace ssa
}  // namespace opt
}  // namespace iroha
<commit_msg>TODO to fix SSA violation.<commit_after>#include "opt/ssa/phi_builder.h"

#include "design/design_tool.h"
#include "iroha/resource_class.h"
#include "iroha/stl_util.h"
#include "opt/bb_set.h"
#include "opt/data_flow.h"

namespace iroha {
namespace opt {
namespace ssa {

PhiBuilder::PhiBuilder(ITable *tab, DebugAnnotation *annotation)
  : table_(tab), annotation_(annotation), phi_(nullptr) {
}

PhiBuilder::~PhiBuilder() {
  STLDeleteValues(&phis_);
  STLDeleteSecondElements(&reg_info_);
}

void PhiBuilder::Perform() {
  bset_.reset(BBSet::Create(table_, false, annotation_));
  data_flow_.reset(DataFlow::Create(bset_.get(), annotation_));
  phi_ = DesignTool::GetOneResource(table_, resource::kPhi);

  for (BB *bb : bset_->bbs_) {
    CalculatePHIInputsForBB(bb);
  }

  for (PHI *phi : phis_) {
    UpdatePHIInputs(phi);
  }

  for (RegDef *reg_def : data_flow_->all_defs_) {
    insn_to_reg_defs_[reg_def->insn].insert(reg_def);
  }

  for (BB *bb : bset_->bbs_) {
    UpdateVersionsForBB(bb);
  }
}

void PhiBuilder::CalculatePHIInputsForBB(BB *bb) {
  set<IInsn *> phi_insns;
  for (IInsn *insn : bb->states_[0]->insns_) {
    if (insn->GetResource() == phi_) {
      phi_insns.insert(insn);
    }
  }
  vector<RegDef *> reaches;
  data_flow_->GetReachDefs(bb, &reaches);
  map<IRegister *, set<RegDef *> > per_reg_defs;
  for (RegDef *reg_def : reaches) {
    per_reg_defs[reg_def->reg].insert(reg_def);
  }
  for (IInsn *phi_insn : phi_insns) {
    IRegister *reg = *(phi_insn->outputs_.begin());
    set<RegDef *> &reaching = per_reg_defs[reg];
    PHI *phi = new PHI;
    phi->insn_ = phi_insn;
    phi->defs_ = reaching;
    phis_.push_back(phi);
  }
}

void PhiBuilder::UpdatePHIInputs(PHI *phi) {
  for (RegDef *reg_def : phi->defs_) {
    IRegister *reg = FindVersionedReg(reg_def);
    phi->insn_->inputs_.push_back(reg);
  }
}

void PhiBuilder::UpdateVersionsForBB(BB *bb) {
  vector<RegDef *> reaches;
  data_flow_->GetReachDefs(bb, &reaches);
  // map (instead of multimap) is sufficient since the graph is in SSA mode.
  map<IRegister *, RegDef *> reg_to_last_def;
  for (RegDef *reg_def : reaches) {
    reg_to_last_def[reg_def->reg] = reg_def;
  }
  for (IState *st : bb->states_) {
    for (IInsn *insn : st->insns_) {
      UpdateVersionsForInsn(&reg_to_last_def, insn);
    }
  }
}

void
PhiBuilder::UpdateVersionsForInsn(map<IRegister *, RegDef *> *reg_to_last_def,
				  IInsn *insn) {
  if (insn->GetResource() != phi_) {
    for (auto it = insn->inputs_.begin(); it != insn->inputs_.end(); ++it) {
      IRegister *ireg = *it;
      if (reg_to_last_def->find(ireg) != reg_to_last_def->end()) {
	RegDef *reg_def = (*reg_to_last_def)[ireg];
	*it = FindVersionedReg(reg_def);
      }
    }
  }
  for (auto it = insn->outputs_.begin(); it != insn->outputs_.end(); ++it) {
    set<RegDef *> &defs = insn_to_reg_defs_[insn];
    RegDef *reg_def = nullptr;
    for (RegDef *d : defs) {
      if (d->reg == *it) {
	reg_def = d;
      }
    }
    (*reg_to_last_def)[reg_def->reg] = reg_def;
    *it = FindVersionedReg(reg_def);
  }
}

int PhiBuilder::GetVersionFromDefInfo(RegDef *reg_def) {
  auto it = def_versions_.find(reg_def);
  if (it == def_versions_.end()) {
    int v = def_versions_.size() + 1;
    def_versions_[reg_def] = v;
    return v;
  }
  return it->second;
}

IRegister *PhiBuilder::FindVersionedReg(RegDef *reg_def) {
  PerRegister *pr = reg_info_[reg_def->reg];
  if (pr == nullptr) {
    pr = new PerRegister;
    reg_info_[reg_def->reg] = pr;
  }
  int version = GetVersionFromDefInfo(reg_def);
  IRegister *reg = pr->versions_[version];
  if (reg == nullptr) {
    reg = new IRegister(table_, reg_def->reg->GetName() + "_v" +
			Util::Itoa(version));
    reg->value_type_ = reg_def->reg->value_type_;
    if (reg_def->reg->HasInitialValue()) {
      // TODO: As this may violate the premise of SSA.
      // Make initial value assignment explicit one assign insn and then apply
      // SSA conversion. Then remove this part.
      Numeric n = reg_def->reg->GetInitialValue();
      reg->SetInitialValue(n);
    }
    table_->registers_.push_back(reg);
    pr->versions_[version] = reg;
  }
  return reg;
}

}  // namespace ssa
}  // namespace opt
}  // namespace iroha
<|endoftext|>


<commit_before>/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _GLIBCXX_USE_NANOSLEEP
#define _GLIBCXX_USE_NANOSLEEP
#endif

#include <CommonAPI/DBus/DBusInputStream.h>
#include <CommonAPI/DBus/DBusMessage.h>
#include <CommonAPI/DBus/DBusProxy.h>
#include <CommonAPI/DBus/DBusConnection.h>
#include <CommonAPI/DBus/DBusStubAdapter.h>

#include <commonapi/tests/TestInterfaceDBusProxy.h>
#include <commonapi/tests/TestInterfaceDBusStubAdapter.h>
#include <commonapi/tests/TestInterfaceStubDefault.h>

#include "DBusTestUtils.h"

#include <gtest/gtest.h>

#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <thread>
#include <vector>

static const std::string commonApiAddress = "local:CommonAPI.DBus.tests.DBusProxyTestInterface:CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string commonApiServiceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string interfaceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string busName = "CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string objectPath = "/CommonAPI/DBus/tests/DBusProxyTestService";

class ProxyTest: public ::testing::Test {
protected:

    void SetUp() {
        proxyDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(proxyDBusConnection_->connect());

        proxy_ = std::make_shared<commonapi::tests::TestInterfaceDBusProxy>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        proxyDBusConnection_);
    }

    virtual void TearDown() {
        usleep(30000);
    }

    void registerTestStub() {
        stubDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(stubDBusConnection_->connect());

        auto stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
        stubAdapter_ = std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        stubDBusConnection_,
                        stubDefault);
        stubAdapter_->init();

        bool serviceNameAcquired = stubDBusConnection_->requestServiceNameAndBlock(busName);

        for(unsigned int i = 0; !serviceNameAcquired && i < 100; i++) {
            usleep(10000);
            serviceNameAcquired = stubDBusConnection_->requestServiceNameAndBlock(busName);
        }
        ASSERT_TRUE(serviceNameAcquired);
        usleep(500000);
    }

    void deregisterTestStub() {
    	stubAdapter_->deinit();
    	stubAdapter_.reset();

		if (stubDBusConnection_->isConnected()) {
			stubDBusConnection_->disconnect();
		}
		stubDBusConnection_.reset();
    }

    void proxyRegisterForAvailabilityStatus() {
        proxyAvailabilityStatus_ = CommonAPI::AvailabilityStatus::UNKNOWN;

        proxyStatusSubscription_ = proxy_->getProxyStatusEvent().subscribe([&](const CommonAPI::AvailabilityStatus& availabilityStatus) {
            proxyAvailabilityStatus_ = availabilityStatus;
        });
        usleep(100000);
    }

    void proxyDeregisterForAvailabilityStatus() {
    	proxy_->getProxyStatusEvent().unsubscribe(proxyStatusSubscription_);
    }

    bool proxyWaitForAvailabilityStatus(const CommonAPI::AvailabilityStatus& availabilityStatus) const {
        for (int i = 0; i < 10; i++) {
            std::cout << "Current status is: " << toString(proxyAvailabilityStatus_) << std::endl;
            if (proxyAvailabilityStatus_ == availabilityStatus)
                return true;
            usleep(100000);
        }

        return false;
    }

    std::shared_ptr<CommonAPI::DBus::DBusConnection> proxyDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusProxy> proxy_;
    CommonAPI::AvailabilityStatus proxyAvailabilityStatus_;

    CommonAPI::ProxyStatusEvent::Subscription proxyStatusSubscription_;

    std::shared_ptr<CommonAPI::DBus::DBusConnection> stubDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter_;
};

TEST_F(ProxyTest, HasCorrectConnectionName) {
  std::string actualName = proxy_->getDBusBusName();
  EXPECT_EQ(busName, actualName);
}

TEST_F(ProxyTest, HasCorrectObjectPath) {
  std::string actualPath = proxy_->getDBusObjectPath();
  EXPECT_EQ(objectPath, actualPath);
}

TEST_F(ProxyTest, HasCorrectInterfaceName) {
  std::string actualName = proxy_->getInterfaceName();
  EXPECT_EQ(interfaceName, actualName);
}

TEST_F(ProxyTest, IsNotAvailable) {
	bool isAvailable = proxy_->isAvailable();
	EXPECT_FALSE(isAvailable);
}

TEST_F(ProxyTest, IsConnected) {
  ASSERT_TRUE(proxy_->getDBusConnection()->isConnected());
}

TEST_F(ProxyTest, AssociatedConnectionHasServiceRegistry) {
	std::shared_ptr<CommonAPI::DBus::DBusProxyConnection> connection = proxy_->getDBusConnection();
	auto registry = connection->getDBusServiceRegistry();
	ASSERT_FALSE(!registry);
}

TEST_F(ProxyTest, DBusProxyStatusEventBeforeServiceIsRegistered) {
    proxyRegisterForAvailabilityStatus();

    EXPECT_NE(proxyAvailabilityStatus_, CommonAPI::AvailabilityStatus::AVAILABLE);

    registerTestStub();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));

    deregisterTestStub();
    proxyDeregisterForAvailabilityStatus();
}

TEST_F(ProxyTest, DBusProxyStatusEventAfterServiceIsRegistered) {
    proxyDBusConnection_->disconnect();

    registerTestStub();

    EXPECT_TRUE(proxyDBusConnection_->connect());

    proxyRegisterForAvailabilityStatus();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));

    deregisterTestStub();
    proxyDeregisterForAvailabilityStatus();
}

TEST_F(ProxyTest, ServiceStatus) {
    registerTestStub();

    std::vector<std::string> availableDBusServices;

    //Service actually IS available!
    for (int i = 0; i < 5; i++) {
        availableDBusServices = proxyDBusConnection_->getDBusServiceRegistry()->getAvailableServiceInstances(
                        commonApiServiceName,
                        "local");

        if (!availableDBusServices.empty()) {
            break;
        }
    }

	auto found = std::find(availableDBusServices.begin(), availableDBusServices.end(), commonApiAddress);

	EXPECT_TRUE(availableDBusServices.begin() != availableDBusServices.end());
	EXPECT_TRUE(found != availableDBusServices.end());

    deregisterTestStub();
}

TEST_F(ProxyTest, isServiceInstanceAlive) {
    registerTestStub();

    bool isInstanceAlive = proxyDBusConnection_->getDBusServiceRegistry()->isServiceInstanceAlive(interfaceName, busName, objectPath);

    for (int i = 0; !isInstanceAlive && i < 10; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        isInstanceAlive = proxyDBusConnection_->getDBusServiceRegistry()->isServiceInstanceAlive(interfaceName, busName, objectPath);
    }

    EXPECT_TRUE(isInstanceAlive);

    deregisterTestStub();
}

TEST_F(ProxyTest, IsAvailableBlocking) {
    registerTestStub();

    // blocking in terms of "if it's still unknown"
    for (int i = 0; !proxy_->isAvailableBlocking() && i < 3; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    EXPECT_TRUE(proxy_->isAvailableBlocking());

    deregisterTestStub();
}

TEST_F(ProxyTest, HasNecessaryAttributesAndEvents) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = (proxy_->getInterfaceVersionAttribute());
	CommonAPI::ProxyStatusEvent& statusEvent = (proxy_->getProxyStatusEvent());
}

TEST_F(ProxyTest, TestInterfaceVersionAttribute) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = proxy_->getInterfaceVersionAttribute();
	CommonAPI::Version version;
	CommonAPI::CallStatus status;
	ASSERT_NO_THROW(status = versionAttribute.getValue(version));
	ASSERT_EQ(CommonAPI::CallStatus::NOT_AVAILABLE, status);
}

TEST_F(ProxyTest, AsyncCallbacksAreCalledIfServiceNotAvailable) {
    commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testInputStruct;
    commonapi::tests::DerivedTypeCollection::TestMap testInputMap;
    std::promise<bool> wasCalledPromise;
    std::future<bool> wasCalledFuture = wasCalledPromise.get_future();
    proxy_->testDerivedTypeMethodAsync(testInputStruct, testInputMap, [&] (const CommonAPI::CallStatus& callStatus,
                                                                          const commonapi::tests::DerivedTypeCollection::TestEnumExtended2&,
                                                                          const commonapi::tests::DerivedTypeCollection::TestMap&) {
                    ASSERT_EQ(callStatus, CommonAPI::CallStatus::NOT_AVAILABLE);
                    wasCalledPromise.set_value(true);
            }
    );
    ASSERT_TRUE(wasCalledFuture.get());
}

int main(int argc, char** argv) {
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
<commit_msg>Removed std::output in one test<commit_after>/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _GLIBCXX_USE_NANOSLEEP
#define _GLIBCXX_USE_NANOSLEEP
#endif

#include <CommonAPI/DBus/DBusInputStream.h>
#include <CommonAPI/DBus/DBusMessage.h>
#include <CommonAPI/DBus/DBusProxy.h>
#include <CommonAPI/DBus/DBusConnection.h>
#include <CommonAPI/DBus/DBusStubAdapter.h>

#include <commonapi/tests/TestInterfaceDBusProxy.h>
#include <commonapi/tests/TestInterfaceDBusStubAdapter.h>
#include <commonapi/tests/TestInterfaceStubDefault.h>

#include "DBusTestUtils.h"

#include <gtest/gtest.h>

#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <thread>
#include <vector>

static const std::string commonApiAddress = "local:CommonAPI.DBus.tests.DBusProxyTestInterface:CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string commonApiServiceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string interfaceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string busName = "CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string objectPath = "/CommonAPI/DBus/tests/DBusProxyTestService";

class ProxyTest: public ::testing::Test {
protected:

    void SetUp() {
        proxyDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(proxyDBusConnection_->connect());

        proxy_ = std::make_shared<commonapi::tests::TestInterfaceDBusProxy>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        proxyDBusConnection_);
    }

    virtual void TearDown() {
        usleep(30000);
    }

    void registerTestStub() {
        stubDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(stubDBusConnection_->connect());

        auto stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
        stubAdapter_ = std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        stubDBusConnection_,
                        stubDefault);
        stubAdapter_->init();

        bool serviceNameAcquired = stubDBusConnection_->requestServiceNameAndBlock(busName);

        for(unsigned int i = 0; !serviceNameAcquired && i < 100; i++) {
            usleep(10000);
            serviceNameAcquired = stubDBusConnection_->requestServiceNameAndBlock(busName);
        }
        ASSERT_TRUE(serviceNameAcquired);
        usleep(500000);
    }

    void deregisterTestStub() {
    	stubAdapter_->deinit();
    	stubAdapter_.reset();

		if (stubDBusConnection_->isConnected()) {
			stubDBusConnection_->disconnect();
		}
		stubDBusConnection_.reset();
    }

    void proxyRegisterForAvailabilityStatus() {
        proxyAvailabilityStatus_ = CommonAPI::AvailabilityStatus::UNKNOWN;

        proxyStatusSubscription_ = proxy_->getProxyStatusEvent().subscribe([&](const CommonAPI::AvailabilityStatus& availabilityStatus) {
            proxyAvailabilityStatus_ = availabilityStatus;
        });
        usleep(100000);
    }

    void proxyDeregisterForAvailabilityStatus() {
    	proxy_->getProxyStatusEvent().unsubscribe(proxyStatusSubscription_);
    }

    bool proxyWaitForAvailabilityStatus(const CommonAPI::AvailabilityStatus& availabilityStatus) const {
        for (int i = 0; i < 10; i++) {
            if (proxyAvailabilityStatus_ == availabilityStatus)
                return true;
            usleep(100000);
        }

        return false;
    }

    std::shared_ptr<CommonAPI::DBus::DBusConnection> proxyDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusProxy> proxy_;
    CommonAPI::AvailabilityStatus proxyAvailabilityStatus_;

    CommonAPI::ProxyStatusEvent::Subscription proxyStatusSubscription_;

    std::shared_ptr<CommonAPI::DBus::DBusConnection> stubDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter_;
};

TEST_F(ProxyTest, HasCorrectConnectionName) {
  std::string actualName = proxy_->getDBusBusName();
  EXPECT_EQ(busName, actualName);
}

TEST_F(ProxyTest, HasCorrectObjectPath) {
  std::string actualPath = proxy_->getDBusObjectPath();
  EXPECT_EQ(objectPath, actualPath);
}

TEST_F(ProxyTest, HasCorrectInterfaceName) {
  std::string actualName = proxy_->getInterfaceName();
  EXPECT_EQ(interfaceName, actualName);
}

TEST_F(ProxyTest, IsNotAvailable) {
	bool isAvailable = proxy_->isAvailable();
	EXPECT_FALSE(isAvailable);
}

TEST_F(ProxyTest, IsConnected) {
  ASSERT_TRUE(proxy_->getDBusConnection()->isConnected());
}

TEST_F(ProxyTest, AssociatedConnectionHasServiceRegistry) {
	std::shared_ptr<CommonAPI::DBus::DBusProxyConnection> connection = proxy_->getDBusConnection();
	auto registry = connection->getDBusServiceRegistry();
	ASSERT_FALSE(!registry);
}

TEST_F(ProxyTest, DBusProxyStatusEventBeforeServiceIsRegistered) {
    proxyRegisterForAvailabilityStatus();

    EXPECT_NE(proxyAvailabilityStatus_, CommonAPI::AvailabilityStatus::AVAILABLE);

    registerTestStub();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));

    deregisterTestStub();
    proxyDeregisterForAvailabilityStatus();
}

TEST_F(ProxyTest, DBusProxyStatusEventAfterServiceIsRegistered) {
    proxyDBusConnection_->disconnect();

    registerTestStub();

    EXPECT_TRUE(proxyDBusConnection_->connect());

    proxyRegisterForAvailabilityStatus();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    EXPECT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));

    deregisterTestStub();
    proxyDeregisterForAvailabilityStatus();
}

TEST_F(ProxyTest, ServiceStatus) {
    registerTestStub();

    std::vector<std::string> availableDBusServices;

    //Service actually IS available!
    for (int i = 0; i < 5; i++) {
        availableDBusServices = proxyDBusConnection_->getDBusServiceRegistry()->getAvailableServiceInstances(
                        commonApiServiceName,
                        "local");

        if (!availableDBusServices.empty()) {
            break;
        }
    }

	auto found = std::find(availableDBusServices.begin(), availableDBusServices.end(), commonApiAddress);

	EXPECT_TRUE(availableDBusServices.begin() != availableDBusServices.end());
	EXPECT_TRUE(found != availableDBusServices.end());

    deregisterTestStub();
}

TEST_F(ProxyTest, isServiceInstanceAlive) {
    registerTestStub();

    bool isInstanceAlive = proxyDBusConnection_->getDBusServiceRegistry()->isServiceInstanceAlive(interfaceName, busName, objectPath);

    for (int i = 0; !isInstanceAlive && i < 10; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
        isInstanceAlive = proxyDBusConnection_->getDBusServiceRegistry()->isServiceInstanceAlive(interfaceName, busName, objectPath);
    }

    EXPECT_TRUE(isInstanceAlive);

    deregisterTestStub();
}

TEST_F(ProxyTest, IsAvailableBlocking) {
    registerTestStub();

    // blocking in terms of "if it's still unknown"
    for (int i = 0; !proxy_->isAvailableBlocking() && i < 3; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    EXPECT_TRUE(proxy_->isAvailableBlocking());

    deregisterTestStub();
}

TEST_F(ProxyTest, HasNecessaryAttributesAndEvents) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = (proxy_->getInterfaceVersionAttribute());
	CommonAPI::ProxyStatusEvent& statusEvent = (proxy_->getProxyStatusEvent());
}

TEST_F(ProxyTest, TestInterfaceVersionAttribute) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = proxy_->getInterfaceVersionAttribute();
	CommonAPI::Version version;
	CommonAPI::CallStatus status;
	ASSERT_NO_THROW(status = versionAttribute.getValue(version));
	ASSERT_EQ(CommonAPI::CallStatus::NOT_AVAILABLE, status);
}

TEST_F(ProxyTest, AsyncCallbacksAreCalledIfServiceNotAvailable) {
    commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testInputStruct;
    commonapi::tests::DerivedTypeCollection::TestMap testInputMap;
    std::promise<bool> wasCalledPromise;
    std::future<bool> wasCalledFuture = wasCalledPromise.get_future();
    proxy_->testDerivedTypeMethodAsync(testInputStruct, testInputMap, [&] (const CommonAPI::CallStatus& callStatus,
                                                                          const commonapi::tests::DerivedTypeCollection::TestEnumExtended2&,
                                                                          const commonapi::tests::DerivedTypeCollection::TestMap&) {
                    ASSERT_EQ(callStatus, CommonAPI::CallStatus::NOT_AVAILABLE);
                    wasCalledPromise.set_value(true);
            }
    );
    ASSERT_TRUE(wasCalledFuture.get());
}

int main(int argc, char** argv) {
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/hashmap.h"

#include "bin/builtin.h"
#include "platform/utils.h"

HashMap::HashMap(MatchFun match,
                 uint32_t initial_capacity) {
  match_ = match;
  Initialize(initial_capacity);
}

HashMap::~HashMap() {
  free(map_);
}

HashMap::Entry* HashMap::Lookup(void* key, uint32_t hash, bool insert) {
  // Find a matching entry.
  Entry* p = Probe(key, hash);
  if (p->key != NULL) {
    return p;
  }

  // No entry found; insert one if necessary.
  if (insert) {
    p->key = key;
    p->value = NULL;
    p->hash = hash;
    occupancy_++;

    // Grow the map if we reached >= 80% occupancy.
    if ((occupancy_ + (occupancy_ / 4)) >= capacity_) {
      Resize();
      p = Probe(key, hash);
    }

    return p;
  }

  // No entry found and none inserted.
  return NULL;
}

void HashMap::Remove(void* key, uint32_t hash) {
  // Lookup the entry for the key to remove.
  Entry* candidate = Probe(key, hash);
  if (candidate->key == NULL) {
    // Key not found nothing to remove.
    return;
  }

  // To remove an entry we need to ensure that it does not create an empty
  // entry that will cause the search for another entry to stop too soon. If all
  // the entries between the entry to remove and the next empty slot have their
  // initial position inside this interval, clearing the entry to remove will
  // not break the search. If, while searching for the next empty entry, an
  // entry is encountered which does not have its initial position between the
  // entry to remove and the position looked at, then this entry can be moved to
  // the place of the entry to remove without breaking the search for it. The
  // entry made vacant by this move is now the entry to remove and the process
  // starts over.
  // Algorithm from http://en.wikipedia.org/wiki/Open_addressing.

  // This guarantees loop termination as there is at least one empty entry so
  // eventually the removed entry will have an empty entry after it.
  ASSERT(occupancy_ < capacity_);

  // "candidate" is the candidate entry to clear. "next" is used to scan
  // forwards.
  Entry* next = candidate;  // Start at the entry to remove.
  while (true) {
    // Move "next" to the next entry. Wrap when at the end of the array.
    next = next + 1;
    if (next == map_end()) {
      next = map_;
    }

    // All entries between "candidate" and "next" have their initial position
    // between candidate and entry and the entry candidate can be cleared
    // without breaking the search for these entries.
    if (next->key == NULL) {
      break;
    }

    // Find the initial position for the entry at position "next". That is
    // the entry where searching for the entry at position "next" will
    // actually start.
    Entry* start = map_ + (next->hash & (capacity_ - 1));

    // If the entry at position "next" has its initial position outside the
    // range between "candidate" and "next" it can be moved forward to
    // position "candidate" and will still be found. There is now the new
    // candidate entry for clearing.
    if ((next > candidate && (start <= candidate || start > next)) ||
        (next < candidate && (start <= candidate && start > next))) {
      *candidate = *next;
      candidate = next;
    }
  }

  // Clear the candidate which will not break searching the hash table.
  candidate->key = NULL;
  occupancy_--;
}

void HashMap::Clear() {
  // Mark all entries as empty.
  const Entry* end = map_end();
  for (Entry* p = map_; p < end; p++) {
    p->key = NULL;
  }
  occupancy_ = 0;
}

HashMap::Entry* HashMap::Start() const {
  return Next(map_ - 1);
}

HashMap::Entry* HashMap::Next(Entry* p) const {
  const Entry* end = map_end();
  ASSERT(map_ - 1 <= p && p < end);
  for (p++; p < end; p++) {
    if (p->key != NULL) {
      return p;
    }
  }
  return NULL;
}

HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
  ASSERT(key != NULL);

  ASSERT(dart::Utils::IsPowerOfTwo(capacity_));
  Entry* p = map_ + (hash & (capacity_ - 1));
  const Entry* end = map_end();
  ASSERT(map_ <= p && p < end);

  ASSERT(occupancy_ < capacity_);  // Guarantees loop termination.
  while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
    p++;
    if (p >= end) {
      p = map_;
    }
  }

  return p;
}

void HashMap::Initialize(uint32_t capacity) {
  ASSERT(dart::Utils::IsPowerOfTwo(capacity));
  map_ = reinterpret_cast<Entry*>(malloc(capacity * sizeof(Entry)));
  if (map_ == NULL) {
    // TODO(sgjesse): Handle out of memory.
    FATAL("Cannot allocate memory for hashmap");
    return;
  }
  capacity_ = capacity;
  Clear();
}

void HashMap::Resize() {
  Entry* map = map_;
  uint32_t n = occupancy_;

  // Allocate larger map.
  Initialize(capacity_ * 2);

  // Rehash all current entries.
  for (Entry* p = map; n > 0; p++) {
    if (p->key != NULL) {
      Lookup(p->key, p->hash, true)->value = p->value;
      n--;
    }
  }

  // Delete old map.
  free(map);
}
<commit_msg>Remove include which was not needed<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/hashmap.h"

#include "platform/utils.h"

HashMap::HashMap(MatchFun match,
                 uint32_t initial_capacity) {
  match_ = match;
  Initialize(initial_capacity);
}

HashMap::~HashMap() {
  free(map_);
}

HashMap::Entry* HashMap::Lookup(void* key, uint32_t hash, bool insert) {
  // Find a matching entry.
  Entry* p = Probe(key, hash);
  if (p->key != NULL) {
    return p;
  }

  // No entry found; insert one if necessary.
  if (insert) {
    p->key = key;
    p->value = NULL;
    p->hash = hash;
    occupancy_++;

    // Grow the map if we reached >= 80% occupancy.
    if ((occupancy_ + (occupancy_ / 4)) >= capacity_) {
      Resize();
      p = Probe(key, hash);
    }

    return p;
  }

  // No entry found and none inserted.
  return NULL;
}

void HashMap::Remove(void* key, uint32_t hash) {
  // Lookup the entry for the key to remove.
  Entry* candidate = Probe(key, hash);
  if (candidate->key == NULL) {
    // Key not found nothing to remove.
    return;
  }

  // To remove an entry we need to ensure that it does not create an empty
  // entry that will cause the search for another entry to stop too soon. If all
  // the entries between the entry to remove and the next empty slot have their
  // initial position inside this interval, clearing the entry to remove will
  // not break the search. If, while searching for the next empty entry, an
  // entry is encountered which does not have its initial position between the
  // entry to remove and the position looked at, then this entry can be moved to
  // the place of the entry to remove without breaking the search for it. The
  // entry made vacant by this move is now the entry to remove and the process
  // starts over.
  // Algorithm from http://en.wikipedia.org/wiki/Open_addressing.

  // This guarantees loop termination as there is at least one empty entry so
  // eventually the removed entry will have an empty entry after it.
  ASSERT(occupancy_ < capacity_);

  // "candidate" is the candidate entry to clear. "next" is used to scan
  // forwards.
  Entry* next = candidate;  // Start at the entry to remove.
  while (true) {
    // Move "next" to the next entry. Wrap when at the end of the array.
    next = next + 1;
    if (next == map_end()) {
      next = map_;
    }

    // All entries between "candidate" and "next" have their initial position
    // between candidate and entry and the entry candidate can be cleared
    // without breaking the search for these entries.
    if (next->key == NULL) {
      break;
    }

    // Find the initial position for the entry at position "next". That is
    // the entry where searching for the entry at position "next" will
    // actually start.
    Entry* start = map_ + (next->hash & (capacity_ - 1));

    // If the entry at position "next" has its initial position outside the
    // range between "candidate" and "next" it can be moved forward to
    // position "candidate" and will still be found. There is now the new
    // candidate entry for clearing.
    if ((next > candidate && (start <= candidate || start > next)) ||
        (next < candidate && (start <= candidate && start > next))) {
      *candidate = *next;
      candidate = next;
    }
  }

  // Clear the candidate which will not break searching the hash table.
  candidate->key = NULL;
  occupancy_--;
}

void HashMap::Clear() {
  // Mark all entries as empty.
  const Entry* end = map_end();
  for (Entry* p = map_; p < end; p++) {
    p->key = NULL;
  }
  occupancy_ = 0;
}

HashMap::Entry* HashMap::Start() const {
  return Next(map_ - 1);
}

HashMap::Entry* HashMap::Next(Entry* p) const {
  const Entry* end = map_end();
  ASSERT(map_ - 1 <= p && p < end);
  for (p++; p < end; p++) {
    if (p->key != NULL) {
      return p;
    }
  }
  return NULL;
}

HashMap::Entry* HashMap::Probe(void* key, uint32_t hash) {
  ASSERT(key != NULL);

  ASSERT(dart::Utils::IsPowerOfTwo(capacity_));
  Entry* p = map_ + (hash & (capacity_ - 1));
  const Entry* end = map_end();
  ASSERT(map_ <= p && p < end);

  ASSERT(occupancy_ < capacity_);  // Guarantees loop termination.
  while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) {
    p++;
    if (p >= end) {
      p = map_;
    }
  }

  return p;
}

void HashMap::Initialize(uint32_t capacity) {
  ASSERT(dart::Utils::IsPowerOfTwo(capacity));
  map_ = reinterpret_cast<Entry*>(malloc(capacity * sizeof(Entry)));
  if (map_ == NULL) {
    // TODO(sgjesse): Handle out of memory.
    FATAL("Cannot allocate memory for hashmap");
    return;
  }
  capacity_ = capacity;
  Clear();
}

void HashMap::Resize() {
  Entry* map = map_;
  uint32_t n = occupancy_;

  // Allocate larger map.
  Initialize(capacity_ * 2);

  // Rehash all current entries.
  for (Entry* p = map; n > 0; p++) {
    if (p->key != NULL) {
      Lookup(p->key, p->hash, true)->value = p->value;
      n--;
    }
  }

  // Delete old map.
  free(map);
}
<|endoftext|>


<commit_before>#include "RecommendSearchService.h"
#include <recommend-manager/User.h>
#include <recommend-manager/ItemCondition.h>
#include <recommend-manager/UserManager.h>
#include <recommend-manager/ItemManager.h>
#include <recommend-manager/RecommenderFactory.h>
#include <recommend-manager/RecommendParam.h>
#include <recommend-manager/TIBParam.h>
#include <recommend-manager/ItemBundle.h>
#include <recommend-manager/ItemIdGenerator.h>

#include <glog/logging.h>

namespace sf1r
{

RecommendSearchService::RecommendSearchService(
    UserManager& userManager,
    ItemManager& itemManager,
    RecommenderFactory& recommenderFactory,
    UserIdGenerator& userIdGenerator,
    ItemIdGenerator& itemIdGenerator
)
    :userManager_(userManager)
    ,itemManager_(itemManager)
    ,recommenderFactory_(recommenderFactory)
    ,userIdGenerator_(userIdGenerator)
    ,itemIdGenerator_(itemIdGenerator)
{
}

bool RecommendSearchService::getUser(const std::string& userIdStr, User& user)
{
    userid_t userId = 0;

    if (! userIdGenerator_.conv(userIdStr, userId, false))
    {
        LOG(ERROR) << "error in getUser(), user id " << userIdStr << " not yet added before";
        return false;
    }

    return userManager_.getUser(userId, user);
}

bool RecommendSearchService::recommend(
    RecommendParam& param,
    std::vector<RecommendItem>& recItemVec
)
{
    if (!convertIds_(param))
        return false;

    Recommender* recommender = recommenderFactory_.getRecommender(param.type);
    if (recommender && recommender->recommend(param, recItemVec))
        return getRecommendItems_(recItemVec);

    return false;
}

bool RecommendSearchService::convertIds_(RecommendParam& param)
{
    if (!param.userIdStr.empty()
        && !userIdGenerator_.conv(param.userIdStr, param.userId, false))
    {
        LOG(ERROR) << "error in convertIds_(), user id " << param.userIdStr << " not yet added before";
        return false;
    }

    if (!convertItemId_(param.inputItems, param.inputItemIds)
        || !convertItemId_(param.includeItems, param.includeItemIds)
        || !convertItemId_(param.excludeItems, param.excludeItemIds))
    {
        return false;
    }

    return true;
}

bool RecommendSearchService::convertItemId_(
    const std::vector<std::string>& inputItemVec,
    std::vector<itemid_t>& outputItemVec
)
{
    itemid_t itemId = 0;

    for (std::size_t i = 0; i < inputItemVec.size(); ++i)
    {
        if (! itemIdGenerator_.getItemIdByStrId(inputItemVec[i], itemId))
        {
            LOG(ERROR) << "error in convertItemId_(), item id " << inputItemVec[i] << " not yet added before";
            return false;
        }

        outputItemVec.push_back(itemId);
    }

    return true;
}

bool RecommendSearchService::getRecommendItems_(std::vector<RecommendItem>& recItemVec) const
{
    for (std::vector<RecommendItem>::iterator it = recItemVec.begin();
        it != recItemVec.end(); ++it)
    {
        if (! itemManager_.getItem(it->item_.getId(), it->item_))
        {
            LOG(ERROR) << "error in ItemManager::getItem(), item id: " << it->item_.getId();
            return false;
        }

        std::vector<ReasonItem>& reasonItems = it->reasonItems_;
        for (std::vector<ReasonItem>::iterator reasonIt = reasonItems.begin();
            reasonIt != reasonItems.end(); ++reasonIt)
        {
            if (! itemManager_.getItem(reasonIt->item_.getId(), reasonIt->item_))
            {
                LOG(ERROR) << "error in ItemManager::getItem(), item id: " << reasonIt->item_.getId();
                return false;
            }
        }
    }

    return true;
}

bool RecommendSearchService::topItemBundle(
    const TIBParam& param,
    std::vector<ItemBundle>& bundleVec
)
{
    TIBRecommender* recommender = recommenderFactory_.getTIBRecommender();
    if (recommender && recommender->recommend(param, bundleVec))
        return getBundleItems_(bundleVec);

    return false;
}

bool RecommendSearchService::getBundleItems_(std::vector<ItemBundle>& bundleVec) const
{
    for (std::vector<ItemBundle>::iterator bundleIt = bundleVec.begin();
        bundleIt != bundleVec.end(); ++bundleIt)
    {
        std::vector<Document>& items = bundleIt->items;

        for (std::vector<Document>::iterator it = items.begin();
            it != items.end(); ++it)
        {
            if (! itemManager_.getItem(it->getId(), *it))
            {
                LOG(ERROR) << "error in ItemManager::getItem(), item id: " << it->getId();
                return false;
            }
        }
    }

    return true;
}

} // namespace sf1r
<commit_msg>as required by product team, if the conversion on item id failed, instead of making recommendation fail, just skip the non-existing ids, and return recommendation result based on other existing ids.<commit_after>#include "RecommendSearchService.h"
#include <recommend-manager/User.h>
#include <recommend-manager/ItemCondition.h>
#include <recommend-manager/UserManager.h>
#include <recommend-manager/ItemManager.h>
#include <recommend-manager/RecommenderFactory.h>
#include <recommend-manager/RecommendParam.h>
#include <recommend-manager/TIBParam.h>
#include <recommend-manager/ItemBundle.h>
#include <recommend-manager/ItemIdGenerator.h>

#include <glog/logging.h>

namespace sf1r
{

RecommendSearchService::RecommendSearchService(
    UserManager& userManager,
    ItemManager& itemManager,
    RecommenderFactory& recommenderFactory,
    UserIdGenerator& userIdGenerator,
    ItemIdGenerator& itemIdGenerator
)
    :userManager_(userManager)
    ,itemManager_(itemManager)
    ,recommenderFactory_(recommenderFactory)
    ,userIdGenerator_(userIdGenerator)
    ,itemIdGenerator_(itemIdGenerator)
{
}

bool RecommendSearchService::getUser(const std::string& userIdStr, User& user)
{
    userid_t userId = 0;

    if (! userIdGenerator_.conv(userIdStr, userId, false))
    {
        LOG(ERROR) << "error in getUser(), user id " << userIdStr << " not yet added before";
        return false;
    }

    return userManager_.getUser(userId, user);
}

bool RecommendSearchService::recommend(
    RecommendParam& param,
    std::vector<RecommendItem>& recItemVec
)
{
    if (!convertIds_(param))
        return false;

    Recommender* recommender = recommenderFactory_.getRecommender(param.type);
    if (recommender && recommender->recommend(param, recItemVec))
        return getRecommendItems_(recItemVec);

    return false;
}

bool RecommendSearchService::convertIds_(RecommendParam& param)
{
    if (!param.userIdStr.empty()
        && !userIdGenerator_.conv(param.userIdStr, param.userId, false))
    {
        LOG(ERROR) << "error in convertIds_(), user id " << param.userIdStr << " not yet added before";
        return false;
    }

    if (!convertItemId_(param.inputItems, param.inputItemIds)
        || !convertItemId_(param.includeItems, param.includeItemIds)
        || !convertItemId_(param.excludeItems, param.excludeItemIds))
    {
        return false;
    }

    return true;
}

bool RecommendSearchService::convertItemId_(
    const std::vector<std::string>& inputItemVec,
    std::vector<itemid_t>& outputItemVec
)
{
    itemid_t itemId = 0;

    for (std::size_t i = 0; i < inputItemVec.size(); ++i)
    {
        if (itemIdGenerator_.getItemIdByStrId(inputItemVec[i], itemId))
        {
            outputItemVec.push_back(itemId);
        }
        else
        {
            LOG(WARNING) << "in convertItemId_(), item id " << inputItemVec[i] << " not yet added before";
        }
    }

    return true;
}

bool RecommendSearchService::getRecommendItems_(std::vector<RecommendItem>& recItemVec) const
{
    for (std::vector<RecommendItem>::iterator it = recItemVec.begin();
        it != recItemVec.end(); ++it)
    {
        if (! itemManager_.getItem(it->item_.getId(), it->item_))
        {
            LOG(ERROR) << "error in ItemManager::getItem(), item id: " << it->item_.getId();
            return false;
        }

        std::vector<ReasonItem>& reasonItems = it->reasonItems_;
        for (std::vector<ReasonItem>::iterator reasonIt = reasonItems.begin();
            reasonIt != reasonItems.end(); ++reasonIt)
        {
            if (! itemManager_.getItem(reasonIt->item_.getId(), reasonIt->item_))
            {
                LOG(ERROR) << "error in ItemManager::getItem(), item id: " << reasonIt->item_.getId();
                return false;
            }
        }
    }

    return true;
}

bool RecommendSearchService::topItemBundle(
    const TIBParam& param,
    std::vector<ItemBundle>& bundleVec
)
{
    TIBRecommender* recommender = recommenderFactory_.getTIBRecommender();
    if (recommender && recommender->recommend(param, bundleVec))
        return getBundleItems_(bundleVec);

    return false;
}

bool RecommendSearchService::getBundleItems_(std::vector<ItemBundle>& bundleVec) const
{
    for (std::vector<ItemBundle>::iterator bundleIt = bundleVec.begin();
        bundleIt != bundleVec.end(); ++bundleIt)
    {
        std::vector<Document>& items = bundleIt->items;

        for (std::vector<Document>::iterator it = items.begin();
            it != items.end(); ++it)
        {
            if (! itemManager_.getItem(it->getId(), *it))
            {
                LOG(ERROR) << "error in ItemManager::getItem(), item id: " << it->getId();
                return false;
            }
        }
    }

    return true;
}

} // namespace sf1r
<|endoftext|>