<commit_before>/*****************************************************************************
  intersectBed.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licenced under the GNU General Public License 2.0 license.
******************************************************************************/
#include "lineFileUtilities.h"
#include "fjoin.h"
#include <queue>
#include <set>

bool leftOf(const BED &a, const BED &b);

bool BedIntersect::processHits(BED &a, vector<BED> &hits) {
    // how many overlaps are there b/w the bed and the set of hits?
    int s, e, overlapBases;
    int  numOverlaps = 0;
    bool hitsFound   = false;
    int aLength      = (a.end - a.start);   // the length of a in b.p.

    // loop through the hits and report those that meet the user's criteria
    vector<BED>::const_iterator h       = hits.begin();
    vector<BED>::const_iterator hitsEnd = hits.end();
    for (; h != hitsEnd; ++h) {
        s            = max(a.start, h->start);
        e            = min(a.end, h->end);
        overlapBases = (e - s);             // the number of overlapping bases b/w a and b

        // is there enough overlap relative to the user's request? (default ~ 1bp)
        if ( ( (float) overlapBases / (float) aLength ) >= _overlapFraction ) {
            // Report the hit if the user doesn't care about reciprocal overlap between A and B.
            if (_reciprocal == false) {
                hitsFound = true;
                numOverlaps++;
                if (_printable == true)
                    ReportOverlapDetail(overlapBases, a, *h, s, e);
            }
            // we require there to be sufficient __reciprocal__ overlap
            else {
                int bLength    = (h->end - h->start);
                float bOverlap = ( (float) overlapBases / (float) bLength );
                if (bOverlap >= _overlapFraction) {
                    hitsFound = true;
                    numOverlaps++;
                    if (_printable == true)
                        ReportOverlapDetail(overlapBases, a, *h, s, e);
                }
            }
        }
    }
    // report the summary of the overlaps if requested.
    ReportOverlapSummary(a, numOverlaps);
    // were hits found for this BED feature?
    return hitsFound;
}

/*
    Constructor
*/
BedIntersect::BedIntersect(string bedAFile, string bedBFile, bool anyHit,
                           bool writeA, bool writeB, bool writeOverlap, bool writeAllOverlap,
                           float overlapFraction, bool noHit, bool writeCount, bool forceStrand,
                           bool reciprocal, bool obeySplits, bool bamInput, bool bamOutput) {

    _bedAFile            = bedAFile;
    _bedBFile            = bedBFile;
    _anyHit              = anyHit;
    _noHit               = noHit;
    _writeA              = writeA;
    _writeB              = writeB;
    _writeOverlap        = writeOverlap;
    _writeAllOverlap     = writeAllOverlap;
    _writeCount          = writeCount;
    _overlapFraction     = overlapFraction;
    _forceStrand         = forceStrand;
    _reciprocal          = reciprocal;
    _obeySplits          = obeySplits;
    _bamInput            = bamInput;
    _bamOutput           = bamOutput;

    if (_anyHit || _noHit || _writeCount)
        _printable = false;
    else
        _printable = true;

    // create new BED file objects for A and B
    _bedA = new BedFile(bedAFile);
    _bedB = new BedFile(bedBFile);

    IntersectBed();
}

/*
    Destructor
*/
BedIntersect::~BedIntersect(void) {
}

bool leftOf(const BED &a, const BED &b) {
    return (a.end <= b.start);
}

void BedIntersect::ReportOverlapDetail(const int &overlapBases, const BED &a, const BED &b,
                                       const CHRPOS &s, const CHRPOS &e) {
    // default. simple intersection only
    if (_writeA == false && _writeB == false && _writeOverlap == false) {
        _bedA->reportBedRangeNewLine(a,s,e);
    }
    //  -wa -wbwrite the original A and B
    else if (_writeA == true && _writeB == true) {
        _bedA->reportBedTab(a);
        _bedB->reportBedNewLine(b);
    }
    // -wa write just the original A
    else if (_writeA == true) {
        _bedA->reportBedNewLine(a);
    }
    // -wb write the intersected portion of A and the original B
    else if (_writeB == true) {
        _bedA->reportBedRangeTab(a,s,e);
        _bedB->reportBedNewLine(b);
    }
    // -wo write the original A and B plus the no. of overlapping bases.
    else if (_writeOverlap == true) {
        _bedA->reportBedTab(a);
        _bedB->reportBedTab(b);
        printf("%d\n", overlapBases);
    }
}

void BedIntersect::ReportOverlapSummary(const BED &a, const int &numOverlapsFound) {
    // -u  just report the fact that there was >= 1 overlaps
    if (_anyHit && (numOverlapsFound >= 1)) {
        _bedA->reportBedNewLine(a);
    }
    // -c  report the total number of features overlapped in B
    else if (_writeCount) {
        _bedA->reportBedTab(a);
        printf("%d\n", numOverlapsFound);
    }
    // -v  report iff there were no overlaps
    else if (_noHit && (numOverlapsFound == 0)) {
        _bedA->reportBedNewLine(a);
    }
    // -wao the user wants to force the reporting of 0 overlap
    else if (_writeAllOverlap && (numOverlapsFound == 0)) {
        _bedA->reportBedTab(a);
        _bedB->reportNullBedTab();
        printf("0\n");
    }
}

void BedIntersect::Scan(BED *x, vector<BED *> *windowX, BedLineStatus xStatus,
                  const BED &y, vector<BED *> *windowY, BedLineStatus yStatus) {

    if (xStatus != BED_VALID) {
        return;
    }

    std::vector<BED *>::iterator wYIter = windowY->begin();
    while (wYIter != windowY->end()) {
        if (leftOf(*(*wYIter), *x) == true) {
            (*wYIter)->finished = true;
            wYIter = windowY->erase(wYIter);  // erase auto-increments to the next position
        }
        else if (overlaps((*wYIter)->start, (*wYIter)->end, x->start, x->end) > 0) {
            if (_lastPick == 0) {
                AddHits(x, *(*wYIter));
            }
            else {
                AddHits(*wYIter, *x);
            }
            ++wYIter;  // force incrementing
        }
    }
    if (leftOf(*x,y) == false)
        windowX->push_back(x);
    else {
        x->finished = true;
    }
    // dump the buffered results (if any)
    FlushOutputBuffer();
}

void BedIntersect::AddHits(BED *x, const BED &y) {
    if (x->overlaps.empty() == true)
        _outputBuffer.push(x);
    x->overlaps.push_back(y);
}

void BedIntersect::FlushOutputBuffer(bool final) {
    while (_outputBuffer.empty() == false)
    {
        if (final == false && _outputBuffer.front()->finished == false)
            break;

        processHits(*_outputBuffer.front(), _outputBuffer.front()->overlaps);
        // remove the finished BED entry from the heap
        delete _outputBuffer.front();
        _outputBuffer.pop();
    }
}

vector<BED*>* BedIntersect::GetWindow(const string &chrom, bool isA) {

    // iterator to test if a window for a given chrom exists.
    map<string, vector<BED*> >::iterator it;

    // grab the current window for A or B, depending on
    // the request.  if a window hasn't yet been created
    // for the requested chrom, create one.

    if (isA) {
        it = _windowA.find(chrom);
        if (it != _windowA.end()) {
            return & _windowA[chrom];
        }
        else {
            _windowA.insert(pair<string, vector<BED *> >(chrom, vector<BED *>()));
            return & _windowA[chrom];
        }
    }
    else {
        it = _windowB.find(chrom);
        if (it != _windowB.end()) {
            return & _windowB[chrom];
        }
        else {
            _windowB.insert(pair<string, vector<BED *> >(chrom, vector<BED *>()));
            return & _windowB[chrom];
        }
    }
}

void BedIntersect::ChromSwitch(const string &chrom) {

    vector<BED*>::iterator windowAIter = _windowA[chrom].begin();
    vector<BED*>::iterator windowAEnd  = _windowA[chrom].end();
    for (; windowAIter != windowAEnd; ++windowAIter)
        (*windowAIter)->finished = true;

    vector<BED*>::iterator windowBIter = _windowB[chrom].begin();
    vector<BED*>::iterator windowBEnd  = _windowB[chrom].end();
    for (; windowBIter != windowBEnd; ++windowBIter)
        (*windowBIter)->finished = true;

    FlushOutputBuffer();
}

void BedIntersect::IntersectBed() {

    int aLineNum = 0;
    int bLineNum = 0;

    // current feature from each file
    BED *a, *b, *prevA, *prevB;

    // status of the current lines
    BedLineStatus aStatus, bStatus;

    // open the files; get the first line from each
    _bedA->Open();
    _bedB->Open();

    prevA = NULL;
    prevB = NULL;
    a = new BED();
    b = new BED();
    aStatus = _bedA->GetNextBed(*a, aLineNum);
    bStatus = _bedB->GetNextBed(*b, bLineNum);

    while (aStatus != BED_INVALID || bStatus != BED_INVALID) {

        if ((a->start <= b->start) && (a->chrom == b->chrom)) {
            prevA = a;
            _lastPick = 0;
            Scan(a, GetWindow(a->chrom, true),  aStatus,
                *b, GetWindow(a->chrom, false), bStatus);

            a = new BED();
            aStatus = _bedA->GetNextBed(*a, aLineNum);
        }
        else if ((a->start > b->start) && (a->chrom == b->chrom)) {
            prevB = b;
            _lastPick = 1;
            Scan(b, GetWindow(b->chrom, false), bStatus,
                *a, GetWindow(b->chrom, true),  aStatus);

            b = new BED();
            bStatus = _bedB->GetNextBed(*b, bLineNum);
        }
        else if (a->chrom != b->chrom) {
            // A was most recently read
            if (_lastPick == 0) {
                prevB = b;
                while (b->chrom == prevA->chrom){
                    _windowB[prevA->chrom].push_back(b);
                    b = new BED();
                    bStatus = _bedB->GetNextBed(*b, bLineNum);
                }
                Scan(prevA, GetWindow(prevA->chrom, true),  aStatus,
                    *prevB, GetWindow(prevA->chrom, false),  bStatus);
            }
            // B was most recently read
            else {
                prevA = a;
                while (a->chrom == prevB->chrom) {
                    _windowA[prevB->chrom].push_back(a);
                    a = new BED();
                    aStatus = _bedA->GetNextBed(*a, aLineNum);
                }
                Scan(prevB, GetWindow(prevB->chrom, false), bStatus,
                    *prevA, GetWindow(prevB->chrom, true),  aStatus);
            }
            FlushOutputBuffer(true);
        }
        if (prevA!=NULL&&prevB!=NULL)
            cout << prevA->chrom << " " << a->chrom << " " << a->start << " "
                 << prevB->chrom << " " << b->chrom << " " << b->start << "\n";
        if (aStatus == BED_INVALID) a->start = INT_MAX;
        if (bStatus == BED_INVALID) b->start = INT_MAX;
    }

    // clear out the final bit of staged output
    FlushOutputBuffer(true);

    // close the files
    _bedA->Close();
    _bedB->Close();
}

<commit_msg>Tweaked fjoin reporting.<commit_after>/*****************************************************************************
  intersectBed.cpp

  (c) 2009 - Aaron Quinlan
  Hall Laboratory
  Department of Biochemistry and Molecular Genetics
  University of Virginia
  aaronquinlan@gmail.com

  Licenced under the GNU General Public License 2.0 license.
******************************************************************************/
#include "lineFileUtilities.h"
#include "fjoin.h"
#include <queue>
#include <set>

bool leftOf(const BED &a, const BED &b);

bool BedIntersect::processHits(BED &a, vector<BED> &hits) {
    // how many overlaps are there b/w the bed and the set of hits?
    int s, e, overlapBases;
    int  numOverlaps = 0;
    bool hitsFound   = false;
    int aLength      = (a.end - a.start);   // the length of a in b.p.

    // loop through the hits and report those that meet the user's criteria
    vector<BED>::const_iterator h       = hits.begin();
    vector<BED>::const_iterator hitsEnd = hits.end();
    for (; h != hitsEnd; ++h) {
        s            = max(a.start, h->start);
        e            = min(a.end, h->end);
        overlapBases = (e - s);             // the number of overlapping bases b/w a and b

        // is there enough overlap relative to the user's request? (default ~ 1bp)
        if ( ( (float) overlapBases / (float) aLength ) >= _overlapFraction ) {
            // Report the hit if the user doesn't care about reciprocal overlap between A and B.
            if (_reciprocal == false) {
                hitsFound = true;
                numOverlaps++;
                if (_printable == true)
                    ReportOverlapDetail(overlapBases, a, *h, s, e);
            }
            // we require there to be sufficient __reciprocal__ overlap
            else {
                int bLength    = (h->end - h->start);
                float bOverlap = ( (float) overlapBases / (float) bLength );
                if (bOverlap >= _overlapFraction) {
                    hitsFound = true;
                    numOverlaps++;
                    if (_printable == true)
                        ReportOverlapDetail(overlapBases, a, *h, s, e);
                }
            }
        }
    }
    // report the summary of the overlaps if requested.
    ReportOverlapSummary(a, numOverlaps);
    // were hits found for this BED feature?
    return hitsFound;
}

/*
    Constructor
*/
BedIntersect::BedIntersect(string bedAFile, string bedBFile, bool anyHit,
                           bool writeA, bool writeB, bool writeOverlap, bool writeAllOverlap,
                           float overlapFraction, bool noHit, bool writeCount, bool forceStrand,
                           bool reciprocal, bool obeySplits, bool bamInput, bool bamOutput) {

    _bedAFile            = bedAFile;
    _bedBFile            = bedBFile;
    _anyHit              = anyHit;
    _noHit               = noHit;
    _writeA              = writeA;
    _writeB              = writeB;
    _writeOverlap        = writeOverlap;
    _writeAllOverlap     = writeAllOverlap;
    _writeCount          = writeCount;
    _overlapFraction     = overlapFraction;
    _forceStrand         = forceStrand;
    _reciprocal          = reciprocal;
    _obeySplits          = obeySplits;
    _bamInput            = bamInput;
    _bamOutput           = bamOutput;

    if (_anyHit || _noHit || _writeCount)
        _printable = false;
    else
        _printable = true;

    // create new BED file objects for A and B
    _bedA = new BedFile(bedAFile);
    _bedB = new BedFile(bedBFile);

    IntersectBed();
}

/*
    Destructor
*/
BedIntersect::~BedIntersect(void) {
}

bool leftOf(const BED &a, const BED &b) {
    return (a.end <= b.start);
}

void BedIntersect::ReportOverlapDetail(const int &overlapBases, const BED &a, const BED &b,
                                       const CHRPOS &s, const CHRPOS &e) {
    // default. simple intersection only
    if (_writeA == false && _writeB == false && _writeOverlap == false) {
        _bedA->reportBedRangeNewLine(a,s,e);
    }
    //  -wa -wbwrite the original A and B
    else if (_writeA == true && _writeB == true) {
        _bedA->reportBedTab(a);
        _bedB->reportBedNewLine(b);
    }
    // -wa write just the original A
    else if (_writeA == true) {
        _bedA->reportBedNewLine(a);
    }
    // -wb write the intersected portion of A and the original B
    else if (_writeB == true) {
        _bedA->reportBedRangeTab(a,s,e);
        _bedB->reportBedNewLine(b);
    }
    // -wo write the original A and B plus the no. of overlapping bases.
    else if (_writeOverlap == true) {
        _bedA->reportBedTab(a);
        _bedB->reportBedTab(b);
        printf("%d\n", overlapBases);
    }
}

void BedIntersect::ReportOverlapSummary(const BED &a, const int &numOverlapsFound) {
    // -u  just report the fact that there was >= 1 overlaps
    if (_anyHit && (numOverlapsFound >= 1)) {
        _bedA->reportBedNewLine(a);
    }
    // -c  report the total number of features overlapped in B
    else if (_writeCount) {
        _bedA->reportBedTab(a);
        printf("%d\n", numOverlapsFound);
    }
    // -v  report iff there were no overlaps
    else if (_noHit && (numOverlapsFound == 0)) {
        _bedA->reportBedNewLine(a);
    }
    // -wao the user wants to force the reporting of 0 overlap
    else if (_writeAllOverlap && (numOverlapsFound == 0)) {
        _bedA->reportBedTab(a);
        _bedB->reportNullBedTab();
        printf("0\n");
    }
}

void BedIntersect::Scan(BED *x, vector<BED *> *windowX, BedLineStatus xStatus,
                  const BED &y, vector<BED *> *windowY, BedLineStatus yStatus) {

    if (xStatus != BED_VALID) {
        return;
    }

    std::vector<BED *>::iterator wYIter = windowY->begin();
    while (wYIter != windowY->end()) {
        if (leftOf(*(*wYIter), *x) == true) {
            (*wYIter)->finished = true;
            wYIter = windowY->erase(wYIter);  // erase auto-increments to the next position
        }
        else if (overlaps((*wYIter)->start, (*wYIter)->end, x->start, x->end) > 0) {
            if (_lastPick == 0) {
                AddHits(x, *(*wYIter));
            }
            else {
                AddHits(*wYIter, *x);
            }
            ++wYIter;  // force incrementing
        }
    }
    if (leftOf(*x,y) == false)
        windowX->push_back(x);
    else {
        x->finished = true;
    }
    // dump the buffered results (if any)
    FlushOutputBuffer();
}

void BedIntersect::AddHits(BED *x, const BED &y) {
    if (x->overlaps.empty() == true)
        _outputBuffer.push(x);
    x->overlaps.push_back(y);
}

void BedIntersect::FlushOutputBuffer(bool final) {
    while (_outputBuffer.empty() == false)
    {
        if (final == false && _outputBuffer.front()->finished == false)
            break;

        processHits(*_outputBuffer.front(), _outputBuffer.front()->overlaps);
        // remove the finished BED entry from the heap
        delete _outputBuffer.front();
        _outputBuffer.pop();
    }
}

vector<BED*>* BedIntersect::GetWindow(const string &chrom, bool isA) {

    // iterator to test if a window for a given chrom exists.
    map<string, vector<BED*> >::iterator it;

    // grab the current window for A or B, depending on
    // the request.  if a window hasn't yet been created
    // for the requested chrom, create one.

    if (isA) {
        it = _windowA.find(chrom);
        if (it != _windowA.end()) {
            return & _windowA[chrom];
        }
        else {
            _windowA.insert(pair<string, vector<BED *> >(chrom, vector<BED *>()));
            return & _windowA[chrom];
        }
    }
    else {
        it = _windowB.find(chrom);
        if (it != _windowB.end()) {
            return & _windowB[chrom];
        }
        else {
            _windowB.insert(pair<string, vector<BED *> >(chrom, vector<BED *>()));
            return & _windowB[chrom];
        }
    }
}

void BedIntersect::ChromSwitch(const string &chrom) {

    vector<BED*>::iterator windowAIter = _windowA[chrom].begin();
    vector<BED*>::iterator windowAEnd  = _windowA[chrom].end();
    for (; windowAIter != windowAEnd; ++windowAIter)
        (*windowAIter)->finished = true;

    vector<BED*>::iterator windowBIter = _windowB[chrom].begin();
    vector<BED*>::iterator windowBEnd  = _windowB[chrom].end();
    for (; windowBIter != windowBEnd; ++windowBIter)
        (*windowBIter)->finished = true;

    FlushOutputBuffer();
}

void BedIntersect::IntersectBed() {

    int aLineNum = 0;
    int bLineNum = 0;

    // current feature from each file
    BED *a, *b, *prevA, *prevB;

    // status of the current lines
    BedLineStatus aStatus, bStatus;

    // open the files; get the first line from each
    _bedA->Open();
    _bedB->Open();

    prevA = NULL;
    prevB = NULL;
    a = new BED();
    b = new BED();
    aStatus = _bedA->GetNextBed(*a, aLineNum);
    bStatus = _bedB->GetNextBed(*b, bLineNum);

    while (aStatus != BED_INVALID || bStatus != BED_INVALID) {

        if ((a->start <= b->start) && (a->chrom == b->chrom)) {
            prevA = a;
            _lastPick = 0;
            Scan(a, GetWindow(a->chrom, true),  aStatus,
                *b, GetWindow(a->chrom, false), bStatus);

            a = new BED();
            aStatus = _bedA->GetNextBed(*a, aLineNum);
        }
        else if ((a->start > b->start) && (a->chrom == b->chrom)) {
            prevB = b;
            _lastPick = 1;
            Scan(b, GetWindow(b->chrom, false), bStatus,
                *a, GetWindow(b->chrom, true),  aStatus);

            b = new BED();
            bStatus = _bedB->GetNextBed(*b, bLineNum);
        }
        else if (a->chrom != b->chrom) {
            // A was most recently read
            if (_lastPick == 0) {
                prevB = b;
                while (b->chrom == prevA->chrom){
                    _windowB[prevA->chrom].push_back(b);
                    b = new BED();
                    bStatus = _bedB->GetNextBed(*b, bLineNum);
                }
                Scan(prevA, GetWindow(prevA->chrom, true),  aStatus,
                    *prevB, GetWindow(prevA->chrom, false),  bStatus);
            }
            // B was most recently read
            else {
                prevA = a;
                while (a->chrom == prevB->chrom) {
                    _windowA[prevB->chrom].push_back(a);
                    a = new BED();
                    aStatus = _bedA->GetNextBed(*a, aLineNum);
                }
                Scan(prevB, GetWindow(prevB->chrom, false), bStatus,
                    *prevA, GetWindow(prevB->chrom, true),  aStatus);
            }
            FlushOutputBuffer(true);
        }
        if (prevA!=NULL&&prevB!=NULL)
            //cout << prevA->chrom << " " << a->chrom << " " << a->start << " "
            //     << prevB->chrom << " " << b->chrom << " " << b->start << "\n";
        if (aStatus == BED_INVALID) a->start = INT_MAX;
        if (bStatus == BED_INVALID) b->start = INT_MAX;
    }

    // clear out the final bit of staged output
    FlushOutputBuffer(true);

    // close the files
    _bedA->Close();
    _bedB->Close();
}

<|endoftext|>


<commit_before>#include "generations.h"
//TODO: time-based killing
Generations::Generations(string input, string output){
	this->population_id = 0;
	this->begin_exec = clock();
	this->output = output;

	Instance instance;
	Chromosome chromosome;

	instance.read_instance(input);
	for(unsigned int i = 0; i < _POPULATION_SIZE; i++){
		vector<Task> tasks(instance.get_tasks());
		random_shuffle(tasks.begin(), tasks.end());

		Order order;
		order.init(tasks, instance.get_maitenances());
		chromosome.order = order;
		chromosome.rank = 0;
		this->population.push_back(chromosome);
	}
	sort_population();
	this->previous_population = population;
	this->maintanance_v = instance.get_maitenances();
	this->first_order = population[0].order.get_exectime();
}

int Generations::average(){
	int av = 0;
	for (unsigned i = 0; i < population.size(); i++ ){
		av += previous_population[i].order.get_exectime();
	}
	return av / _POPULATION_SIZE;
}

void Generations::selection(){
	//unsigned int av;
	double r;
	//if (population_id == 0) av = 0;
	//else av = average();

	for (unsigned i = 0; i < population.size(); i++ ){
		r = population[i].order.get_exectime();
		population[i].rank = r;
	}
}

void Generations::rebuild(vector<Task>& tasks, int resection){
		vector<int> missing_tasks;
		vector<int> duplicates;
		vector<Task> all_tasks(this->previous_population[0].order.get_tasks());

		for (int i = 0; i < resection; i++){
			for (unsigned j = resection; j < tasks.size(); j++){
				if(tasks[i].get_id() == tasks[j].get_id()) {
					duplicates.push_back(j);
					break;
				}
			}
		}

		for (unsigned int i = 0; i < all_tasks.size(); i++){
			if(find(tasks.begin(), tasks.end(), all_tasks[i]) == tasks.end() && find(missing_tasks.begin(), missing_tasks.end(), i) == missing_tasks.end()) missing_tasks.push_back(i);
		}

		for (unsigned int i = 0; i < duplicates.size(); i++) tasks[duplicates[i]] = all_tasks[missing_tasks[i]];

		time_exceeded();
}

void Generations::remove_weak(){
	int remove_count = floor(_POPULATION_SIZE * _REMOVE_PCT/100.0);
	random_device rd;
	mt19937_64 gen(rd());
	uniform_int_distribution<int> dist(0, 99);
	vector<int> to_remove;

	sort_population();
	for(int i = _POPULATION_SIZE - 1; i >= 0; i--){
		if(dist(gen) >= _REMOVE_FAIL_PCT){
			population.erase(population.begin() + i);
			remove_count--;
		}
		if (remove_count == 0) break;
	}

	time_exceeded();

	this->previous_population = this->population;
}

bool Generations::crossing_over(int itterator){
	random_device rd;
	mt19937_64 gen(rd());
	uniform_int_distribution<int> random_resection(_MIN_RESECTION_PCT, _MAX_RESECTION_PCT);
	uniform_int_distribution<int> random_chromosome(0, floor(_POPULATION_SIZE * _REMOVE_PCT/100.0) - 1);
	int chromosome1_num = random_chromosome(gen);
	int chromosome2_num = random_chromosome(gen);
	while(chromosome1_num == chromosome2_num) chromosome2_num = random_chromosome(gen);
	vector<Task> tmp(previous_population[chromosome1_num].order.get_tasks());
	int resection = floor(tmp.size() * random_resection(gen)/100.0);
	if (resection <= 0) return false;
	vector<Task> tasks(&tmp[0], &tmp[resection]);
	tmp = previous_population[chromosome2_num].order.get_tasks();
	vector<Task> tasks2(&tmp[resection], &tmp[tmp.size()]);
	tasks.insert(tasks.end(), tasks2.begin(), tasks2.end());

	this->rebuild(tasks, resection);

	Order order;
	order.init(tasks, this->maintanance_v);
	Chromosome new_chromosome;
	new_chromosome.order = order;
	new_chromosome.rank = 0;
	this->population.push_back(new_chromosome);

	time_exceeded();

	return true;
}

void Generations::mutate(int chromosome_id){
	random_device rd;
	mt19937_64 gen(rd());
	vector<Task> tasks = population[chromosome_id].order.get_tasks();
	uniform_int_distribution<int> random_task_id(0, tasks.size() - 1);
	int task_id[2];

	task_id[0] = random_task_id(gen);
	task_id[1] = random_task_id(gen);
	while(task_id[0] == task_id[1]) task_id[1] = random_task_id(gen);

	iter_swap(tasks.begin() + task_id[0], tasks.begin() + task_id[1]);

	Order order;
	order.init(tasks, this->maintanance_v);
	Chromosome new_chromosome;
	new_chromosome.order = order;
	new_chromosome.rank = 0;
	population[chromosome_id] = new_chromosome;

	time_exceeded();
}

inline bool Less_than_rank::operator() (const Chromosome& chromosome1, const Chromosome& chromosome2){
	return (chromosome1.rank < chromosome2.rank);
}

void Generations::sort_population(){
	sort(population.begin(), population.end(), Less_than_rank());
}

void Generations::next_generation(){
	random_device rd;
	mt19937_64 gen(rd());
	uniform_int_distribution<int> random_mutation(0, 100);
	selection();
	remove_weak();

	this->population.clear();
	for (unsigned int i = 0; i < _POPULATION_SIZE; i++){
//	std::cout<<"du\n";
		crossing_over(i);
	//std::cout<<"da\n";
		if(random_mutation(gen) < _MUTATION_CHANCE_PCT) {
			mutate(i);
		}
	}
	this->population_id++;

	time_exceeded();
}

void Generations::dump_generation(string filename){
	ofstream dump;
	unsigned int m_iter = 0;
	int st = 0, tf = 0,  m_sum = 0, idle = 0, idle_1_t = 0, idle_2_t = 0; //start time, to finish, maitanance iterator
	char d = ','; // delimiter
	dump.open(filename.c_str());
	dump << "***" /*<< id*/ << "****" << endl;
	//rank
	sort_population();
	dump << population[0].order.get_exectime() << d << first_order << endl;
	dump << "M1:";
	vector <Task> t = population[0].order.get_tasks();
	/*for (unsigned int i = 0; i < maintanance_v.size(); i++){
        m_sum += maintanance_v[i].get_duration();
        std::cout<< i << " " << maintanance_v[i].get_duration() << '\n';
    }*/
    st = 0;
 /*   std::cout<<"************************\n";
    for (unsigned int i = 0; i < t.size(); i++)
    {
        std::cout<< t[i].get_start_t(1) << "    " << t[i].get_op_t(1) <<endl;

    }*/
    std::cout<< "id" << "\t" << "start" << "\t" << "op_time" << "\t" << "end_time" << "\t" << "punished"<< endl;
     for (unsigned int i = 0; i < t.size(); i++)
    {
        int time;
        if (t[i].is_punished()==true){
        	time = t[i].get_punished_op_t();
        } else{
        	time = t[i].get_op_t(1);
        }
        std::cout<< t[i].get_id() << "\t" << t[i].get_start_t(1) << "\t" << time << "\t" << t[i].get_start_t(1) + time << "\t\t" <<  t[i].is_punished() << endl;

    }
    std::cout<< "************\n";
    for (unsigned int i = 0; i < maintanance_v.size(); i++){
        m_sum += maintanance_v[i].get_duration();
        std::cout<< i << "\t" <<  maintanance_v[i].get_start_t() << "\t" << maintanance_v[i].get_duration() << '\n';
    }

    for (unsigned int i = 0; i < t.size(); i++){
        if (m_iter < maintanance_v.size()){
        if (t[i].is_punished()==false){
            if (maintanance_v[m_iter].get_start_t() > t[i].get_start_t(1)){
                if (st < t[i].get_start_t(1)){

                        dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d  ;
                        idle_1_t += t[i].get_start_t(1) - st;
                        idle++;
                }

                dump << "op1_k" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_op_t(1) << d;
                st = t[i].get_start_t(1) + t[i].get_op_t(1);
            }else{
                if (st < maintanance_v[m_iter].get_start_t() ){
                    dump << "idle1_" << idle << d << st << d << maintanance_v[m_iter].get_start_t() - st  << d;
                    idle_1_t += maintanance_v[m_iter].get_start_t() - st;
                    idle++;
                }
                dump << "maint1_" << m_iter <<d << maintanance_v[m_iter].get_start_t() << d << maintanance_v[m_iter].get_duration() << d;
                st = maintanance_v[m_iter].get_start_t() + maintanance_v[m_iter].get_duration();
                m_iter++;

                if (st < t[i].get_start_t(1)){
                        dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d;
                        idle_1_t += t[i].get_start_t(1) - st;
                        idle ++;
                }
                dump << "op1_o" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_op_t(1)<<d;
                st = t[i].get_start_t(1) + t[i].get_op_t(1);
                }
            }else{ // punished
                if (st < t[i].get_start_t(1)){
                    dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d;
                    idle_1_t += t[i].get_start_t(1) - st;
                    idle++;
                }
                    tf = t[i].get_punished_op_t() - (t[i].get_punished_op_t() - maintanance_v[m_iter].get_start_t());
                    dump << "op1_" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_punished_op_t() - maintanance_v[m_iter].get_start_t() << d;
                    dump << "maint1_" << m_iter << d << maintanance_v[m_iter].get_start_t() << d << maintanance_v[m_iter].get_duration() << d;
                    dump << "op1_" << t[i].get_id() << d << maintanance_v[m_iter].get_start_t() + maintanance_v[m_iter].get_duration() << d << tf << d;
                    st = maintanance_v[m_iter].get_start_t() + maintanance_v[m_iter].get_duration() + tf;
                    m_iter++;
            }
        }else{
            if(st < t[i].get_start_t(1)){
                dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d;
                idle++;
                idle_1_t += t[i].get_start_t(1) - st;
            }
            dump << "op1_" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_op_t(1) << d;
            st = t[i].get_start_t(1) + t[i].get_op_t(1);
        }

        }
        st = 0;
        idle = 0;
        dump << endl;
        dump << "M2:";
        t = population[0].order.get_tasks_2();
        for( unsigned int i = 0; i< t.size(); i++){
            if(st < t[i].get_start_t(2)){
                dump << "idle2_" << idle << d << st << d << t[i].get_start_t(2) - st << d;
                idle++;
                idle_2_t += t[i].get_start_t(2) - st;
            }
            dump << "op2_" << t[i].get_id() << d << t[i].get_start_t(2) << d << t[i].get_op_t(2) << d;
            st = t[i].get_start_t(2) + t[i].get_op_t(2);
        }

    dump << endl;
    dump << m_sum <<'\n';
    dump << 0 << '\n';
    dump << idle_1_t << '\n';
    dump << idle_2_t << '\n';
    dump << "***EOF***";
	dump.close();
}

bool Generations::time_exceeded(){
	clock_t end = clock();
	double elapsed_secs = double(end - this->begin_exec) / CLOCKS_PER_SEC;;
	if(elapsed_secs > _EXEC_TIME_SECS){
		dump_generation(this->output);
		exit(0);
		return true;
	}
	return false;
}
<commit_msg>dump fix<commit_after>#include "generations.h"
//TODO: time-based killing
Generations::Generations(string input, string output){
	this->population_id = 0;
	this->begin_exec = clock();
	this->output = output;

	Instance instance;
	Chromosome chromosome;

	instance.read_instance(input);
	for(unsigned int i = 0; i < _POPULATION_SIZE; i++){
		vector<Task> tasks(instance.get_tasks());
		random_shuffle(tasks.begin(), tasks.end());

		Order order;
		order.init(tasks, instance.get_maitenances());
		chromosome.order = order;
		chromosome.rank = 0;
		this->population.push_back(chromosome);
	}
	sort_population();
	this->previous_population = population;
	this->maintanance_v = instance.get_maitenances();
	this->first_order = population[0].order.get_exectime();
}

int Generations::average(){
	int av = 0;
	for (unsigned i = 0; i < population.size(); i++ ){
		av += previous_population[i].order.get_exectime();
	}
	return av / _POPULATION_SIZE;
}

void Generations::selection(){
	//unsigned int av;
	double r;
	//if (population_id == 0) av = 0;
	//else av = average();

	for (unsigned i = 0; i < population.size(); i++ ){
		r = population[i].order.get_exectime();
		population[i].rank = r;
	}
}

void Generations::rebuild(vector<Task>& tasks, int resection){
		vector<int> missing_tasks;
		vector<int> duplicates;
		vector<Task> all_tasks(this->previous_population[0].order.get_tasks());

		for (int i = 0; i < resection; i++){
			for (unsigned j = resection; j < tasks.size(); j++){
				if(tasks[i].get_id() == tasks[j].get_id()) {
					duplicates.push_back(j);
					break;
				}
			}
		}

		for (unsigned int i = 0; i < all_tasks.size(); i++){
			if(find(tasks.begin(), tasks.end(), all_tasks[i]) == tasks.end() && find(missing_tasks.begin(), missing_tasks.end(), i) == missing_tasks.end()) missing_tasks.push_back(i);
		}

		for (unsigned int i = 0; i < duplicates.size(); i++) tasks[duplicates[i]] = all_tasks[missing_tasks[i]];

		time_exceeded();
}

void Generations::remove_weak(){
	int remove_count = floor(_POPULATION_SIZE * _REMOVE_PCT/100.0);
	random_device rd;
	mt19937_64 gen(rd());
	uniform_int_distribution<int> dist(0, 99);
	vector<int> to_remove;

	sort_population();
	for(int i = _POPULATION_SIZE - 1; i >= 0; i--){
		if(dist(gen) >= _REMOVE_FAIL_PCT){
			population.erase(population.begin() + i);
			remove_count--;
		}
		if (remove_count == 0) break;
	}

	time_exceeded();

	this->previous_population = this->population;
}

bool Generations::crossing_over(int itterator){
	random_device rd;
	mt19937_64 gen(rd());
	uniform_int_distribution<int> random_resection(_MIN_RESECTION_PCT, _MAX_RESECTION_PCT);
	uniform_int_distribution<int> random_chromosome(0, floor(_POPULATION_SIZE * _REMOVE_PCT/100.0) - 1);
	int chromosome1_num = random_chromosome(gen);
	int chromosome2_num = random_chromosome(gen);
	while(chromosome1_num == chromosome2_num) chromosome2_num = random_chromosome(gen);
	vector<Task> tmp(previous_population[chromosome1_num].order.get_tasks());
	int resection = floor(tmp.size() * random_resection(gen)/100.0);
	if (resection <= 0) return false;
	vector<Task> tasks(&tmp[0], &tmp[resection]);
	tmp = previous_population[chromosome2_num].order.get_tasks();
	vector<Task> tasks2(&tmp[resection], &tmp[tmp.size()]);
	tasks.insert(tasks.end(), tasks2.begin(), tasks2.end());

	this->rebuild(tasks, resection);

	Order order;
	order.init(tasks, this->maintanance_v);
	Chromosome new_chromosome;
	new_chromosome.order = order;
	new_chromosome.rank = 0;
	this->population.push_back(new_chromosome);

	time_exceeded();

	return true;
}

void Generations::mutate(int chromosome_id){
	random_device rd;
	mt19937_64 gen(rd());
	vector<Task> tasks = population[chromosome_id].order.get_tasks();
	uniform_int_distribution<int> random_task_id(0, tasks.size() - 1);
	int task_id[2];

	task_id[0] = random_task_id(gen);
	task_id[1] = random_task_id(gen);
	while(task_id[0] == task_id[1]) task_id[1] = random_task_id(gen);

	iter_swap(tasks.begin() + task_id[0], tasks.begin() + task_id[1]);

	Order order;
	order.init(tasks, this->maintanance_v);
	Chromosome new_chromosome;
	new_chromosome.order = order;
	new_chromosome.rank = 0;
	population[chromosome_id] = new_chromosome;

	time_exceeded();
}

inline bool Less_than_rank::operator() (const Chromosome& chromosome1, const Chromosome& chromosome2){
	return (chromosome1.rank < chromosome2.rank);
}

void Generations::sort_population(){
	sort(population.begin(), population.end(), Less_than_rank());
}

void Generations::next_generation(){
	random_device rd;
	mt19937_64 gen(rd());
	uniform_int_distribution<int> random_mutation(0, 100);
	selection();
	remove_weak();

	this->population.clear();
	for (unsigned int i = 0; i < _POPULATION_SIZE; i++){
//	std::cout<<"du\n";
		crossing_over(i);
	//std::cout<<"da\n";
		if(random_mutation(gen) < _MUTATION_CHANCE_PCT) {
			mutate(i);
		}
	}
	this->population_id++;

	time_exceeded();
}

void Generations::dump_generation(string filename){
	ofstream dump;
	unsigned int m_iter = 0;
	int st = 0, tf = 0,  m_sum = 0, idle = 0, idle_1_t = 0, idle_2_t = 0; //start time, to finish, maitanance iterator
	char d = ','; // delimiter
	dump.open(filename.c_str());
	dump << "***" /*<< id*/ << "****" << endl;
	//rank
	sort_population();
	dump << population[0].order.get_exectime() << d << first_order << endl;
	dump << "M1:";
	vector <Task> t = population[0].order.get_tasks();
	/*for (unsigned int i = 0; i < maintanance_v.size(); i++){
        m_sum += maintanance_v[i].get_duration();
        std::cout<< i << " " << maintanance_v[i].get_duration() << '\n';
    }*/
    st = 0;
 /*   std::cout<<"************************\n";
    for (unsigned int i = 0; i < t.size(); i++)
    {
        std::cout<< t[i].get_start_t(1) << "    " << t[i].get_op_t(1) <<endl;

    }*/
    std::cout<< "id" << "\t" << "start" << "\t" << "op_time" << "\t" << "end_time" << "\t" << "punished"<< endl;
     for (unsigned int i = 0; i < t.size(); i++)
    {
        int time;
        if (t[i].is_punished()==true){
        	time = t[i].get_punished_op_t();
        } else{
        	time = t[i].get_op_t(1);
        }
        std::cout<< t[i].get_id() << "\t" << t[i].get_start_t(1) << "\t" << time << "\t" << t[i].get_start_t(1) + time << "\t\t" <<  t[i].is_punished() << endl;

    }
    std::cout<< "************\n";
    for (unsigned int i = 0; i < maintanance_v.size(); i++){
        m_sum += maintanance_v[i].get_duration();
        std::cout<< i << "\t" <<  maintanance_v[i].get_start_t() << "\t" << maintanance_v[i].get_duration() << '\n';
    }

    for (unsigned int i = 0; i < t.size(); i++){
        if (m_iter < maintanance_v.size()){
        if (t[i].is_punished()==false){
            if (maintanance_v[m_iter].get_start_t() > t[i].get_start_t(1)){
                if (st < t[i].get_start_t(1)){

                        dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d  ;
                        idle_1_t += t[i].get_start_t(1) - st;
                        idle++;
                }

                dump << "op1_k" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_op_t(1) << d;
                st = t[i].get_start_t(1) + t[i].get_op_t(1);
            }else{
                if (st < maintanance_v[m_iter].get_start_t() ){
                    dump << "idle1_" << idle << d << st << d << maintanance_v[m_iter].get_start_t() - st  << d;
                    idle_1_t += maintanance_v[m_iter].get_start_t() - st;
                    idle++;
                }
                dump << "maint1_" << m_iter <<d << maintanance_v[m_iter].get_start_t() << d << maintanance_v[m_iter].get_duration() << d;
                st = maintanance_v[m_iter].get_start_t() + maintanance_v[m_iter].get_duration();
                m_iter++;

                if (st < t[i].get_start_t(1)){
                        dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d;
                        idle_1_t += t[i].get_start_t(1) - st;
                        idle ++;
                }
                dump << "op1_o" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_op_t(1)<<d;
                st = t[i].get_start_t(1) + t[i].get_op_t(1);
                }
            }else{ // punished
                if (st < t[i].get_start_t(1)){
                    dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d;
                    idle_1_t += t[i].get_start_t(1) - st;
                    idle++;
                }
                    tf = t[i].get_punished_op_t() - (maintanance_v[m_iter].get_start_t() - t[i].get_start_t(1));
                    dump << "op1_w" << t[i].get_id() << d << t[i].get_start_t(1) << d <<  maintanance_v[m_iter].get_start_t() - t[i].get_start_t(1) << d;
                    dump << "maint1_" << m_iter << d << maintanance_v[m_iter].get_start_t() << d << maintanance_v[m_iter].get_duration() << d;
                    dump << "op1_g" << t[i].get_id() << d << maintanance_v[m_iter].get_start_t() + maintanance_v[m_iter].get_duration() << d << tf << d;
                    st = maintanance_v[m_iter].get_start_t() + maintanance_v[m_iter].get_duration() + tf;
                    m_iter++;
            }
        }else{
            if(st < t[i].get_start_t(1)){
                dump << "idle1_" << idle << d << st << d << t[i].get_start_t(1) - st << d;
                idle++;
                idle_1_t += t[i].get_start_t(1) - st;
            }
            dump << "op1_" << t[i].get_id() << d << t[i].get_start_t(1) << d << t[i].get_op_t(1) << d;
            st = t[i].get_start_t(1) + t[i].get_op_t(1);
        }

        }
        st = 0;
        idle = 0;
        dump << endl;
        dump << "M2:";
        t = population[0].order.get_tasks_2();
        for( unsigned int i = 0; i< t.size(); i++){
            if(st < t[i].get_start_t(2)){
                dump << "idle2_" << idle << d << st << d << t[i].get_start_t(2) - st << d;
                idle++;
                idle_2_t += t[i].get_start_t(2) - st;
            }
            dump << "op2_" << t[i].get_id() << d << t[i].get_start_t(2) << d << t[i].get_op_t(2) << d;
            st = t[i].get_start_t(2) + t[i].get_op_t(2);
        }

    dump << endl;
    dump << m_sum <<'\n';
    dump << 0 << '\n';
    dump << idle_1_t << '\n';
    dump << idle_2_t << '\n';
    dump << "***EOF***";
	dump.close();
}

bool Generations::time_exceeded(){
	clock_t end = clock();
	double elapsed_secs = double(end - this->begin_exec) / CLOCKS_PER_SEC;;
	if(elapsed_secs > _EXEC_TIME_SECS){
		dump_generation(this->output);
		exit(0);
		return true;
	}
	return false;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// macho_walker.cc: Iterate over the load commands in a mach-o file
//
// See macho_walker.h for documentation
//
// Author: Dan Waylonis

extern "C" {  // necessary for Leopard
  #include <assert.h>
  #include <fcntl.h>
  #include <mach-o/arch.h>
  #include <mach-o/loader.h>
  #include <mach-o/swap.h>
  #include <string.h>
  #include <unistd.h>
}

#include "common/mac/byteswap.h"
#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"

namespace MacFileUtilities {

MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
                         void *context)
    : file_(0),
      memory_(NULL),
      memory_size_(0),
      callback_(callback),
      callback_context_(context),
      current_header_(NULL),
      current_header_size_(0),
      current_header_offset_(0) {
  file_ = open(path, O_RDONLY);
}

MachoWalker::MachoWalker(void *memory, size_t size,
                         LoadCommandCallback callback, void *context)
    : file_(0),
      memory_(memory),
      memory_size_(size),
      callback_(callback),
      callback_context_(context),
      current_header_(NULL),
      current_header_size_(0),
      current_header_offset_(0) {
}

MachoWalker::~MachoWalker() {
  if (file_ != -1)
    close(file_);
}

int MachoWalker::ValidateCPUType(int cpu_type) {
  // If the user didn't specify, use the local architecture.
  if (cpu_type == 0) {
    const NXArchInfo *arch = NXGetLocalArchInfo();
    assert(arch);
    cpu_type = arch->cputype;
  }

  return cpu_type;
}

bool MachoWalker::WalkHeader(int cpu_type) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  off_t offset;
  if (FindHeader(valid_cpu_type, offset)) {
    if (cpu_type & CPU_ARCH_ABI64)
      return WalkHeader64AtOffset(offset);

    return WalkHeaderAtOffset(offset);
  }

  return false;
}

bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
  if (memory_) {
    bool result = true;
    if (offset + size > memory_size_) {
      size = memory_size_ - offset;
      result = false;
    }
    if (size < 0)
      return false;
    memcpy(buffer, static_cast<char *>(memory_) + offset, size);
    return result;
  } else {
    return pread(file_, buffer, size, offset) == (ssize_t)size;
  }
}

bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
  if (current_header_) {
    memcpy(header, current_header_, sizeof(mach_header_64));
    *offset = current_header_offset_;
    return true;
  }

  return false;
}

bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  // Read the magic bytes that's common amongst all mach-o files
  uint32_t magic;
  if (!ReadBytes(&magic, sizeof(magic), 0))
    return false;

  offset = sizeof(magic);

  // Figure out what type of file we've got
  bool is_fat = false;
  if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
    is_fat = true;
  }
  else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
           magic != MH_CIGAM_64) {
    return false;
  }

  if (!is_fat) {
    // If we don't have a fat header, check if the cpu type matches the single
    // header
    cpu_type_t header_cpu_type;
    if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
      return false;

    if (magic == MH_CIGAM || magic == MH_CIGAM_64)
      header_cpu_type = ByteSwap(header_cpu_type);

    if (valid_cpu_type != header_cpu_type)
      return false;

    offset = 0;
    return true;
  } else {
    // Read the fat header and find an appropriate architecture
    offset = 0;
    struct fat_header fat;
    if (!ReadBytes(&fat, sizeof(fat), offset))
      return false;

    if (NXHostByteOrder() != NX_BigEndian)
      swap_fat_header(&fat, NXHostByteOrder());

    offset += sizeof(fat);

    // Search each architecture for the desired one
    struct fat_arch arch;
    for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
      if (!ReadBytes(&arch, sizeof(arch), offset))
        return false;

      if (NXHostByteOrder() != NX_BigEndian)
        swap_fat_arch(&arch, 1, NXHostByteOrder());

      if (arch.cputype == valid_cpu_type) {
        offset = arch.offset;
        return true;
      }

      offset += sizeof(arch);
    }
  }

  return false;
}

bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
  struct mach_header header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM);
  if (swap)
    swap_mach_header(&header, NXHostByteOrder());

  // Copy the data into the mach_header_64 structure.  Since the 32-bit and
  // 64-bit only differ in the last field (reserved), this is safe to do.
  struct mach_header_64 header64;
  memcpy((void *)&header64, (const void *)&header, sizeof(header));
  header64.reserved = 0;

  current_header_ = &header64;
  current_header_size_ = sizeof(header); // 32-bit, not 64-bit
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
  struct mach_header_64 header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM_64);
  if (swap)
    breakpad_swap_mach_header_64(&header, NXHostByteOrder());

  current_header_ = &header;
  current_header_size_ = sizeof(header);
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
                                 bool swap) {
  for (uint32_t i = 0; i < number_of_commands; ++i) {
    struct load_command cmd;
    if (!ReadBytes(&cmd, sizeof(cmd), offset))
      return false;

    if (swap)
      swap_load_command(&cmd, NXHostByteOrder());

    // Call the user callback
    if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
      break;

    offset += cmd.cmdsize;
  }

  return true;
}

}  // namespace MacFileUtilities
<commit_msg> Correct incorrect bounds checking. Review URL: http://breakpad.appspot.com/319002<commit_after>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// macho_walker.cc: Iterate over the load commands in a mach-o file
//
// See macho_walker.h for documentation
//
// Author: Dan Waylonis

extern "C" {  // necessary for Leopard
  #include <assert.h>
  #include <fcntl.h>
  #include <mach-o/arch.h>
  #include <mach-o/loader.h>
  #include <mach-o/swap.h>
  #include <string.h>
  #include <unistd.h>
}

#include "common/mac/byteswap.h"
#include "common/mac/macho_walker.h"
#include "common/mac/macho_utilities.h"

namespace MacFileUtilities {

MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
                         void *context)
    : file_(0),
      memory_(NULL),
      memory_size_(0),
      callback_(callback),
      callback_context_(context),
      current_header_(NULL),
      current_header_size_(0),
      current_header_offset_(0) {
  file_ = open(path, O_RDONLY);
}

MachoWalker::MachoWalker(void *memory, size_t size,
                         LoadCommandCallback callback, void *context)
    : file_(0),
      memory_(memory),
      memory_size_(size),
      callback_(callback),
      callback_context_(context),
      current_header_(NULL),
      current_header_size_(0),
      current_header_offset_(0) {
}

MachoWalker::~MachoWalker() {
  if (file_ != -1)
    close(file_);
}

int MachoWalker::ValidateCPUType(int cpu_type) {
  // If the user didn't specify, use the local architecture.
  if (cpu_type == 0) {
    const NXArchInfo *arch = NXGetLocalArchInfo();
    assert(arch);
    cpu_type = arch->cputype;
  }

  return cpu_type;
}

bool MachoWalker::WalkHeader(int cpu_type) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  off_t offset;
  if (FindHeader(valid_cpu_type, offset)) {
    if (cpu_type & CPU_ARCH_ABI64)
      return WalkHeader64AtOffset(offset);

    return WalkHeaderAtOffset(offset);
  }

  return false;
}

bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
  if (memory_) {
    bool result = true;
    if (offset + size > memory_size_) {
      if (offset >= memory_size_)
        return false;
      size = memory_size_ - offset;
      result = false;
    }
    memcpy(buffer, static_cast<char *>(memory_) + offset, size);
    return result;
  } else {
    return pread(file_, buffer, size, offset) == (ssize_t)size;
  }
}

bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
  if (current_header_) {
    memcpy(header, current_header_, sizeof(mach_header_64));
    *offset = current_header_offset_;
    return true;
  }

  return false;
}

bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
  int valid_cpu_type = ValidateCPUType(cpu_type);
  // Read the magic bytes that's common amongst all mach-o files
  uint32_t magic;
  if (!ReadBytes(&magic, sizeof(magic), 0))
    return false;

  offset = sizeof(magic);

  // Figure out what type of file we've got
  bool is_fat = false;
  if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
    is_fat = true;
  }
  else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
           magic != MH_CIGAM_64) {
    return false;
  }

  if (!is_fat) {
    // If we don't have a fat header, check if the cpu type matches the single
    // header
    cpu_type_t header_cpu_type;
    if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
      return false;

    if (magic == MH_CIGAM || magic == MH_CIGAM_64)
      header_cpu_type = ByteSwap(header_cpu_type);

    if (valid_cpu_type != header_cpu_type)
      return false;

    offset = 0;
    return true;
  } else {
    // Read the fat header and find an appropriate architecture
    offset = 0;
    struct fat_header fat;
    if (!ReadBytes(&fat, sizeof(fat), offset))
      return false;

    if (NXHostByteOrder() != NX_BigEndian)
      swap_fat_header(&fat, NXHostByteOrder());

    offset += sizeof(fat);

    // Search each architecture for the desired one
    struct fat_arch arch;
    for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
      if (!ReadBytes(&arch, sizeof(arch), offset))
        return false;

      if (NXHostByteOrder() != NX_BigEndian)
        swap_fat_arch(&arch, 1, NXHostByteOrder());

      if (arch.cputype == valid_cpu_type) {
        offset = arch.offset;
        return true;
      }

      offset += sizeof(arch);
    }
  }

  return false;
}

bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
  struct mach_header header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM);
  if (swap)
    swap_mach_header(&header, NXHostByteOrder());

  // Copy the data into the mach_header_64 structure.  Since the 32-bit and
  // 64-bit only differ in the last field (reserved), this is safe to do.
  struct mach_header_64 header64;
  memcpy((void *)&header64, (const void *)&header, sizeof(header));
  header64.reserved = 0;

  current_header_ = &header64;
  current_header_size_ = sizeof(header); // 32-bit, not 64-bit
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
  struct mach_header_64 header;
  if (!ReadBytes(&header, sizeof(header), offset))
    return false;

  bool swap = (header.magic == MH_CIGAM_64);
  if (swap)
    breakpad_swap_mach_header_64(&header, NXHostByteOrder());

  current_header_ = &header;
  current_header_size_ = sizeof(header);
  current_header_offset_ = offset;
  offset += current_header_size_;
  bool result = WalkHeaderCore(offset, header.ncmds, swap);
  current_header_ = NULL;
  current_header_size_ = 0;
  current_header_offset_ = 0;
  return result;
}

bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
                                 bool swap) {
  for (uint32_t i = 0; i < number_of_commands; ++i) {
    struct load_command cmd;
    if (!ReadBytes(&cmd, sizeof(cmd), offset))
      return false;

    if (swap)
      swap_load_command(&cmd, NXHostByteOrder());

    // Call the user callback
    if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
      break;

    offset += cmd.cmdsize;
  }

  return true;
}

}  // namespace MacFileUtilities
<|endoftext|>


<commit_before>#include <phypp.hpp>

vec1d schechter2(vec1d m, double mstar1, double index1, double phistar1,
    double mstar2, double index2, double phistar2) {
    vec1d tm1 = e10(m-mstar1);
    vec1d tm2 = e10(m-mstar2);
    return log(10.0)*(exp(-tm1)*phistar1*pow(tm1, 1+index1) + exp(-tm2)*phistar2*pow(tm2, 1+index2));
}

int phypp_main(int argc, char* argv[]) {
    double mmin = 4.0, mmax = 13.0;
    double zmax = 10.5;
    double dm = 0.05;
    std::string mf;

    read_args(argc, argv, arg_list(mmin, mmax, dm, zmax, mf));

    vec1f zl, zu;
    vec1f a_mstar1, a_mstar2, a_phistar1, a_phistar2, a_index1, a_index2;
    vec1f p_mstar1, p_mstar2, p_phistar1, p_phistar2, p_index1, p_index2;
    std::string imf;

    if (mf == "tomczak") {
        // Tomczak et al. (2013)

        zl = {0.2, 0.5,  0.75, 1.0,  1.25, 1.5, 2.0, 2.5};
        zu = {0.5, 0.75, 1.0,  1.25, 1.5,  2.0, 2.5, 3.0};

        // Active
        a_mstar1 = {10.59, 10.65, 10.56, 10.44, 10.69, 10.59, 10.58, 10.61};
        a_mstar2 = a_mstar1;
        a_phistar1 = {-2.67, -2.97, -2.81, -2.98, -3.04, -3.37, -4.30, -4.95};
        a_index1 = {-1.08, -0.97, -0.46, 0.53, -0.55, 0.75, 2.06, 2.36};
        a_phistar2 = {-4.46, -3.34, -3.36, -3.11, -3.59, -3.28, -3.28, -3.71};
        a_index2 = {-2.00, -1.58, -1.61, -1.44, -1.62, -1.47, -1.38, -1.67};

        // Passive
        p_mstar1 = {10.75, 10.68, 10.63, 10.63, 10.49, 10.77, 10.69, 9.95};
        p_mstar2 = p_mstar1;
        p_phistar1 = {-2.76, -2.67, -2.81, -3.03, -3.36, -3.41, -3.59, -4.22};
        p_index1 = {-0.47, -0.10, 0.04, 0.11, 0.85, -0.19, -0.37, -0.62};
        p_phistar2 = {-5.21, -4.29, -4.40, -4.80, -3.72, -3.91, -6.95, -4.51};
        p_index2 = {-1.97, -1.69, -1.51, -1.57, -0.54, -0.18, -3.07, 2.51};

        a_phistar1 = e10(a_phistar1);
        a_phistar2 = e10(a_phistar2);
        p_phistar1 = e10(p_phistar1);
        p_phistar2 = e10(p_phistar2);

        imf = "chabrier";
    } else {
        // My stellar mass functions in GS

        zl = {0.3, 0.7, 1.2, 1.9, 2.5, 3.5};
        zu = {0.7, 1.2, 1.9, 2.5, 3.5, 4.5};

        // Active
        a_mstar1 = {11.0000, 11.0000, 11.0000, 11.0000, 11.0000, 11.0000};
        a_mstar2 = {10.6418, 10.7292, 10.6717, 10.8404, 10.9443, 11.0000};
        a_phistar1 = {0.000898887, 0.000718160, 0.000465684, 0.000213874, 0.000212404, 3.69e-05};
        a_index1 = {-1.40000, -1.40000, -1.50000, -1.57000, -1.60000, -1.80000};
        a_phistar2 = {8.30778e-05, 0.000404045, 0.000417749, 0.000406023, 9.06860e-05, 0.0};
        a_index2 = {0.500000, 0.500000, 0.500000, 0.00000, 0.500000, 0.500000};

        // Passive
        p_mstar1 = {11.0000, 11.0000, 11.0000, 11.0000, 11.0000, 11.0000};
        p_mstar2 = {11.0426, 10.8601, 10.8342, 11.0471, 10.9439, 11.0000};
        p_phistar1 = {7.77453e-05, 3.54586e-05, 2.29979e-05, 1.00000e-05, 0.00000, 0.00000};
        p_index1 = {-1.65000, -1.60000, -1.25000, -1.00000, -1.00000, -1.35000};
        p_phistar2 = {0.00154472, 0.00104263, 0.000624682, 0.000173119, 0.000122278, 3.00000e-05};
        p_index2 = {-0.481039, 0.0594024, 0.296244, -0.166611, -0.263124, -0.300000};

        imf = "salpeter";
    }

    // Note: z = 0 is obtained from Baldry et al. (2012)
    // This mass function is in Chabrier IMF, so we may need to convert that
    // to match the mass functions at other redshifts.
    // NB: the IMF can be anything, but it has to be consistent at all z...
    float b12_factor = 1.0;
    if (imf == "salpeter") {
        b12_factor = 1.0/1.8;
    }

    prepend(zu,         vec1f{min(zl)});
    prepend(zl,         vec1f{0.0});

    prepend(a_mstar1,   vec1f{10.72});
    prepend(a_mstar2,   vec1f{10.72});
    prepend(a_phistar1, vec1f{0.71e-3});
    prepend(a_phistar2, vec1f{0.0});
    prepend(a_index1,   vec1f{-1.45});
    prepend(a_index2,   vec1f{0.3});

    prepend(p_mstar1,   vec1f{10.72});
    prepend(p_mstar2,   vec1f{10.72});
    prepend(p_phistar1, vec1f{3.25e-3});
    prepend(p_phistar2, vec1f{0.08e-3});
    prepend(p_index1,   vec1f{-0.45});
    prepend(p_index2,   vec1f{-1.45});

    // Note: z > 4.0 is obtained by keeping the shape of the last redshift bin and
    //       decreasing phistar, following the total stellar mass density of
    //       Grazian et al. (2015)
    uint_t ilast = a_mstar1.size()-1;
    uint_t nhzb = ceil((zmax - max(zu))/0.2);
    double dhz = (zmax - max(zu))/nhzb;

    append(zl, findgen(nhzb)*dhz + max(zu));
    append(zu, findgen(nhzb)*dhz + max(zu) + dhz);

    auto g15_rhostar = vectorize_lambda([](double z){
        return (z < 6 ? e10(-0.43*z) : e10(-0.43*6.0)*e10(-0.7*(z-6.0)));
    });

    vec1d decrease = g15_rhostar(0.5*(zl+zu)[(ilast+1)-_])/g15_rhostar(0.5*(zl[ilast] + zu[ilast]));
    vec1d index = interpolate({-1.8, -2.0, -2.1, -2.1}, {4.0, 5.0, 6.0, 6.01}, 0.5*(zl+zu)[(ilast+1)-_]);

    for (uint_t i : range(decrease)) {
        a_mstar1.push_back(a_mstar1[ilast]);
        a_mstar2.push_back(a_mstar2[ilast]);
        a_index1.push_back(index[i]);
        a_index2.push_back(a_index2[ilast]);
        a_phistar1.push_back(decrease[i]*a_phistar1[ilast]);
        a_phistar2.push_back(decrease[i]*a_phistar2[ilast]);

        p_mstar1.push_back(p_mstar1[ilast]);
        p_mstar2.push_back(p_mstar2[ilast]);
        p_index1.push_back(p_index1[ilast]);
        p_index2.push_back(p_index2[ilast]);
        p_phistar1.push_back(decrease[i]*p_phistar1[ilast]);
        p_phistar2.push_back(decrease[i]*p_phistar2[ilast]);
    }

    struct {
        vec2f zb, mb;
        vec2d active, passive;
        std::string imf;
    } out;

    out.imf = imf;

    out.zb.resize(2, zl.size());
    out.zb(0,_) = zl;
    out.zb(1,_) = zu;
    out.mb = make_bins(rgen(mmin - dm, mmax + dm, ceil((mmax - mmin)/dm) + 2));

    uint_t nm = out.mb.dims[1];
    uint_t nz = out.zb.dims[1];

    out.active.resize(nz, nm);
    out.passive.resize(nz, nm);

    vec1d mx = 0.5*(out.mb(0,_) + out.mb(1,_));

    for (uint_t z : range(nz)) {
        double factor = 0.0;
        if (z == 0) {
            factor = log10(b12_factor);
        }

        out.active(z,_) = schechter2(factor + mx,
            a_mstar1[z], a_index1[z], a_phistar1[z], a_mstar2[z], a_index2[z], a_phistar2[z]);
        out.passive(z,_) = schechter2(factor + mx,
            p_mstar1[z], p_index1[z], p_phistar1[z], p_mstar2[z], p_index2[z], p_phistar2[z]);
    }

    fits::write_table("mass_func_candels.fits", ftable(
        out.zb, out.mb, out.active, out.passive, out.imf
    ));

    return 0;
}
<commit_msg>Pushed MF to z=15<commit_after>#include <phypp.hpp>

vec1d schechter2(vec1d m, double mstar1, double index1, double phistar1,
    double mstar2, double index2, double phistar2) {
    vec1d tm1 = e10(m-mstar1);
    vec1d tm2 = e10(m-mstar2);
    return log(10.0)*(exp(-tm1)*phistar1*pow(tm1, 1+index1) + exp(-tm2)*phistar2*pow(tm2, 1+index2));
}

int phypp_main(int argc, char* argv[]) {
    double mmin = 4.0, mmax = 13.0;
    double zmax = 15;
    double dm = 0.05;
    std::string mf;

    read_args(argc, argv, arg_list(mmin, mmax, dm, zmax, mf));

    vec1f zl, zu;
    vec1f a_mstar1, a_mstar2, a_phistar1, a_phistar2, a_index1, a_index2;
    vec1f p_mstar1, p_mstar2, p_phistar1, p_phistar2, p_index1, p_index2;
    std::string imf;

    if (mf == "tomczak") {
        // Tomczak et al. (2013)

        zl = {0.2, 0.5,  0.75, 1.0,  1.25, 1.5, 2.0, 2.5};
        zu = {0.5, 0.75, 1.0,  1.25, 1.5,  2.0, 2.5, 3.0};

        // Active
        a_mstar1 = {10.59, 10.65, 10.56, 10.44, 10.69, 10.59, 10.58, 10.61};
        a_mstar2 = a_mstar1;
        a_phistar1 = {-2.67, -2.97, -2.81, -2.98, -3.04, -3.37, -4.30, -4.95};
        a_index1 = {-1.08, -0.97, -0.46, 0.53, -0.55, 0.75, 2.06, 2.36};
        a_phistar2 = {-4.46, -3.34, -3.36, -3.11, -3.59, -3.28, -3.28, -3.71};
        a_index2 = {-2.00, -1.58, -1.61, -1.44, -1.62, -1.47, -1.38, -1.67};

        // Passive
        p_mstar1 = {10.75, 10.68, 10.63, 10.63, 10.49, 10.77, 10.69, 9.95};
        p_mstar2 = p_mstar1;
        p_phistar1 = {-2.76, -2.67, -2.81, -3.03, -3.36, -3.41, -3.59, -4.22};
        p_index1 = {-0.47, -0.10, 0.04, 0.11, 0.85, -0.19, -0.37, -0.62};
        p_phistar2 = {-5.21, -4.29, -4.40, -4.80, -3.72, -3.91, -6.95, -4.51};
        p_index2 = {-1.97, -1.69, -1.51, -1.57, -0.54, -0.18, -3.07, 2.51};

        a_phistar1 = e10(a_phistar1);
        a_phistar2 = e10(a_phistar2);
        p_phistar1 = e10(p_phistar1);
        p_phistar2 = e10(p_phistar2);

        imf = "chabrier";
    } else {
        // My stellar mass functions in GS

        zl = {0.3, 0.7, 1.2, 1.9, 2.5, 3.5};
        zu = {0.7, 1.2, 1.9, 2.5, 3.5, 4.5};

        // Active
        a_mstar1 = {11.0000, 11.0000, 11.0000, 11.0000, 11.0000, 11.0000};
        a_mstar2 = {10.6418, 10.7292, 10.6717, 10.8404, 10.9443, 11.0000};
        a_phistar1 = {0.000898887, 0.000718160, 0.000465684, 0.000213874, 0.000212404, 3.69e-05};
        a_index1 = {-1.40000, -1.40000, -1.50000, -1.57000, -1.60000, -1.80000};
        a_phistar2 = {8.30778e-05, 0.000404045, 0.000417749, 0.000406023, 9.06860e-05, 0.0};
        a_index2 = {0.500000, 0.500000, 0.500000, 0.00000, 0.500000, 0.500000};

        // Passive
        p_mstar1 = {11.0000, 11.0000, 11.0000, 11.0000, 11.0000, 11.0000};
        p_mstar2 = {11.0426, 10.8601, 10.8342, 11.0471, 10.9439, 11.0000};
        p_phistar1 = {7.77453e-05, 3.54586e-05, 2.29979e-05, 1.00000e-05, 0.00000, 0.00000};
        p_index1 = {-1.65000, -1.60000, -1.25000, -1.00000, -1.00000, -1.35000};
        p_phistar2 = {0.00154472, 0.00104263, 0.000624682, 0.000173119, 0.000122278, 3.00000e-05};
        p_index2 = {-0.481039, 0.0594024, 0.296244, -0.166611, -0.263124, -0.300000};

        imf = "salpeter";
    }

    // Note: z = 0 is obtained from Baldry et al. (2012)
    // This mass function is in Chabrier IMF, so we may need to convert that
    // to match the mass functions at other redshifts.
    // NB: the IMF can be anything, but it has to be consistent at all z...
    float b12_factor = 1.0;
    if (imf == "salpeter") {
        b12_factor = 1.0/1.8;
    }

    prepend(zu,         vec1f{min(zl)});
    prepend(zl,         vec1f{0.0});

    prepend(a_mstar1,   vec1f{10.72});
    prepend(a_mstar2,   vec1f{10.72});
    prepend(a_phistar1, vec1f{0.71e-3});
    prepend(a_phistar2, vec1f{0.0});
    prepend(a_index1,   vec1f{-1.45});
    prepend(a_index2,   vec1f{0.3});

    prepend(p_mstar1,   vec1f{10.72});
    prepend(p_mstar2,   vec1f{10.72});
    prepend(p_phistar1, vec1f{3.25e-3});
    prepend(p_phistar2, vec1f{0.08e-3});
    prepend(p_index1,   vec1f{-0.45});
    prepend(p_index2,   vec1f{-1.45});

    // Note: z > 4.0 is obtained by keeping the shape of the last redshift bin and
    //       decreasing phistar, following the total stellar mass density of
    //       Grazian et al. (2015)
    uint_t ilast = a_mstar1.size()-1;
    uint_t nhzb = ceil((zmax - max(zu))/0.2);
    double dhz = (zmax - max(zu))/nhzb;

    append(zl, findgen(nhzb)*dhz + max(zu));
    append(zu, findgen(nhzb)*dhz + max(zu) + dhz);

    auto g15_rhostar = vectorize_lambda([](double z){
        return (z < 6 ? e10(-0.43*z) : e10(-0.43*6.0)*e10(-0.7*(z-6.0)));
    });

    vec1d decrease = g15_rhostar(0.5*(zl+zu)[(ilast+1)-_])/g15_rhostar(0.5*(zl[ilast] + zu[ilast]));
    vec1d index = interpolate({-1.8, -2.0, -2.1, -2.1}, {4.0, 5.0, 6.0, 6.01}, 0.5*(zl+zu)[(ilast+1)-_]);

    for (uint_t i : range(decrease)) {
        a_mstar1.push_back(a_mstar1[ilast]);
        a_mstar2.push_back(a_mstar2[ilast]);
        a_index1.push_back(index[i]);
        a_index2.push_back(a_index2[ilast]);
        a_phistar1.push_back(decrease[i]*a_phistar1[ilast]);
        a_phistar2.push_back(decrease[i]*a_phistar2[ilast]);

        p_mstar1.push_back(p_mstar1[ilast]);
        p_mstar2.push_back(p_mstar2[ilast]);
        p_index1.push_back(p_index1[ilast]);
        p_index2.push_back(p_index2[ilast]);
        p_phistar1.push_back(decrease[i]*p_phistar1[ilast]);
        p_phistar2.push_back(decrease[i]*p_phistar2[ilast]);
    }

    struct {
        vec2f zb, mb;
        vec2d active, passive;
        std::string imf;
    } out;

    out.imf = imf;

    out.zb.resize(2, zl.size());
    out.zb(0,_) = zl;
    out.zb(1,_) = zu;
    out.mb = make_bins(rgen(mmin - dm, mmax + dm, ceil((mmax - mmin)/dm) + 2));

    uint_t nm = out.mb.dims[1];
    uint_t nz = out.zb.dims[1];

    out.active.resize(nz, nm);
    out.passive.resize(nz, nm);

    vec1d mx = 0.5*(out.mb(0,_) + out.mb(1,_));

    for (uint_t z : range(nz)) {
        double factor = 0.0;
        if (z == 0) {
            factor = log10(b12_factor);
        }

        out.active(z,_) = schechter2(factor + mx,
            a_mstar1[z], a_index1[z], a_phistar1[z], a_mstar2[z], a_index2[z], a_phistar2[z]);
        out.passive(z,_) = schechter2(factor + mx,
            p_mstar1[z], p_index1[z], p_phistar1[z], p_mstar2[z], p_index2[z], p_phistar2[z]);
    }

    fits::write_table("mass_func_candels.fits", ftable(
        out.zb, out.mb, out.active, out.passive, out.imf
    ));

    return 0;
}
<|endoftext|>


<commit_before>#include <boost/asio.hpp>

#include <blackhole/sink/elasticsearch/resolver.hpp>

#include "../global.hpp"

using elasticsearch::resolver;

typedef boost::asio::ip::tcp protocol_type;
typedef protocol_type::endpoint endpoint_type;

boost::asio::ip::address_v4::bytes_type localhost_v4 = {{ 127, 0, 0, 1 }};
boost::asio::ip::address_v6::bytes_type localhost_v6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }};

TEST(resolver, FullResolveByIp) {
    boost::asio::io_service service;
    EXPECT_EQ(
        endpoint_type(boost::asio::ip::address_v4(localhost_v4), 5000),
        resolver<protocol_type>::resolve("localhost/127.0.0.1:5000", service)
    );
}

TEST(resolver, ResolveByIp) {
    boost::asio::io_service service;
    EXPECT_EQ(
        endpoint_type(boost::asio::ip::address_v4(localhost_v4), 5000),
        resolver<protocol_type>::resolve("/127.0.0.1:5000", service)
    );
}

TEST(resolver, ResolveByIpWithoutSlash) {
    boost::asio::io_service service;
    EXPECT_EQ(
        endpoint_type(boost::asio::ip::address_v4(localhost_v4), 5000),
        resolver<protocol_type>::resolve("127.0.0.1:5000", service)
    );
}

TEST(resolver, ResolveByHostname) {
    boost::asio::io_service service;
    resolver<protocol_type>::resolve("localhost/:5000", service);
    auto expected_v4 = endpoint_type(
        boost::asio::ip::address_v4(localhost_v4),
        5000
    );

    auto expected_v6 = endpoint_type(
        boost::asio::ip::address_v6(localhost_v6),
        5000
    );

    auto actual = resolver<protocol_type>::resolve("localhost/:5000", service);
    EXPECT_TRUE(expected_v4 == actual || expected_v6 == actual);
}

TEST(resolver, ThrowExceptionWhenPortNotSpecifyed) {
    boost::asio::io_service service;

    EXPECT_THROW(
        resolver<protocol_type>::resolve("localhost/127.0.0.1", service),
        std::logic_error
    );
}

TEST(resolver, ThrowExceptionWhenIncorrectInput) {
    boost::asio::io_service service;

    EXPECT_THROW(
        resolver<protocol_type>::resolve("localhost//127.0.0.1:5000", service),
        std::runtime_error
    );
}
<commit_msg>[Unit Testing] Fix broken resolver test.<commit_after>#include <boost/asio.hpp>

#include <blackhole/sink/elasticsearch/resolver.hpp>

#include "../global.hpp"

using elasticsearch::resolver;

typedef boost::asio::ip::tcp protocol_type;
typedef protocol_type::endpoint endpoint_type;

boost::asio::ip::address_v4::bytes_type localhost_v4 = {{ 127, 0, 0, 1 }};
boost::asio::ip::address_v6::bytes_type localhost_v6 = {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }};

TEST(resolver, FullResolveByIp) {
    boost::asio::io_service service;
    EXPECT_EQ(
        endpoint_type(boost::asio::ip::address_v4(localhost_v4), 5000),
        resolver<protocol_type>::resolve("localhost/127.0.0.1:5000", service)
    );
}

TEST(resolver, ResolveByIp) {
    boost::asio::io_service service;
    EXPECT_EQ(
        endpoint_type(boost::asio::ip::address_v4(localhost_v4), 5000),
        resolver<protocol_type>::resolve("/127.0.0.1:5000", service)
    );
}

TEST(resolver, ResolveByIpWithoutSlash) {
    boost::asio::io_service service;
    EXPECT_EQ(
        endpoint_type(boost::asio::ip::address_v4(localhost_v4), 5000),
        resolver<protocol_type>::resolve("127.0.0.1:5000", service)
    );
}

TEST(resolver, ResolveByHostname) {
    boost::asio::io_service service;
    resolver<protocol_type>::resolve("localhost/:5000", service);
    auto expected_v4 = endpoint_type(
        boost::asio::ip::address_v4(localhost_v4),
        5000
    );

    auto expected_v6 = endpoint_type(
        boost::asio::ip::address_v6(localhost_v6),
        5000
    );

    auto actual = resolver<protocol_type>::resolve("localhost/:5000", service);

    // Expanded fe80:1::1.
    auto isatap = endpoint_type(
        boost::asio::ip::address_v6(boost::asio::ip::address_v6::bytes_type {{
            254, 128, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
        }}),
        5000
    );

    EXPECT_THAT(actual, AnyOf(
        Eq(expected_v4),
        Eq(expected_v6),
        Eq(isatap)
    ));
}

TEST(resolver, ThrowExceptionWhenPortNotSpecifyed) {
    boost::asio::io_service service;

    EXPECT_THROW(
        resolver<protocol_type>::resolve("localhost/127.0.0.1", service),
        std::logic_error
    );
}

TEST(resolver, ThrowExceptionWhenIncorrectInput) {
    boost::asio::io_service service;

    EXPECT_THROW(
        resolver<protocol_type>::resolve("localhost//127.0.0.1:5000", service),
        std::runtime_error
    );
}
<|endoftext|>


<commit_before>#include <array>

#include <boost/asio.hpp>

#include <urdl/option_set.hpp>
#include <urdl/read_stream.hpp>

#include <blackhole/utils/atomic.hpp>

#include "../global.hpp"

namespace urlfetch {

struct request_t {
    std::string url;
    urdl::option_set options;
    long timeout;
};

struct response_t {
    std::string data;
};

template<class Stream = urdl::read_stream>
class task_t : public std::enable_shared_from_this<task_t<Stream>> {
public:
    typedef Stream stream_type;
    typedef boost::asio::io_service loop_type;
    typedef std::function<
        void(request_t&&, response_t&&, const boost::system::error_code&)
    > callback_type;

private:
    char buffer[4096];

    request_t request;
    response_t response;
    callback_type callback;
    stream_type stream_;

public:
    task_t(request_t request, callback_type callback, loop_type& loop) :
        request(std::move(request)),
        callback(std::move(callback)),
        stream_(loop)
    {}

    stream_type& stream() {
        return stream_;
    }

    void run() {
        //!@todo: do nothing if the stream is active.
        stream_.async_open(
            request.url,
            std::bind(
                &task_t::on_open,
                this->shared_from_this(),
                std::placeholders::_1
            )
        );
    }

private:
    void on_open(const boost::system::error_code& ec) {
        std::cout << "on_open: " << ec.message() << std::endl;
        if (ec) {
            callback(std::move(request), std::move(response), ec);
            return;
        }

        async_read_some();
    }

    void on_read(const boost::system::error_code& ec, std::size_t length) {
        std::cout << "on_read: " << ec.message() << std::endl;
        if (ec) {
            //!@todo: timer.cancel();
            if (ec.value() == boost::asio::error::eof) {
                callback(
                    std::move(request),
                    std::move(response),
                    boost::system::error_code()
                );
            } else {
                //!@todo:
                //callback(std::move(request), std::move(response), ec);
            }

            return;
        }

        response.data.append(buffer, length);
        async_read_some();
    }

    void async_read_some() {
        stream_.async_read_some(
            boost::asio::buffer(buffer),
            std::bind(
                &task_t::on_read,
                this->shared_from_this(),
                std::placeholders::_1,
                std::placeholders::_2
            )
        );
    }
};

} // namespace urlfetch

namespace mock {

class stream_t {
public:
    stream_t(boost::asio::io_service&) {}

    MOCK_METHOD2(
        async_open,
        void(
            const urdl::url&,
            std::function<void(const boost::system::error_code&)>
        )
    );

    MOCK_METHOD2(
        async_read_some,
        void(
            boost::asio::mutable_buffer,
            std::function<void(const boost::system::error_code&, std::size_t)>
        )
    );
};

} // namespace mock

TEST(request_t, Class) {
    urlfetch::request_t request;
    UNUSED(request);
}

TEST(urlfetch_t, Class) {
    urlfetch::request_t request;
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    urlfetch::task_t<mock::stream_t>::callback_type callback;
    urlfetch::task_t<mock::stream_t> task(request, callback, loop);
    UNUSED(task);
}

void post_open(boost::asio::io_service& loop,
               std::function<void(const boost::system::error_code&)> task,
               const boost::system::error_code& ec) {
    loop.post(std::bind(task, ec));
}

void post_read(boost::asio::io_service& loop,
               const boost::asio::mutable_buffer& buffer,
               std::function<
                   void(const boost::system::error_code&, std::size_t length)
               > task,
               const boost::system::error_code& ec,
               std::string data) {
    BOOST_ASSERT(data.size() <= 4096);

    std::size_t size = boost::asio::buffer_size(buffer);
    EXPECT_EQ(4096, size);

    unsigned char* p = boost::asio::buffer_cast<unsigned char*>(buffer);
    std::copy(data.begin(), data.end(), p);
    loop.post(std::bind(task, ec, data.size()));
}

namespace testing {

struct successfull_get_t {
    std::atomic<int>& counter;

    void operator()(urlfetch::request_t&& request,
                    urlfetch::response_t&& response,
                    const boost::system::error_code& ec) {
        EXPECT_EQ("http://127.0.0.1:80", request.url);
        EXPECT_EQ("{}", response.data);
        EXPECT_EQ(0, ec.value());
        counter++;
    }
};

} // namespace testing

TEST(urlfetch_t, SuccessfulGet) {
    //!\brief GET request, which should handle correctly.

    /*! The main idea of this test is to check http stream's correct method
     *  invocation sequence.
     *  We create GET request and push it into the urlfetch::task_t object.
     *  The first event should be a connection opening, from which our mock
     *  must be called, which puts stream's read callback invocation with
     *  correct error code (no errors) into the event loop.
     *  Then we poll one event which should be exactly that callback.
     *  We mock it to write empty json string "{}" into the buffer and then
     *  just wait for the next chunk.
     *  The next event loop tick there will be no chunks, but there will be EOF
     *  error, which should trigger result callback's invocation with all
     *  received data.
     */
    urlfetch::request_t request;
    request.url = "http://127.0.0.1:80";

    std::atomic<int> counter(0);
    testing::successfull_get_t event { counter };
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    auto task = std::make_shared<
        urlfetch::task_t<mock::stream_t>
    >(request, event, loop);

    // We mock `async_open` to handle correctly and post channel reading.
    EXPECT_CALL(task->stream(), async_open(urdl::url("http://127.0.0.1:80"), _))
            .Times(1)
            .WillOnce(
                WithArg<1>(
                    Invoke(
                        std::bind(
                            &post_open,
                            std::ref(loop),
                            std::placeholders::_1,
                            boost::system::error_code()
                        )
                    )
                )
            );
    task->run();

    // The first read event - just writing some bytes to the buffer.
    EXPECT_CALL(task->stream(), async_read_some(_, _))
            .Times(1)
            .WillOnce(
                Invoke(
                    std::bind(
                        &post_read,
                        std::ref(loop),
                        std::placeholders::_1,
                        std::placeholders::_2,
                        boost::system::error_code(),
                        "{}"
                    )
                )
            );

    // Poll `on_open` task.
    loop.run_one();

    // The second read event - pushing EOF "error" to notify, that there will
    // no more bytes be received.
    EXPECT_CALL(task->stream(), async_read_some(_, _))
            .Times(1)
            .WillOnce(
                Invoke(
                    std::bind(
                        &post_read,
                        std::ref(loop),
                        std::placeholders::_1,
                        std::placeholders::_2,
                        boost::asio::error::make_error_code(
                            boost::asio::error::eof
                        ),
                        ""
                    )
                )
            );

    // Pool `on_read` first task.
    loop.run_one();

    // Poll `on_read` second task.
    loop.run_one();

    EXPECT_EQ(1, counter);
}

TEST(urlfetch_t, SuccessfulPost) {
    //!@todo: Implement.
}

namespace testing {

struct connection_error_t {
    std::atomic<int>& counter;

    void operator()(urlfetch::request_t&&,
                    urlfetch::response_t&&,
                    const boost::system::error_code& ec) {
        EXPECT_EQ(boost::asio::error::connection_refused, ec.value());
        counter++;
    }
};

} // namespace testing

TEST(urlfetch_t, DirectConnectionError) {
    std::atomic<int> counter(0);

    urlfetch::request_t request;
    request.url = "http://127.0.0.1:80";

    testing::connection_error_t event { counter };
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    auto task = std::make_shared<
        urlfetch::task_t<mock::stream_t>
    >(request, event, loop);

    // We mock `async_open` to emit connection error.
    EXPECT_CALL(task->stream(), async_open(_, _))
            .Times(1)
            .WillOnce(
                WithArg<1>(
                    Invoke(
                        std::bind(
                            &post_open,
                            std::ref(loop),
                            std::placeholders::_1,
                            boost::asio::error::make_error_code(
                                boost::asio::error::connection_refused
                            )
                        )
                    )
                )
            );
    task->run();

    // Extract callback.
    loop.run_one();
    EXPECT_EQ(1, counter);
}

TEST(urlfetch_t, DeferredConnectionError) {
}

TEST(urlfetch_t, Timeout) {
}

TEST(urlfetch_t, Cancel) {
}

TEST(urlfetch_t, Manual) {
//    urlfetch::get(url, callback, loop, timeout=default);
//    urlfetch::post(url, body, callback, loop, timeout=default);
//    urlfetch::execute(request, callback, loop);
}
<commit_msg>[Urlfetch] Deferred errors now handles correctly.<commit_after>#include <array>

#include <boost/asio.hpp>

#include <urdl/option_set.hpp>
#include <urdl/read_stream.hpp>

#include <blackhole/utils/atomic.hpp>

#include "../global.hpp"

namespace urlfetch {

struct request_t {
    std::string url;
    urdl::option_set options;
    long timeout;
};

struct response_t {
    std::string data;
};

template<class Stream = urdl::read_stream>
class task_t : public std::enable_shared_from_this<task_t<Stream>> {
public:
    typedef Stream stream_type;
    typedef boost::asio::io_service loop_type;
    typedef std::function<
        void(request_t&&, response_t&&, const boost::system::error_code&)
    > callback_type;

private:
    char buffer[4096];

    request_t request;
    response_t response;
    callback_type callback;
    stream_type stream_;

public:
    task_t(request_t request, callback_type callback, loop_type& loop) :
        request(std::move(request)),
        callback(std::move(callback)),
        stream_(loop)
    {}

    stream_type& stream() {
        return stream_;
    }

    void run() {
        //!@todo: do nothing if the stream is active.
        stream_.async_open(
            request.url,
            std::bind(
                &task_t::on_open,
                this->shared_from_this(),
                std::placeholders::_1
            )
        );
    }

private:
    void on_open(const boost::system::error_code& ec) {
        std::cout << "on_open: " << ec.message() << std::endl;
        if (ec) {
            callback(std::move(request), std::move(response), ec);
            return;
        }

        async_read_some();
    }

    void on_read(const boost::system::error_code& ec, std::size_t length) {
        std::cout << "on_read: " << ec.message() << std::endl;
        if (ec) {
            //!@todo: timer.cancel();
            if (ec.value() == boost::asio::error::eof) {
                callback(
                    std::move(request),
                    std::move(response),
                    boost::system::error_code()
                );
            } else {
                callback(std::move(request), std::move(response), ec);
            }

            return;
        }

        response.data.append(buffer, length);
        async_read_some();
    }

    void async_read_some() {
        stream_.async_read_some(
            boost::asio::buffer(buffer),
            std::bind(
                &task_t::on_read,
                this->shared_from_this(),
                std::placeholders::_1,
                std::placeholders::_2
            )
        );
    }
};

} // namespace urlfetch

namespace mock {

class stream_t {
public:
    stream_t(boost::asio::io_service&) {}

    MOCK_METHOD2(
        async_open,
        void(
            const urdl::url&,
            std::function<void(const boost::system::error_code&)>
        )
    );

    MOCK_METHOD2(
        async_read_some,
        void(
            boost::asio::mutable_buffer,
            std::function<void(const boost::system::error_code&, std::size_t)>
        )
    );
};

} // namespace mock

TEST(request_t, Class) {
    urlfetch::request_t request;
    UNUSED(request);
}

TEST(urlfetch_t, Class) {
    urlfetch::request_t request;
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    urlfetch::task_t<mock::stream_t>::callback_type callback;
    urlfetch::task_t<mock::stream_t> task(request, callback, loop);
    UNUSED(task);
}

void post_open(boost::asio::io_service& loop,
               std::function<void(const boost::system::error_code&)> task,
               const boost::system::error_code& ec) {
    loop.post(std::bind(task, ec));
}

void post_read(boost::asio::io_service& loop,
               const boost::asio::mutable_buffer& buffer,
               std::function<
                   void(const boost::system::error_code&, std::size_t length)
               > task,
               const boost::system::error_code& ec,
               std::string data) {
    BOOST_ASSERT(data.size() <= 4096);

    std::size_t size = boost::asio::buffer_size(buffer);
    EXPECT_EQ(4096, size);

    unsigned char* p = boost::asio::buffer_cast<unsigned char*>(buffer);
    std::copy(data.begin(), data.end(), p);
    loop.post(std::bind(task, ec, data.size()));
}

namespace testing {

struct successfull_get_t {
    std::atomic<int>& counter;

    void operator()(urlfetch::request_t&& request,
                    urlfetch::response_t&& response,
                    const boost::system::error_code& ec) {
        EXPECT_EQ("http://127.0.0.1:80", request.url);
        EXPECT_EQ("{}", response.data);
        EXPECT_EQ(0, ec.value());
        counter++;
    }
};

} // namespace testing

TEST(urlfetch_t, SuccessfulGet) {
    //!\brief GET request, which should handle correctly.

    /*! The main idea of this test is to check http stream's correct method
     *  invocation sequence.
     *  We create GET request and push it into the urlfetch::task_t object.
     *  The first event should be a connection opening, from which our mock
     *  must be called, which puts stream's read callback invocation with
     *  correct error code (no errors) into the event loop.
     *  Then we poll one event which should be exactly that callback.
     *  We mock it to write empty json string "{}" into the buffer and then
     *  just wait for the next chunk.
     *  The next event loop tick there will be no chunks, but there will be EOF
     *  error, which should trigger result callback's invocation with all
     *  received data.
     */
    urlfetch::request_t request;
    request.url = "http://127.0.0.1:80";

    std::atomic<int> counter(0);
    testing::successfull_get_t event { counter };
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    auto task = std::make_shared<
        urlfetch::task_t<mock::stream_t>
    >(request, event, loop);

    // We mock `async_open` to handle correctly and post channel reading.
    EXPECT_CALL(task->stream(), async_open(urdl::url("http://127.0.0.1:80"), _))
            .Times(1)
            .WillOnce(
                WithArg<1>(
                    Invoke(
                        std::bind(
                            &post_open,
                            std::ref(loop),
                            std::placeholders::_1,
                            boost::system::error_code()
                        )
                    )
                )
            );
    task->run();

    // The first read event - just writing some bytes to the buffer.
    EXPECT_CALL(task->stream(), async_read_some(_, _))
            .Times(1)
            .WillOnce(
                Invoke(
                    std::bind(
                        &post_read,
                        std::ref(loop),
                        std::placeholders::_1,
                        std::placeholders::_2,
                        boost::system::error_code(),
                        "{}"
                    )
                )
            );

    // Poll `on_open` task.
    loop.run_one();

    // The second read event - pushing EOF "error" to notify, that there will
    // no more bytes be received.
    EXPECT_CALL(task->stream(), async_read_some(_, _))
            .Times(1)
            .WillOnce(
                Invoke(
                    std::bind(
                        &post_read,
                        std::ref(loop),
                        std::placeholders::_1,
                        std::placeholders::_2,
                        boost::asio::error::make_error_code(
                            boost::asio::error::eof
                        ),
                        ""
                    )
                )
            );

    // Pool `on_read` first task.
    loop.run_one();

    // Poll `on_read` second task.
    loop.run_one();

    EXPECT_EQ(1, counter);
}

TEST(urlfetch_t, SuccessfulPost) {
    //!@todo: Implement.
}

namespace testing {

struct connection_error_t {
    std::atomic<int>& counter;
    boost::system::error_code ec;

    void operator()(urlfetch::request_t&&,
                    urlfetch::response_t&&,
                    const boost::system::error_code& ec) {
        EXPECT_EQ(this->ec.value(), ec.value());
        counter++;
    }
};

} // namespace testing

TEST(urlfetch_t, DirectConnectionError) {
    //!\brief GET request, which should fail with connection error on opening.

    /*! Entire request should results in callback invocation with error. */
    std::atomic<int> counter(0);

    urlfetch::request_t request;
    request.url = "http://127.0.0.1:80";

    const auto expected_ec = boost::asio::error::make_error_code(
        boost::asio::error::connection_refused
    );

    testing::connection_error_t event { counter, expected_ec };
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    auto task = std::make_shared<
        urlfetch::task_t<mock::stream_t>
    >(request, event, loop);

    // We mock `async_open` to emit connection error.
    EXPECT_CALL(task->stream(), async_open(_, _))
            .Times(1)
            .WillOnce(
                WithArg<1>(
                    Invoke(
                        std::bind(
                            &post_open,
                            std::ref(loop),
                            std::placeholders::_1,
                            expected_ec
                        )
                    )
                )
            );
    task->run();

    // Extract callback.
    loop.run_one();
    EXPECT_EQ(1, counter);
}

TEST(urlfetch_t, DeferredConnectionError) {
    //!\brief GET request, which should fail with connection error on opening.

    /*! Entire request should results in callback invocation with error. */
    std::atomic<int> counter(0);

    urlfetch::request_t request;
    request.url = "http://127.0.0.1:80";

    const auto expected_ec = boost::asio::error::make_error_code(
        boost::asio::error::broken_pipe
    );
    testing::connection_error_t event { counter, expected_ec };
    urlfetch::task_t<mock::stream_t>::loop_type loop;
    auto task = std::make_shared<
        urlfetch::task_t<mock::stream_t>
    >(request, event, loop);

    // We mock `async_open` to handle correctly and post channel reading.
    EXPECT_CALL(task->stream(), async_open(_, _))
            .Times(1)
            .WillOnce(
                WithArg<1>(
                    Invoke(
                        std::bind(
                            &post_open,
                            std::ref(loop),
                            std::placeholders::_1,
                            boost::system::error_code()
                        )
                    )
                )
            );
    task->run();

    // The first read event results in connection error.
    EXPECT_CALL(task->stream(), async_read_some(_, _))
            .Times(1)
            .WillOnce(
                Invoke(
                    std::bind(
                        &post_read,
                        std::ref(loop),
                        std::placeholders::_1,
                        std::placeholders::_2,
                        expected_ec,
                        ""
                    )
                )
            );

    // Extract open event.
    loop.run_one();

    // Extract callback.
    loop.run_one();

    EXPECT_EQ(1, counter);
}

TEST(urlfetch_t, Timeout) {
}

TEST(urlfetch_t, Cancel) {
}

TEST(urlfetch_t, Manual) {
//    urlfetch::get(url, callback, loop, timeout=default);
//    urlfetch::post(url, body, callback, loop, timeout=default);
//    urlfetch::execute(request, callback, loop);
}
<|endoftext|>