<commit_before>
#include <stdlib.h>
#include <string.h>

#include "SKIP_LIST.h"

namespace SKIP_LIST {

  struct HANDLE {
    int (*compare) ( void const * node1, void const * node2 );
    int max_level;
    int current_level;
    double prob;
    unsigned short rand_state[3];
    size_t num_items;
    struct NODE * header;
  };

  struct HANDLE * init( int (*compare) ( void const * node1, void const * node2 ), int max_level, double prob ) {
    struct HANDLE *h = (struct HANDLE *) calloc( 1, sizeof(struct HANDLE) );
    h->compare = compare;
    if(max_level < 1) max_level = 32;
    if(prob < 0 || prob >= 1) prob = 0.25;
    h->max_level = max_level;
    h->current_level = 0;
    h->prob = prob;
    h->header = (struct NODE *) calloc( 1, sizeof(struct NODE) + sizeof(struct NODE*) * h->max_level );
    h->header->data = NULL;
    h->header->num_forward = h->max_level;
    h->num_items = 0;
    return h;
  }

  void destroy( struct HANDLE *& h ) {
    free(h);
    h = NULL;
  }

  int generate_level( HANDLE * h ) {
    int level = 0;
    double r;
    do {
      r = erand48(h->rand_state);
      ++level;
    } while(r < h->prob && level < h->max_level);
    return level;
  }

  void insert( struct HANDLE * h, void * item, size_t item_len ) {
    struct NODE ** update = (struct NODE **) calloc( 1, sizeof(struct NODE*) * h->max_level );
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    for( int i=h->current_level; i>0; --i ) {
      while( n->num_forward >= i && forward[i-1] && h->compare((forward[i-1])->data, item) < 0 ) {
	n = forward[i-1];
	forward = (struct NODE **) (n+1);
      }
      update[i-1] = n;
    }
    n = *(struct NODE **) (n+1);
    if( n && h->compare(n->data, item) == 0 )
      return;
    else {
      int new_level = generate_level( h );
      if( new_level > h->current_level ) {
	for( int i=h->current_level; i<new_level; ++i ) {
	  update[i] = h->header;
	}
	h->current_level = new_level;
      }
      NODE * new_node = (struct NODE *) calloc( 1, sizeof(struct NODE) + item_len + sizeof(struct NODE*) * new_level );
      new_node->data = ((char *) (new_node+1)) + sizeof(struct NODE *) * new_level;
      memcpy( new_node->data, item, item_len );
      new_node->data_len = item_len;
      new_node->num_forward = new_level;
      struct NODE ** nforward = (struct NODE **) (new_node+1);
      for( int i=0; i<new_level; ++i ) {
	struct NODE ** forward = (struct NODE **) (update[i]+1);
	nforward[i] = forward[i];
	forward[i] = new_node;
      }
      h->num_items += 1;
    }
    free( update );
  }

  void remove( struct HANDLE * h, void * item ) {
    struct NODE ** update = (struct NODE **) calloc( 1, sizeof(struct NODE*) * h->max_level );
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    for( int i=h->current_level; i>0; --i ) {
      while( n->num_forward >= i && forward[i-1] && h->compare((forward[i-1])->data, item) < 0 ) {
	n = forward[i-1];
	forward = (struct NODE **) (n+1);
      }
      update[i-1] = n;
    }
    n = *(struct NODE **) (n+1);
    struct NODE ** nforward = (struct NODE **) (n+1);
    if( h->compare(n->data, item) == 0 ) {
      for( int i=0; i<h->current_level; ++i ) {
	struct NODE ** forward = (struct NODE **) (update[i]+1);
	if( forward[i] != n )
	  break;
	forward[i] = nforward[i];
      }
      free( n );
      struct NODE ** hforward = (struct NODE **) (h->header+1);
      while( h->current_level > 1 && hforward[h->current_level] == NULL )
	h->current_level--;
      h->num_items -= 1;
    }
    free( update );
  }

  void * find( struct HANDLE * h, void const * item ) {
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    for( int i=h->current_level; i>0; --i ) {
      while( n->num_forward >= i && forward[i-1] && h->compare((forward[i-1])->data, item) < 0 ) {
	n = forward[i-1];
	forward = (struct NODE **) (n+1);
      }
    }
    n = *(struct NODE **) (n+1);
    return (n && h->compare(n->data, item) == 0) ? n->data : NULL;
  }

  struct NODE * first( struct HANDLE * h ) {
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    if( forward[0] ) {
      n = forward[0];
      return n;
    }
    return NULL;
  }

  struct NODE * next ( struct NODE * n ) {
    if( !n ) return NULL;
    struct NODE ** forward = (struct NODE **) (n+1);
    if( forward[0] ) {
      n = forward[0];
      return n;
    }
    return NULL;
  }

  size_t size( struct HANDLE * h ) {
    return h->num_items;
  }
};
<commit_msg>Update SKIP_LIST.cc<commit_after>
#include <stdlib.h>
#include <string.h>

#include "SKIP_LIST.h"

namespace SKIP_LIST {

  struct HANDLE {
    int (*compare) ( void const * node1, void const * node2 );
    int max_level;
    int current_level;
    double prob;
    unsigned short rand_state[3];
    size_t num_items;
    struct NODE * header;
  };

  struct HANDLE * init( int (*compare) ( void const * node1, void const * node2 ), int max_level, double prob ) {
    struct HANDLE *h = (struct HANDLE *) calloc( 1, sizeof(struct HANDLE) );
    h->compare = compare;
    if(max_level < 1) max_level = 32;
    if(prob < 0 || prob >= 1) prob = 0.25;
    h->max_level = max_level;
    h->current_level = 0;
    h->prob = prob;
    h->header = (struct NODE *) calloc( 1, sizeof(struct NODE) + sizeof(struct NODE*) * h->max_level );
    h->header->data = NULL;
    h->header->num_forward = h->max_level;
    h->num_items = 0;
    return h;
  }

  void destroy( struct HANDLE *& h ) {
    free(h);
    h = NULL;
  }

  int generate_level( HANDLE * h ) {
    int level = 0;
    double r;
    do {
      r = erand48(h->rand_state);
      ++level;
    } while(r < h->prob && level < h->max_level);
    return level;
  }

  void insert( struct HANDLE * h, void * item, size_t item_len ) {
    struct NODE ** update = (struct NODE **) calloc( 1, sizeof(struct NODE*) * h->max_level );
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    for( int i=h->current_level; i>0; --i ) {
      while( n->num_forward >= i && forward[i-1] && h->compare((forward[i-1])->data, item) < 0 ) {
	n = forward[i-1];
	forward = (struct NODE **) (n+1);
      }
      update[i-1] = n;
    }
    n = *(struct NODE **) (n+1);
    if( n && h->compare(n->data, item) == 0 ) {
    	free( update );
    	return;
    }
    else {
      int new_level = generate_level( h );
      if( new_level > h->current_level ) {
	for( int i=h->current_level; i<new_level; ++i ) {
	  update[i] = h->header;
	}
	h->current_level = new_level;
      }
      NODE * new_node = (struct NODE *) calloc( 1, sizeof(struct NODE) + item_len + sizeof(struct NODE*) * new_level );
      new_node->data = ((char *) (new_node+1)) + sizeof(struct NODE *) * new_level;
      memcpy( new_node->data, item, item_len );
      new_node->data_len = item_len;
      new_node->num_forward = new_level;
      struct NODE ** nforward = (struct NODE **) (new_node+1);
      for( int i=0; i<new_level; ++i ) {
	struct NODE ** forward = (struct NODE **) (update[i]+1);
	nforward[i] = forward[i];
	forward[i] = new_node;
      }
      h->num_items += 1;
    }
    free( update );
  }

  void remove( struct HANDLE * h, void * item ) {
    struct NODE ** update = (struct NODE **) calloc( 1, sizeof(struct NODE*) * h->max_level );
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    for( int i=h->current_level; i>0; --i ) {
      while( n->num_forward >= i && forward[i-1] && h->compare((forward[i-1])->data, item) < 0 ) {
	n = forward[i-1];
	forward = (struct NODE **) (n+1);
      }
      update[i-1] = n;
    }
    n = *(struct NODE **) (n+1);
    struct NODE ** nforward = (struct NODE **) (n+1);
    if( h->compare(n->data, item) == 0 ) {
      for( int i=0; i<h->current_level; ++i ) {
	struct NODE ** forward = (struct NODE **) (update[i]+1);
	if( forward[i] != n )
	  break;
	forward[i] = nforward[i];
      }
      free( n );
      struct NODE ** hforward = (struct NODE **) (h->header+1);
      while( h->current_level > 1 && hforward[h->current_level] == NULL )
	h->current_level--;
      h->num_items -= 1;
    }
    free( update );
  }

  void * find( struct HANDLE * h, void const * item ) {
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    for( int i=h->current_level; i>0; --i ) {
      while( n->num_forward >= i && forward[i-1] && h->compare((forward[i-1])->data, item) < 0 ) {
	n = forward[i-1];
	forward = (struct NODE **) (n+1);
      }
    }
    n = *(struct NODE **) (n+1);
    return (n && h->compare(n->data, item) == 0) ? n->data : NULL;
  }

  struct NODE * first( struct HANDLE * h ) {
    struct NODE * n = h->header;
    struct NODE ** forward = (struct NODE **) (n+1);
    if( forward[0] ) {
      n = forward[0];
      return n;
    }
    return NULL;
  }

  struct NODE * next ( struct NODE * n ) {
    if( !n ) return NULL;
    struct NODE ** forward = (struct NODE **) (n+1);
    if( forward[0] ) {
      n = forward[0];
      return n;
    }
    return NULL;
  }

  size_t size( struct HANDLE * h ) {
    return h->num_items;
  }
};
<|endoftext|>


<commit_before>#include "Solution.h"
#include "Location.h"
#include <cmath>
#include <cstdlib>
#include <utility>
#include <stdio.h>

Solution::Solution()
{
    //ctor
}

Solution::Solution(double cost, double infeasibilityCost):
                cost_(cost), infeasibilityCost_(infeasibilityCost){
}

Solution::~Solution()
{
    driverInst_.clear();
    trailerInst_.clear();
    stockLevelInst_.clear();
    safetyLevelInst_.clear();
}

void Solution::clear(){
    for(std::vector<std::vector<Shift*> > c : driverInst_){
        for(std::vector<Shift*> b : c){
            b.clear();
        }
        c.clear();
    }
    driverInst_.clear();

    for(std::vector<std::vector<Shift*> > c : trailerInst_){
        for(std::vector<Shift*> b : c){
            b.clear();
        }
        c.clear();
    }
    trailerInst_.clear();

    for(std::vector<double> a : stockLevelInst_){
        a.clear();
    }
    stockLevelInst_.clear();

    for(std::vector<std::vector<Stop*> > a : locationInstStop_){
        for(std::vector<Stop*> b : a)
            b.clear();
        a.clear();
    }
    locationInstStop_.clear();

    safetyLevelInst_.clear();

    infeasibilityCost_=-1;
    cost_=-1;
}

void Solution::reset(){
    std::vector<Shift*> v;
    v.resize(2,NULL);
    v.clear();

    clear();
    driverInst_.resize(InputData::getDrivers()->size());
    for(std::vector<std::vector<Shift*> > a : driverInst_){
        a.resize(InputData::getNumInst(),v);
    }

    trailerInst_.resize(InputData::getTrailers()->size());
    for(std::vector<std::vector<Shift*> > a : trailerInst_){
        a.resize(InputData::getNumInst(),v);
    }

    safetyLevelInst_.clear();
    stockLevelInst_.resize(InputData::getLocations()->size());
    int i=0;
    bool safetyLevelReached = false;
    for(Location* loc : *(InputData::getLocations())){
        switch(loc->getType()){
            case Location::BASE:{
                stockLevelInst_[i].clear();
            }break;
            case Location::SOURCE:{
                stockLevelInst_[i].resize(InputData::getNumInst(),INFINITY);
            }break;
            case Location::CUSTOMER:{
                Customer* c=(Customer*)loc;
                stockLevelInst_[i].resize(InputData::getNumInst(),c->getInitialQuantity());
                for(unsigned int j=1;j< c->getForecast()->size();j++){
                    stockLevelInst_[i][j]=stockLevelInst_[i][j-1]-(*(c->getForecast()))[j];
                    if(!safetyLevelReached && stockLevelInst_[i][j]<c->getSafetyLevel()){
                        safetyLevelReached = true;
                        safetyLevelInst_.insert(std::make_pair(j,c));
                    }
                }
            }break;
        }
        i++;
    }

    std::vector<Stop*> s;
    s.resize(2,NULL);
    s.clear();
    locationInstStop_.resize(InputData::getLocations()->size());
    for(std::vector<std::vector<Stop*> > a : locationInstStop_){
        a.resize(InputData::getNumInst(),s);
    }
}

int Solution::checkShift(Shift* shift){
    //    Shift* shift;
    int i;
    std::vector<Stop*>::iterator stopIt = shift->getStop()->begin();
    Stop* stop=*(stopIt);

    if(!shift->getDriver()->canDrive(shift->getTrailer())){
        return Penalty::TRAILER_DRIVER_COMPATIBILITY;
    }

    //retrieve trailer quantity
    double trailerQuant = shift->getTrailer()->getInicialQuantity();
    for(i=shift->getInitialInstant()-1; i>=0; i--){
        if(!getTrailerInst()->at(shift->getTrailer()->getIndex()).at(i).empty()){
            Shift* lastShift = getTrailerInst()->at(shift->getTrailer()->getIndex()).at(i).at(0);
//            trailerQuant = lastShift->getFinalQuantity();//TODO criar esse metodo
        }
    }
//    TODO: criar getInitialQuantity
//    if(trailerQuant!=shift->getInitialQuantity()){
//        return Penalty::TRAILER_INITIAL_QUANTITY;
//    }

    //falta checar se na primeira hora tem um shift terminando
    for(i= shift->getInitialInstant(); i<=shift->getFinalInstant(); ++i){
        //check if driver is available
        if(!getDriverInst()->at(shift->getDriver()->getIndex()).at(i).empty()){
            return Penalty::DRIVER_INTERSHIFT_DURATION;
        }
        //check if trailer is available
        if(!getTrailerInst()->at(shift->getTrailer()->getIndex()).at(i).empty()){
            return Penalty::TRAILER_SHIFTS_OVERLAP;
        }
        //check if location is availble
        if(stop!=NULL && stop->getArriveTime() >= i && stop->getArriveTime() < i+1){
            for(int k=i; k<i+stop->getLocation()->getSetupTime();k++){
                if(!getLocationInstStop()->at(stop->getLocation()->getIndex()).at(i).empty()){
                    return Penalty::STOP_ARRIVAL_TIME;
                }
            }
            trailerQuant-=stop->getQuantity();
            if(trailerQuant<0){
                return Penalty::TRAILER_NON_NEGATIVE_QUANTITY;
            }else if(trailerQuant > shift->getTrailer()->getCapacity()){
                return Penalty::TRAILER_MAX_CAPACITY;
            }
            if(stop->getLocation()->getType()==Location::CUSTOMER){
                Customer* customer= (Customer*) stop->getLocation();
                if(!customer->isTrailerAllowed(shift->getTrailer())){
                    return Penalty::CUSTOMER_TRAILER_COMPATIBILITY;
                }
                //check stockLevel
                for(int k=i;k< (int)getStockLevelInst()->size();k++){
                    if( getStockLevelInst()->at(customer->getIndex()).at(k)+
                        stop->getQuantity() > customer->getCapacity() ){
                        return Penalty::CUSTOMER_MAX_TANK_CAPACITY;
                    }
                }
            }else if(stop->getLocation()->getType()==Location::SOURCE){
                Source* source= (Source*) stop->getLocation();
                for(int k=i;k< (int)getStockLevelInst()->size();k++){
                    if( getStockLevelInst()->at(source->getIndex()).at(k)+
                        stop->getQuantity() < 0 ){
                        return Penalty::SOURCE_NON_NEGATIVE_CAPACITY;//TODO replace source_non by source
                    }
                }
                if(stop->getQuantity()>0){
                    printf("Stop deve ter quantidade negativa se location for source\n");
                    return Penalty::SOURCE_MAX_TANK_CAPACITY;
                }
            }
            stopIt++;
            stop= (stopIt!=shift->getStop()->end()) ? *stopIt : NULL;
        }
    }
}

bool Solution::checkStop(Stop* stop){
    /*
        1 Does the Shift Fits?
            Verify if there is not another Stop at the instant
        2 Conflict with another driver/trailer
            Verify if there is another Stop in the same location at the same instant
    */
}

void Solution::insertShift(Shift* shift){
    //Hour interval
    int iniHour_ = (shift->getInitialInstant());//Initial hour of the shift
    int finalHour_ = (shift->getFinalInstant());//Final hour of the shift

    //driverInst_
    int driverIndex_ = shift->getDriver()->getIndex();//Get the shift's driver index
    for(int i=iniHour_;i<=finalHour_;i++){
        driverInst_[driverIndex_][i].push_back(shift);//Add the shift on the driver's Instants list
    }

    //trailerInst_
    int trailerIndex_ = shift->getTrailer()->getIndex();//Get the shift's trailer index
    for(int i=iniHour_;i<=finalHour_;i++){
        trailerInst_[trailerIndex_][i].push_back(shift);//Add the shift on the trailer's Instants list
    }

    //locationInstStop_
    for(int j=0;j<shift->getStop()->size();j++){//j = stop
        int locationIndex_ = shift->getStop()->at(j)->getLocation()->getIndex();//Getting each location index

        double iniHourStop_ = shift->getStop()->at(j)->getArriveTime();//initial our of arrival at location
        double finalHourStop_ = shift->getStop()->at(j)->getArriveTime();//setting up the final hour of arrival/ hour of departure from location

        if( instanceof<Customer>(shift->getStop()->at(j)->getLocation())){
            finalHourStop_ += ((Customer*)shift->getStop()->at(j)->getLocation())->getSetupTime();
        }else if( instanceof<Source>(shift->getStop()->at(j)->getLocation()) ){
            finalHourStop_ += ((Source*)shift->getStop()->at(j)->getLocation())->getSetupTime();
        }

        for(int i=iniHourStop_;i<=finalHourStop_;i++){
            locationInstStop_[locationIndex_][i].push_back(shift->getStop()->at(j));//Adding the stop on the Instant list
        }
    }
    shift->setSolution(this);
}

void Solution::removeShift(Shift* shift){
    //Hour interval
    int iniHour_ = (shift->getInitialInstant());
    int finalHour_ = (shift->getFinalInstant());

    //driverInst_
    int driverIndex_ = shift->getDriver()->getIndex();
    for(int i=iniHour_;i<=finalHour_;i++){
        for(int j=0;j<driverInst_[driverIndex_][i].size();j++){//For every hour on the driver's list
            if(driverInst_[driverIndex_][i].at(j)==shift){//Checking to see if the shift is present on that position
                driverInst_[driverIndex_][i].erase(driverInst_[driverIndex_][i].begin()+j);//If it is, remove it.
            }
        }
    }

    //trailerInst_
    int trailerIndex_ = shift->getTrailer()->getIndex();
    for(int i=iniHour_;i<=finalHour_;i++){
        for(int j=0;j<trailerInst_[trailerIndex_][i].size();j++){//For every hour on the trailer's list
            if(trailerInst_[trailerIndex_][i].at(j)==shift){//Checking to see if the shift is present on that position
                trailerInst_[trailerIndex_][i].erase(trailerInst_[trailerIndex_][i].begin()+j);//If it is, remove it.
            }
        }
    }
    //locationInstStop_
    for(int j=0;j<shift->getStop()->size();j++){//j = stop
        int locationIndex_ = shift->getStop()->at(j)->getLocation()->getIndex();//Getting each location index

        double iniHourStop_ = shift->getStop()->at(j)->getArriveTime();//initial our of arrival at location
        double finalHourStop_ = shift->getStop()->at(j)->getArriveTime();//setting up the final hour of arrival/ hour of departure from location

        if( instanceof<Customer>(shift->getStop()->at(j)->getLocation())){
            finalHourStop_ += ((Customer*)shift->getStop()->at(j)->getLocation())->getSetupTime();

            //Updating the Stock of the customer
            for(int time=iniHourStop_;time<stockLevelInst_[locationIndex_].size();time++){
                if(stockLevelInst_[locationIndex_][time]==0)
                    break;

                stockLevelInst_[locationIndex_][time] -= shift->getStop()->at(j)->getQuantity();

                if(stockLevelInst_[locationIndex_][time]<0){
                    stockLevelInst_[locationIndex_][time]=0;
                }
            }

        }
		else if( instanceof<Source>(shift->getStop()->at(j)->getLocation()) ){
            finalHourStop_ += ((Source*)shift->getStop()->at(j)->getLocation())->getSetupTime();
        }

        for(int i=iniHourStop_;i<=finalHourStop_;i++){
            for(int k=0;k<locationInstStop_[locationIndex_][i].size();k++){//For every hour on the locations's list
                if(locationInstStop_[locationIndex_][i].at(k) == shift->getStop()->at(j)){

                    //Removing Stop
                    locationInstStop_[locationIndex_][i].erase(locationInstStop_[locationIndex_][i].begin()+k);//If it is, remove it.
                }
            }
        }
    }
    shift->setSolution(NULL);
    /**

    TODO             -> VERIFICAR OS SHIFTS VIZINHOS DO TRAILER
                        MODIFICAR OS ESTOQUES DE TODOS OS STOPS
                        RETORNAR OS NOVO CUSTO
    **/

}

void Solution::insertStopInShift(Shift* shift, Stop* stop){
}

void Solution::removeStopFromShift(Shift* shift, Stop* stop){
}

void Solution::calcCost(){
    double totalQuantity = 0;
    double cost  = 0;

    int maxTankCapacity = 0;
    int safetyLevel = 0;
    int runOut = 0;

    for(int i=0;i<trailerInst_.size();i++){
        Shift* shift = NULL;
        for(int j=0;j<trailerInst_.at(i).size();j++){
            for(int k=0;k<trailerInst_.at(i).at(j).size();k++){
                if(shift == NULL || shift != trailerInst_.at(i).at(j).at(k)){
                    shift = trailerInst_.at(i).at(j).at(k);
                    cost += shift->getCost();
                    totalQuantity += shift->getQuantityDelivered();
                }
            }
        }
    }

    cost_ = cost/totalQuantity;

    //chegando se violou restries
    for(Customer* c: *InputData::getCustomers()){
        for(double i: stockLevelInst_.at(c->getIndex())){
            if(c->getCapacity() < i){
                maxTankCapacity++;
            }

            if(c->getSafetyLevel() > i){
                safetyLevel++;
            }

            if(0 >= i){
                runOut++;
            }
        }
    }

    cost += maxTankCapacity * Penalties::getValue(CUSTOMER_MAX_TANK_CAPACITY) +
            safetyLevel * Penalties::getValue(CUSTOMER_SAFETY_LEVEL) +
            runOut * Penalties::getValue(CUSTOMER_RUN_OUT);

}
<commit_msg>Alterações em removeShift<commit_after>#include "Solution.h"
#include "Location.h"
#include <cmath>
#include <cstdlib>
#include <utility>
#include <stdio.h>

Solution::Solution()
{
    //ctor
}

Solution::Solution(double cost, double infeasibilityCost):
                cost_(cost), infeasibilityCost_(infeasibilityCost){
}

Solution::~Solution()
{
    driverInst_.clear();
    trailerInst_.clear();
    stockLevelInst_.clear();
    safetyLevelInst_.clear();
}

void Solution::clear(){
    for(std::vector<std::vector<Shift*> > c : driverInst_){
        for(std::vector<Shift*> b : c){
            b.clear();
        }
        c.clear();
    }
    driverInst_.clear();

    for(std::vector<std::vector<Shift*> > c : trailerInst_){
        for(std::vector<Shift*> b : c){
            b.clear();
        }
        c.clear();
    }
    trailerInst_.clear();

    for(std::vector<double> a : stockLevelInst_){
        a.clear();
    }
    stockLevelInst_.clear();

    for(std::vector<std::vector<Stop*> > a : locationInstStop_){
        for(std::vector<Stop*> b : a)
            b.clear();
        a.clear();
    }
    locationInstStop_.clear();

    safetyLevelInst_.clear();

    infeasibilityCost_=-1;
    cost_=-1;
}

void Solution::reset(){
    std::vector<Shift*> v;
    v.resize(2,NULL);
    v.clear();

    clear();
    driverInst_.resize(InputData::getDrivers()->size());
    for(std::vector<std::vector<Shift*> > a : driverInst_){
        a.resize(InputData::getNumInst(),v);
    }

    trailerInst_.resize(InputData::getTrailers()->size());
    for(std::vector<std::vector<Shift*> > a : trailerInst_){
        a.resize(InputData::getNumInst(),v);
    }

    safetyLevelInst_.clear();
    stockLevelInst_.resize(InputData::getLocations()->size());
    int i=0;
    bool safetyLevelReached = false;
    for(Location* loc : *(InputData::getLocations())){
        switch(loc->getType()){
            case Location::BASE:{
                stockLevelInst_[i].clear();
            }break;
            case Location::SOURCE:{
                stockLevelInst_[i].resize(InputData::getNumInst(),INFINITY);
            }break;
            case Location::CUSTOMER:{
                Customer* c=(Customer*)loc;
                stockLevelInst_[i].resize(InputData::getNumInst(),c->getInitialQuantity());
                for(unsigned int j=1;j< c->getForecast()->size();j++){
                    stockLevelInst_[i][j]=stockLevelInst_[i][j-1]-(*(c->getForecast()))[j];
                    if(!safetyLevelReached && stockLevelInst_[i][j]<c->getSafetyLevel()){
                        safetyLevelReached = true;
                        safetyLevelInst_.insert(std::make_pair(j,c));
                    }
                }
            }break;
        }
        i++;
    }

    std::vector<Stop*> s;
    s.resize(2,NULL);
    s.clear();
    locationInstStop_.resize(InputData::getLocations()->size());
    for(std::vector<std::vector<Stop*> > a : locationInstStop_){
        a.resize(InputData::getNumInst(),s);
    }
}

int Solution::checkShift(Shift* shift){
    //    Shift* shift;
    int i;
    std::vector<Stop*>::iterator stopIt = shift->getStop()->begin();
    Stop* stop=*(stopIt);

    if(!shift->getDriver()->canDrive(shift->getTrailer())){
        return Penalty::TRAILER_DRIVER_COMPATIBILITY;
    }

    //retrieve trailer quantity
    double trailerQuant = shift->getTrailer()->getInicialQuantity();
    for(i=shift->getInitialInstant()-1; i>=0; i--){
        if(!getTrailerInst()->at(shift->getTrailer()->getIndex()).at(i).empty()){
            Shift* lastShift = getTrailerInst()->at(shift->getTrailer()->getIndex()).at(i).at(0);
//            trailerQuant = lastShift->getFinalQuantity();//TODO criar esse metodo
        }
    }
//    TODO: criar getInitialQuantity
//    if(trailerQuant!=shift->getInitialQuantity()){
//        return Penalty::TRAILER_INITIAL_QUANTITY;
//    }

    //falta checar se na primeira hora tem um shift terminando
    for(i= shift->getInitialInstant(); i<=shift->getFinalInstant(); ++i){
        //check if driver is available
        if(!getDriverInst()->at(shift->getDriver()->getIndex()).at(i).empty()){
            return Penalty::DRIVER_INTERSHIFT_DURATION;
        }
        //check if trailer is available
        if(!getTrailerInst()->at(shift->getTrailer()->getIndex()).at(i).empty()){
            return Penalty::TRAILER_SHIFTS_OVERLAP;
        }
        //check if location is availble
        if(stop!=NULL && stop->getArriveTime() >= i && stop->getArriveTime() < i+1){
            for(int k=i; k<i+stop->getLocation()->getSetupTime();k++){
                if(!getLocationInstStop()->at(stop->getLocation()->getIndex()).at(i).empty()){
                    return Penalty::STOP_ARRIVAL_TIME;
                }
            }
            trailerQuant-=stop->getQuantity();
            if(trailerQuant<0){
                return Penalty::TRAILER_NON_NEGATIVE_QUANTITY;
            }else if(trailerQuant > shift->getTrailer()->getCapacity()){
                return Penalty::TRAILER_MAX_CAPACITY;
            }
            if(stop->getLocation()->getType()==Location::CUSTOMER){
                Customer* customer= (Customer*) stop->getLocation();
                if(!customer->isTrailerAllowed(shift->getTrailer())){
                    return Penalty::CUSTOMER_TRAILER_COMPATIBILITY;
                }
                //check stockLevel
                for(int k=i;k< (int)getStockLevelInst()->size();k++){
                    if( getStockLevelInst()->at(customer->getIndex()).at(k)+
                        stop->getQuantity() > customer->getCapacity() ){
                        return Penalty::CUSTOMER_MAX_TANK_CAPACITY;
                    }
                }
            }else if(stop->getLocation()->getType()==Location::SOURCE){
                Source* source= (Source*) stop->getLocation();
                for(int k=i;k< (int)getStockLevelInst()->size();k++){
                    if( getStockLevelInst()->at(source->getIndex()).at(k)+
                        stop->getQuantity() < 0 ){
                        return Penalty::SOURCE_NON_NEGATIVE_CAPACITY;//TODO replace source_non by source
                    }
                }
                if(stop->getQuantity()>0){
                    printf("Stop deve ter quantidade negativa se location for source\n");
                    return Penalty::SOURCE_MAX_TANK_CAPACITY;
                }
            }
            stopIt++;
            stop= (stopIt!=shift->getStop()->end()) ? *stopIt : NULL;
        }
    }
}

bool Solution::checkStop(Stop* stop){
    /*
        1 Does the Shift Fits?
            Verify if there is not another Stop at the instant
        2 Conflict with another driver/trailer
            Verify if there is another Stop in the same location at the same instant
    */
}

void Solution::insertShift(Shift* shift){
    //Hour interval
    int iniHour_ = (shift->getInitialInstant());//Initial hour of the shift
    int finalHour_ = (shift->getFinalInstant());//Final hour of the shift

    //driverInst_
    int driverIndex_ = shift->getDriver()->getIndex();//Get the shift's driver index
    for(int i=iniHour_;i<=finalHour_;i++){
        driverInst_[driverIndex_][i].push_back(shift);//Add the shift on the driver's Instants list
    }

    //trailerInst_
    int trailerIndex_ = shift->getTrailer()->getIndex();//Get the shift's trailer index
    for(int i=iniHour_;i<=finalHour_;i++){
        trailerInst_[trailerIndex_][i].push_back(shift);//Add the shift on the trailer's Instants list
    }

    //locationInstStop_
    for(int j=0;j<shift->getStop()->size();j++){//j = stop
        int locationIndex_ = shift->getStop()->at(j)->getLocation()->getIndex();//Getting each location index

        double iniHourStop_ = shift->getStop()->at(j)->getArriveTime();//initial our of arrival at location
        double finalHourStop_ = shift->getStop()->at(j)->getArriveTime();//setting up the final hour of arrival/ hour of departure from location

        if( instanceof<Customer>(shift->getStop()->at(j)->getLocation())){
            finalHourStop_ += ((Customer*)shift->getStop()->at(j)->getLocation())->getSetupTime();
        }else if( instanceof<Source>(shift->getStop()->at(j)->getLocation()) ){
            finalHourStop_ += ((Source*)shift->getStop()->at(j)->getLocation())->getSetupTime();
        }

        for(int i=iniHourStop_;i<=finalHourStop_;i++){
            locationInstStop_[locationIndex_][i].push_back(shift->getStop()->at(j));//Adding the stop on the Instant list
        }
    }
    shift->setSolution(this);
}

void Solution::removeShift(Shift* shift){
    //Hour interval
    int iniHour_ = (shift->getInitialInstant());
    int finalHour_ = (shift->getFinalInstant());

    //driverInst_
    int driverIndex_ = shift->getDriver()->getIndex();
    for(int i=iniHour_;i<=finalHour_;i++){
        for(int j=0;j<driverInst_[driverIndex_][i].size();j++){//For every hour on the driver's list
            if(driverInst_[driverIndex_][i].at(j)==shift){//Checking to see if the shift is present on that position
                driverInst_[driverIndex_][i].erase(driverInst_[driverIndex_][i].begin()+j);//If it is, remove it.
            }
        }
    }

    //trailerInst_
    int trailerIndex_ = shift->getTrailer()->getIndex();
    for(int i=iniHour_;i<=finalHour_;i++){
        for(int j=0;j<trailerInst_[trailerIndex_][i].size();j++){//For every hour on the trailer's list
            if(trailerInst_[trailerIndex_][i].at(j)==shift){//Checking to see if the shift is present on that position
                trailerInst_[trailerIndex_][i].erase(trailerInst_[trailerIndex_][i].begin()+j);//If it is, remove it.
            }
        }
    }

    //locationInstStop_
    for(int j=0;j<shift->getStop()->size();j++){//j = stop
        int locationIndex_ = shift->getStop()->at(j)->getLocation()->getIndex();//Getting each location index

        double iniHourStop_ = shift->getStop()->at(j)->getArriveTime();//initial hour of arrival at location
        double finalHourStop_ = shift->getStop()->at(j)->getArriveTime();//setting up the final hour of arrival/ hour of departure from location

        if( instanceof<Customer>(shift->getStop()->at(j)->getLocation())){
            finalHourStop_ += ((Customer*)shift->getStop()->at(j)->getLocation())->getSetupTime();

            //Updating the Stock of the customer
            for(int time=iniHourStop_;time<stockLevelInst_[locationIndex_].size();time++){
                if(stockLevelInst_[locationIndex_][time]==0)
                    break;

                stockLevelInst_[locationIndex_][time] -= shift->getStop()->at(j)->getQuantity();

                if(stockLevelInst_[locationIndex_][time]<0){
                    stockLevelInst_[locationIndex_][time]=0;
                }
            }

        }
		else if( instanceof<Source>(shift->getStop()->at(j)->getLocation()) ){
            finalHourStop_ += ((Source*)shift->getStop()->at(j)->getLocation())->getSetupTime();
        }

        for(int i=iniHourStop_;i<=finalHourStop_;i++){
            for(int k=0;k<locationInstStop_[locationIndex_][i].size();k++){//For every hour on the locations's list
                if(locationInstStop_[locationIndex_][i].at(k) == shift->getStop()->at(j)){

                    //Removing Stop
                    locationInstStop_[locationIndex_][i].erase(locationInstStop_[locationIndex_][i].begin()+k);//If it is, remove it.
                }
            }
        }
    }
    shift->setSolution(NULL);
    calcCost();
    /**

    TODO             -> ( )VERIFICAR OS SHIFTS VIZINHOS DO TRAILER
                        (x)MODIFICAR OS ESTOQUES DE TODOS OS STOPS
                        (x)RETORNAR OS NOVOS CUSTO
    **/

}

void Solution::insertStopInShift(Shift* shift, Stop* stop){
}

void Solution::removeStopFromShift(Shift* shift, Stop* stop){
}

void Solution::calcCost(){
    double totalQuantity = 0;
    double cost  = 0;

    int maxTankCapacity = 0;
    int safetyLevel = 0;
    int runOut = 0;

    for(int i=0;i<trailerInst_.size();i++){
        Shift* shift = NULL;
        for(int j=0;j<trailerInst_.at(i).size();j++){
            for(int k=0;k<trailerInst_.at(i).at(j).size();k++){
                if(shift == NULL || shift != trailerInst_.at(i).at(j).at(k)){
                    shift = trailerInst_.at(i).at(j).at(k);
                    cost += shift->getCost();
                    totalQuantity += shift->getQuantityDelivered();
                }
            }
        }
    }

    cost_ = cost/totalQuantity;

    //chegando se violou restries
    for(Customer* c: *InputData::getCustomers()){
        for(double i: stockLevelInst_.at(c->getIndex())){
            if(c->getCapacity() < i){
                maxTankCapacity++;
            }

            if(c->getSafetyLevel() > i){
                safetyLevel++;
            }

            if(0 >= i){
                runOut++;
            }
        }
    }

    cost += maxTankCapacity * Penalties::getValue(CUSTOMER_MAX_TANK_CAPACITY) +
            safetyLevel * Penalties::getValue(CUSTOMER_SAFETY_LEVEL) +
            runOut * Penalties::getValue(CUSTOMER_RUN_OUT);

}
<|endoftext|>


<commit_before>#include <cassert>
#include "tinyxml2.h"
#include "onut.h"
#include "crypto.h"
#include "zlib/zlib.h"

namespace onut
{
    TiledMap::sLayer::~sLayer()
    {
    }

    TiledMap::sTileLayer::~sTileLayer()
    {
        if (tileIds) delete[] tileIds;
    }

    TiledMap::sObjectLayer::~sObjectLayer()
    {
        if (pObjects) delete[] pObjects;
    }

    TiledMap::sTileLayerInternal::~sTileLayerInternal()
    {
        if (tiles) delete[] tiles;
    }

    TiledMap::TiledMap(const std::string &map, onut::ContentManager<> *pContentManager)
    {
        tinyxml2::XMLDocument doc;
        doc.LoadFile(map.c_str());
        assert(!doc.Error());
        auto pXMLMap = doc.FirstChildElement("map");
        assert(pXMLMap);

        // Tilesets
        for (auto pXMLTileset = pXMLMap->FirstChildElement("tileset"); pXMLTileset; pXMLTileset = pXMLTileset->NextSiblingElement("tileset"))
        {
            ++m_tilesetCount;
        }
        assert(m_tilesetCount);
        m_tileSets = new sTileSet[m_tilesetCount];
        m_tilesetCount = 0;
        for (auto pXMLTileset = pXMLMap->FirstChildElement("tileset"); pXMLTileset; pXMLTileset = pXMLTileset->NextSiblingElement("tileset"))
        {
            auto &pTileSet = m_tileSets[m_tilesetCount];

            pTileSet.name = pXMLTileset->Attribute("name");
            pTileSet.firstId = pXMLTileset->IntAttribute("firstgid");
            assert(pTileSet.firstId);
            pTileSet.tileWidth = pXMLTileset->IntAttribute("tilewidth");
            assert(pTileSet.tileWidth);
            pTileSet.tileHeight = pXMLTileset->IntAttribute("tileheight");
            assert(pTileSet.tileHeight);

            auto pXMLImage = pXMLTileset->FirstChildElement("image");
            assert(pXMLImage);
            auto szImageFilename = pXMLImage->Attribute("source");
            assert(szImageFilename);
            auto filename = getPath(map) + "/" + szImageFilename;
            pTileSet.pTexture = pContentManager->getResource<Texture>(filename);

            ++m_tilesetCount;
        }

        // Layers
        for (auto pXMLLayer = pXMLMap->FirstChildElement(); pXMLLayer; pXMLLayer = pXMLLayer->NextSiblingElement())
        {
            if (!strcmp(pXMLLayer->Name(), "layer") ||
                !strcmp(pXMLLayer->Name(), "objectgroup"))
            {
                ++m_layerCount;
            }
        }
        assert(m_layerCount);
        m_layers = new sLayer*[m_layerCount];
        m_layerCount = 0;
        for (auto pXMLLayer = pXMLMap->FirstChildElement(); pXMLLayer; pXMLLayer = pXMLLayer->NextSiblingElement())
        {
            if (!strcmp(pXMLLayer->Name(), "layer"))
            {
                m_layers[m_layerCount] = new sTileLayerInternal();
                auto &pLayer = *(sTileLayerInternal*)m_layers[m_layerCount];

                pLayer.name = pXMLLayer->Attribute("name");
                if (pXMLLayer->Attribute("visible"))
                {
                    pLayer.isVisible = pXMLLayer->BoolAttribute("visible");
                }

                pLayer.width = pXMLLayer->IntAttribute("width");
                assert(pLayer.width);
                pLayer.height = pXMLLayer->IntAttribute("height");
                assert(pLayer.height);
                m_width = std::max<>(m_width, pLayer.width);
                m_height = std::max<>(m_height, pLayer.height);
                auto len = pLayer.width * pLayer.height;
                pLayer.tileIds = new uint32_t[len];

                auto pXMLData = pXMLLayer->FirstChildElement("data");
                assert(pXMLData);
                auto szEncoding = pXMLData->Attribute("encoding");
                auto szCompression = pXMLData->Attribute("compression");

                if (!szEncoding)
                {
                    int i = 0;
                    for (auto pXMLTile = pXMLData->FirstChildElement("tile"); pXMLTile; pXMLTile = pXMLTile->NextSiblingElement("tile"), ++i)
                    {
                        auto id = pXMLTile->IntAttribute("gid");
                        assert(i < len);
                        pLayer.tileIds[i] = id;
                    }
                    assert(i == len);
                }
                else
                {
                    auto szData = pXMLData->GetText();
                    assert(szData);
                    auto pos = std::string(szData).find_first_not_of("\n ");
                    assert(pos < strlen(szData));
                    szData = szData + pos;

                    if (!strcmp(szEncoding, "csv"))
                    {
                        auto csvData = splitString(szData, ',');
                        assert(static_cast<int>(csvData.size()) == len);
                        for (int i = 0; i < len; ++i)
                        {
                            try
                            {
                                pLayer.tileIds[i] = static_cast<uint32_t>(std::stoul(csvData[i]));
                            }
                            catch (std::exception e)
                            {
                                assert(false);
                            }
                        }
                    }
                    else if (!strcmp(szEncoding, "base64"))
                    {
                        auto decoded = base64_decode(szData);
                        if (!szCompression)
                        {
                            assert(static_cast<int>(decoded.size()) == len * 4);
                            memcpy(pLayer.tileIds, decoded.data(), 4 * len);
                        }
                        else if (!strcmp(szCompression, "gzip"))
                        {
                            int err;
                            z_stream d_stream; // decompression stream

                            d_stream.zalloc = (alloc_func)0;
                            d_stream.zfree = (free_func)0;
                            d_stream.opaque = (voidpf)0;

                            d_stream.next_in = reinterpret_cast<Bytef*>(decoded.data()); // where deflated is a pointer the the compressed data buffer
                            d_stream.avail_in = static_cast<uInt>(decoded.size()); // where deflatedLen is the length of the compressed data
                            d_stream.next_out = reinterpret_cast<Bytef*>(pLayer.tileIds); // where inflated is a pointer to the resulting uncompressed data buffer
                            d_stream.avail_out = static_cast<uInt>(len * 4); // where inflatedLen is the size of the uncompressed data buffer

                            err = inflateInit2(&d_stream, 31);
                            assert(err == Z_OK);
                            err = inflate(&d_stream, Z_FINISH);
                            assert(err == Z_STREAM_END);
                            err = inflateEnd(&d_stream);
                            assert(err == Z_OK);
                        }
                        else if (!strcmp(szCompression, "zlib"))
                        {
                            int err;
                            z_stream d_stream; // decompression stream

                            d_stream.zalloc = (alloc_func)0;
                            d_stream.zfree = (free_func)0;
                            d_stream.opaque = (voidpf)0;

                            d_stream.next_in = reinterpret_cast<Bytef*>(decoded.data()); // where deflated is a pointer the the compressed data buffer
                            d_stream.avail_in = static_cast<uInt>(decoded.size()); // where deflatedLen is the length of the compressed data
                            d_stream.next_out = reinterpret_cast<Bytef*>(pLayer.tileIds); // where inflated is a pointer to the resulting uncompressed data buffer
                            d_stream.avail_out = static_cast<uInt>(len * 4); // where inflatedLen is the size of the uncompressed data buffer

                            err = inflateInit2(&d_stream, 15 + 32);
                            assert(err == Z_OK);
                            err = inflate(&d_stream, Z_FINISH);
                            assert(err == Z_STREAM_END);
                            err = inflateEnd(&d_stream);
                            assert(err == Z_OK);
                        }
                    }
                }

                // Resolve the tiles to tilesets
                pLayer.tiles = new sTile[len];
                for (int i = 0; i < len; ++i)
                {
                    auto pTile = pLayer.tiles + i;
                    auto tileId = pLayer.tileIds[i];
                    if (tileId == 0)
                    {
                        continue;
                    }
                    auto pTileSet = m_tileSets;
                    for (int j = 0; j < m_tilesetCount; ++j, pTileSet)
                    {
                        if (pTileSet->firstId > static_cast<int>(tileId)) break;
                    }
                    pTile->pTileset = pTileSet;
                    auto texSize = pTileSet->pTexture->getSize();
                    auto fitW = texSize.x / 40;
                    auto fitH = texSize.y / 40;
                    auto onTextureId = tileId - pTileSet->firstId;
                    pTile->UVs.x = static_cast<float>((onTextureId % fitW) * pTileSet->tileWidth) / static_cast<float>(texSize.x);
                    pTile->UVs.y = static_cast<float>((onTextureId / fitH) * pTileSet->tileHeight) / static_cast<float>(texSize.y);
                    pTile->UVs.z = static_cast<float>((onTextureId % fitW + 1) * pTileSet->tileWidth) / static_cast<float>(texSize.x);
                    pTile->UVs.w = static_cast<float>((onTextureId / fitH + 1) * pTileSet->tileHeight) / static_cast<float>(texSize.y);
                    pTile->rect.x = static_cast<float>((i % pLayer.width) * pTileSet->tileWidth);
                    pTile->rect.y = static_cast<float>((i / pLayer.height) * pTileSet->tileHeight);
                    pTile->rect.z = static_cast<float>(pTileSet->tileWidth);
                    pTile->rect.w = static_cast<float>(pTileSet->tileHeight);
                }

                ++m_layerCount;
            }
            else if (!strcmp(pXMLLayer->Name(), "objectgroup"))
            {
                m_layers[m_layerCount] = new sObjectLayer();
                auto &pLayer = *(sObjectLayer*)m_layers[m_layerCount];

                pLayer.name = pXMLLayer->Attribute("name");
                if (pXMLLayer->Attribute("visible"))
                {
                    pLayer.isVisible = pXMLLayer->BoolAttribute("visible");
                }

                for (auto pXMLObject = pXMLLayer->FirstChildElement("object"); pXMLObject; pXMLObject = pXMLObject->NextSiblingElement("object"))
                {
                    pLayer.objectCount++;
                }
                pLayer.pObjects = new sObject[pLayer.objectCount];
                pLayer.objectCount = 0;
                for (auto pXMLObject = pXMLLayer->FirstChildElement("object"); pXMLObject; pXMLObject = pXMLObject->NextSiblingElement("object"))
                {
                    auto &object = pLayer.pObjects[pLayer.objectCount];
                    pLayer.objectCount++;

                    object.id = pXMLObject->IntAttribute("id");
                    if (pXMLObject->Attribute("name")) object.name = pXMLObject->Attribute("name");
                    if (pXMLObject->Attribute("type")) object.type = pXMLObject->Attribute("type");
                    object.position.x = pXMLObject->FloatAttribute("x");
                    object.position.y = pXMLObject->FloatAttribute("y");
                    object.size.x = pXMLObject->FloatAttribute("width");
                    object.size.y = pXMLObject->FloatAttribute("160");

                    auto pXMLProperties = pXMLObject->FirstChildElement("properties");
                    if (pXMLProperties)
                    {
                        for (auto pXMLProperty = pXMLProperties->FirstChildElement("property"); pXMLProperty; pXMLProperty = pXMLProperty->NextSiblingElement("property"))
                        {
                            if (pXMLProperty->Attribute("name") &&
                                pXMLProperty->Attribute("value"))
                            {
                                object.properties[pXMLProperty->Attribute("name")] = pXMLProperty->Attribute("value");
                            }
                        }
                    }
                }

                ++m_layerCount;
            }
        }

        //TODO: Compile the graphics by batch of 16x16 terrain chunks
    }

    TiledMap::~TiledMap()
    {
        if (m_layers)
        {
            for (auto i = 0; i < m_layerCount; ++i)
            {
                if (m_layers[i]) delete m_layers[i];
            }
            delete[] m_layers;
        }
        if (m_tileSets) delete[] m_tileSets;
    }

    TiledMap::sLayer *TiledMap::getLayer(const std::string &name) const
    {
        for (int i = 0; i < m_layerCount; ++i)
        {
            if (m_layers[i]->name == name) return m_layers[i];
        }
        return nullptr;
    }

    void TiledMap::render(const RECT &rect)
    {
        for (int i = 0; i < m_layerCount; ++i)
        {
            if (!m_layers[i]->isVisible) continue;
            renderLayer(rect, m_layers[i]);
        }
    }

    void TiledMap::renderLayer(const RECT &rect, int index)
    {
        renderLayer(rect, m_layers[index]);
    }

    void TiledMap::renderLayer(const RECT &rect, const std::string &name)
    {
        renderLayer(rect, getLayer(name));
    }

    void TiledMap::renderLayer(const RECT &in_rect, sLayer *in_pLayer)
    {
        auto pLayer = dynamic_cast<sTileLayerInternal*>(in_pLayer);
        if (!pLayer) return;

        RECT rect = in_rect;
        rect.left = std::max<>(0l, rect.left);
        rect.top = std::max<>(0l, rect.top);
        rect.right = std::min<>(static_cast<LONG>(m_width - 1), rect.right);
        rect.bottom = std::min<>(static_cast<LONG>(m_height - 1), rect.bottom);

        egModelPush();
        egModelIdentity();
        egModelMult(&m_transform._11);

        OSB->begin();
        for (LONG y = rect.top; y <= rect.bottom; ++y)
        {
            sTile *pTile = pLayer->tiles + y * m_width + rect.left;
            for (LONG x = rect.left; x <= rect.right; ++x, ++pTile)
            {
                if (!pTile->pTileset) continue;
                OSB->drawRectWithUVs(pTile->pTileset->pTexture, pTile->rect, pTile->UVs);
            }
        }
        OSB->end();

        egModelPop();
    }
};
<commit_msg>Fixed size.y not being set<commit_after>#include <cassert>
#include "tinyxml2.h"
#include "onut.h"
#include "crypto.h"
#include "zlib/zlib.h"

namespace onut
{
    TiledMap::sLayer::~sLayer()
    {
    }

    TiledMap::sTileLayer::~sTileLayer()
    {
        if (tileIds) delete[] tileIds;
    }

    TiledMap::sObjectLayer::~sObjectLayer()
    {
        if (pObjects) delete[] pObjects;
    }

    TiledMap::sTileLayerInternal::~sTileLayerInternal()
    {
        if (tiles) delete[] tiles;
    }

    TiledMap::TiledMap(const std::string &map, onut::ContentManager<> *pContentManager)
    {
        tinyxml2::XMLDocument doc;
        doc.LoadFile(map.c_str());
        assert(!doc.Error());
        auto pXMLMap = doc.FirstChildElement("map");
        assert(pXMLMap);

        // Tilesets
        for (auto pXMLTileset = pXMLMap->FirstChildElement("tileset"); pXMLTileset; pXMLTileset = pXMLTileset->NextSiblingElement("tileset"))
        {
            ++m_tilesetCount;
        }
        assert(m_tilesetCount);
        m_tileSets = new sTileSet[m_tilesetCount];
        m_tilesetCount = 0;
        for (auto pXMLTileset = pXMLMap->FirstChildElement("tileset"); pXMLTileset; pXMLTileset = pXMLTileset->NextSiblingElement("tileset"))
        {
            auto &pTileSet = m_tileSets[m_tilesetCount];

            pTileSet.name = pXMLTileset->Attribute("name");
            pTileSet.firstId = pXMLTileset->IntAttribute("firstgid");
            assert(pTileSet.firstId);
            pTileSet.tileWidth = pXMLTileset->IntAttribute("tilewidth");
            assert(pTileSet.tileWidth);
            pTileSet.tileHeight = pXMLTileset->IntAttribute("tileheight");
            assert(pTileSet.tileHeight);

            auto pXMLImage = pXMLTileset->FirstChildElement("image");
            assert(pXMLImage);
            auto szImageFilename = pXMLImage->Attribute("source");
            assert(szImageFilename);
            auto filename = getPath(map) + "/" + szImageFilename;
            pTileSet.pTexture = pContentManager->getResource<Texture>(filename);

            ++m_tilesetCount;
        }

        // Layers
        for (auto pXMLLayer = pXMLMap->FirstChildElement(); pXMLLayer; pXMLLayer = pXMLLayer->NextSiblingElement())
        {
            if (!strcmp(pXMLLayer->Name(), "layer") ||
                !strcmp(pXMLLayer->Name(), "objectgroup"))
            {
                ++m_layerCount;
            }
        }
        assert(m_layerCount);
        m_layers = new sLayer*[m_layerCount];
        m_layerCount = 0;
        for (auto pXMLLayer = pXMLMap->FirstChildElement(); pXMLLayer; pXMLLayer = pXMLLayer->NextSiblingElement())
        {
            if (!strcmp(pXMLLayer->Name(), "layer"))
            {
                m_layers[m_layerCount] = new sTileLayerInternal();
                auto &pLayer = *(sTileLayerInternal*)m_layers[m_layerCount];

                pLayer.name = pXMLLayer->Attribute("name");
                if (pXMLLayer->Attribute("visible"))
                {
                    pLayer.isVisible = pXMLLayer->BoolAttribute("visible");
                }

                pLayer.width = pXMLLayer->IntAttribute("width");
                assert(pLayer.width);
                pLayer.height = pXMLLayer->IntAttribute("height");
                assert(pLayer.height);
                m_width = std::max<>(m_width, pLayer.width);
                m_height = std::max<>(m_height, pLayer.height);
                auto len = pLayer.width * pLayer.height;
                pLayer.tileIds = new uint32_t[len];

                auto pXMLData = pXMLLayer->FirstChildElement("data");
                assert(pXMLData);
                auto szEncoding = pXMLData->Attribute("encoding");
                auto szCompression = pXMLData->Attribute("compression");

                if (!szEncoding)
                {
                    int i = 0;
                    for (auto pXMLTile = pXMLData->FirstChildElement("tile"); pXMLTile; pXMLTile = pXMLTile->NextSiblingElement("tile"), ++i)
                    {
                        auto id = pXMLTile->IntAttribute("gid");
                        assert(i < len);
                        pLayer.tileIds[i] = id;
                    }
                    assert(i == len);
                }
                else
                {
                    auto szData = pXMLData->GetText();
                    assert(szData);
                    auto pos = std::string(szData).find_first_not_of("\n ");
                    assert(pos < strlen(szData));
                    szData = szData + pos;

                    if (!strcmp(szEncoding, "csv"))
                    {
                        auto csvData = splitString(szData, ',');
                        assert(static_cast<int>(csvData.size()) == len);
                        for (int i = 0; i < len; ++i)
                        {
                            try
                            {
                                pLayer.tileIds[i] = static_cast<uint32_t>(std::stoul(csvData[i]));
                            }
                            catch (std::exception e)
                            {
                                assert(false);
                            }
                        }
                    }
                    else if (!strcmp(szEncoding, "base64"))
                    {
                        auto decoded = base64_decode(szData);
                        if (!szCompression)
                        {
                            assert(static_cast<int>(decoded.size()) == len * 4);
                            memcpy(pLayer.tileIds, decoded.data(), 4 * len);
                        }
                        else if (!strcmp(szCompression, "gzip"))
                        {
                            int err;
                            z_stream d_stream; // decompression stream

                            d_stream.zalloc = (alloc_func)0;
                            d_stream.zfree = (free_func)0;
                            d_stream.opaque = (voidpf)0;

                            d_stream.next_in = reinterpret_cast<Bytef*>(decoded.data()); // where deflated is a pointer the the compressed data buffer
                            d_stream.avail_in = static_cast<uInt>(decoded.size()); // where deflatedLen is the length of the compressed data
                            d_stream.next_out = reinterpret_cast<Bytef*>(pLayer.tileIds); // where inflated is a pointer to the resulting uncompressed data buffer
                            d_stream.avail_out = static_cast<uInt>(len * 4); // where inflatedLen is the size of the uncompressed data buffer

                            err = inflateInit2(&d_stream, 31);
                            assert(err == Z_OK);
                            err = inflate(&d_stream, Z_FINISH);
                            assert(err == Z_STREAM_END);
                            err = inflateEnd(&d_stream);
                            assert(err == Z_OK);
                        }
                        else if (!strcmp(szCompression, "zlib"))
                        {
                            int err;
                            z_stream d_stream; // decompression stream

                            d_stream.zalloc = (alloc_func)0;
                            d_stream.zfree = (free_func)0;
                            d_stream.opaque = (voidpf)0;

                            d_stream.next_in = reinterpret_cast<Bytef*>(decoded.data()); // where deflated is a pointer the the compressed data buffer
                            d_stream.avail_in = static_cast<uInt>(decoded.size()); // where deflatedLen is the length of the compressed data
                            d_stream.next_out = reinterpret_cast<Bytef*>(pLayer.tileIds); // where inflated is a pointer to the resulting uncompressed data buffer
                            d_stream.avail_out = static_cast<uInt>(len * 4); // where inflatedLen is the size of the uncompressed data buffer

                            err = inflateInit2(&d_stream, 15 + 32);
                            assert(err == Z_OK);
                            err = inflate(&d_stream, Z_FINISH);
                            assert(err == Z_STREAM_END);
                            err = inflateEnd(&d_stream);
                            assert(err == Z_OK);
                        }
                    }
                }

                // Resolve the tiles to tilesets
                pLayer.tiles = new sTile[len];
                for (int i = 0; i < len; ++i)
                {
                    auto pTile = pLayer.tiles + i;
                    auto tileId = pLayer.tileIds[i];
                    if (tileId == 0)
                    {
                        continue;
                    }
                    auto pTileSet = m_tileSets;
                    for (int j = 0; j < m_tilesetCount; ++j, pTileSet)
                    {
                        if (pTileSet->firstId > static_cast<int>(tileId)) break;
                    }
                    pTile->pTileset = pTileSet;
                    auto texSize = pTileSet->pTexture->getSize();
                    auto fitW = texSize.x / 40;
                    auto fitH = texSize.y / 40;
                    auto onTextureId = tileId - pTileSet->firstId;
                    pTile->UVs.x = static_cast<float>((onTextureId % fitW) * pTileSet->tileWidth) / static_cast<float>(texSize.x);
                    pTile->UVs.y = static_cast<float>((onTextureId / fitH) * pTileSet->tileHeight) / static_cast<float>(texSize.y);
                    pTile->UVs.z = static_cast<float>((onTextureId % fitW + 1) * pTileSet->tileWidth) / static_cast<float>(texSize.x);
                    pTile->UVs.w = static_cast<float>((onTextureId / fitH + 1) * pTileSet->tileHeight) / static_cast<float>(texSize.y);
                    pTile->rect.x = static_cast<float>((i % pLayer.width) * pTileSet->tileWidth);
                    pTile->rect.y = static_cast<float>((i / pLayer.height) * pTileSet->tileHeight);
                    pTile->rect.z = static_cast<float>(pTileSet->tileWidth);
                    pTile->rect.w = static_cast<float>(pTileSet->tileHeight);
                }

                ++m_layerCount;
            }
            else if (!strcmp(pXMLLayer->Name(), "objectgroup"))
            {
                m_layers[m_layerCount] = new sObjectLayer();
                auto &pLayer = *(sObjectLayer*)m_layers[m_layerCount];

                pLayer.name = pXMLLayer->Attribute("name");
                if (pXMLLayer->Attribute("visible"))
                {
                    pLayer.isVisible = pXMLLayer->BoolAttribute("visible");
                }

                for (auto pXMLObject = pXMLLayer->FirstChildElement("object"); pXMLObject; pXMLObject = pXMLObject->NextSiblingElement("object"))
                {
                    pLayer.objectCount++;
                }
                pLayer.pObjects = new sObject[pLayer.objectCount];
                pLayer.objectCount = 0;
                for (auto pXMLObject = pXMLLayer->FirstChildElement("object"); pXMLObject; pXMLObject = pXMLObject->NextSiblingElement("object"))
                {
                    auto &object = pLayer.pObjects[pLayer.objectCount];
                    pLayer.objectCount++;

                    object.id = pXMLObject->IntAttribute("id");
                    if (pXMLObject->Attribute("name")) object.name = pXMLObject->Attribute("name");
                    if (pXMLObject->Attribute("type")) object.type = pXMLObject->Attribute("type");
                    object.position.x = pXMLObject->FloatAttribute("x");
                    object.position.y = pXMLObject->FloatAttribute("y");
                    object.size.x = pXMLObject->FloatAttribute("width");
                    object.size.y = pXMLObject->FloatAttribute("height");

                    auto pXMLProperties = pXMLObject->FirstChildElement("properties");
                    if (pXMLProperties)
                    {
                        for (auto pXMLProperty = pXMLProperties->FirstChildElement("property"); pXMLProperty; pXMLProperty = pXMLProperty->NextSiblingElement("property"))
                        {
                            if (pXMLProperty->Attribute("name") &&
                                pXMLProperty->Attribute("value"))
                            {
                                object.properties[pXMLProperty->Attribute("name")] = pXMLProperty->Attribute("value");
                            }
                        }
                    }
                }

                ++m_layerCount;
            }
        }

        //TODO: Compile the graphics by batch of 16x16 terrain chunks
    }

    TiledMap::~TiledMap()
    {
        if (m_layers)
        {
            for (auto i = 0; i < m_layerCount; ++i)
            {
                if (m_layers[i]) delete m_layers[i];
            }
            delete[] m_layers;
        }
        if (m_tileSets) delete[] m_tileSets;
    }

    TiledMap::sLayer *TiledMap::getLayer(const std::string &name) const
    {
        for (int i = 0; i < m_layerCount; ++i)
        {
            if (m_layers[i]->name == name) return m_layers[i];
        }
        return nullptr;
    }

    void TiledMap::render(const RECT &rect)
    {
        for (int i = 0; i < m_layerCount; ++i)
        {
            if (!m_layers[i]->isVisible) continue;
            renderLayer(rect, m_layers[i]);
        }
    }

    void TiledMap::renderLayer(const RECT &rect, int index)
    {
        renderLayer(rect, m_layers[index]);
    }

    void TiledMap::renderLayer(const RECT &rect, const std::string &name)
    {
        renderLayer(rect, getLayer(name));
    }

    void TiledMap::renderLayer(const RECT &in_rect, sLayer *in_pLayer)
    {
        auto pLayer = dynamic_cast<sTileLayerInternal*>(in_pLayer);
        if (!pLayer) return;

        RECT rect = in_rect;
        rect.left = std::max<>(0l, rect.left);
        rect.top = std::max<>(0l, rect.top);
        rect.right = std::min<>(static_cast<LONG>(m_width - 1), rect.right);
        rect.bottom = std::min<>(static_cast<LONG>(m_height - 1), rect.bottom);

        egModelPush();
        egModelIdentity();
        egModelMult(&m_transform._11);

        OSB->begin();
        for (LONG y = rect.top; y <= rect.bottom; ++y)
        {
            sTile *pTile = pLayer->tiles + y * m_width + rect.left;
            for (LONG x = rect.left; x <= rect.right; ++x, ++pTile)
            {
                if (!pTile->pTileset) continue;
                OSB->drawRectWithUVs(pTile->pTileset->pTexture, pTile->rect, pTile->UVs);
            }
        }
        OSB->end();

        egModelPop();
    }
};
<|endoftext|>


<commit_before>// Copyright (c) 2019 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#include <tuple>
#include "common.hh"

namespace avl7 {

struct AVLNodeBase;
using BasePtr       = AVLNodeBase*;
using ConstBasePtr  = const AVLNodeBase*;

static constexpr int kHeightMask = 0xff;

struct AVLNodeBase {
  BasePtr parent;
  BasePtr left;
  BasePtr right;
  int height;

  inline int lheight() const noexcept { return left ? left->height : 0; }
  inline int rheight() const noexcept { return right ? right->height : 0; }
  inline void update_height() noexcept { height = Xt::max(lheight(), rheight()) + 1; }

  static inline BasePtr _minimum(BasePtr x) noexcept {
    while (x->left != nullptr)
      x = x->left;
    return x;
  }

  static inline ConstBasePtr _minimum(ConstBasePtr x) noexcept {
    return _minimum(const_cast<BasePtr>(x));
  }

  static inline BasePtr _maximum(BasePtr x) noexcept {
    while (x->right != nullptr)
      x = x->right;
    return x;
  }

  static inline ConstBasePtr _maximum(ConstBasePtr x) noexcept {
    return _maximum(const_cast<BasePtr>(x));
  }
};

inline void __avlnode_replace_child(
    BasePtr x, BasePtr y, BasePtr p, BasePtr& root) noexcept {
  if (p != nullptr) {
    if (root == x)
      root = y;
    else if (p->left == x)
      p->left = y;
    else
      p->right = y;
  }
  else {
    root = y;
  }
}

inline BasePtr avlnode_rotate_left(BasePtr x, BasePtr& root) noexcept {
  //          |                   |
  //          x                   y
  //           \                 / \
  //            y               x   b
  //           / \               \
  //         [a]  b              [a]

  BasePtr y = x->right;
  x->right = y->left;
  if (x->right != nullptr)
    x->right->parent = x;
  y->parent = x->parent;
  __avlnode_replace_child(x, y, x->parent, root);
  y->left = x;
  x->parent = y;
  x->update_height();
  y->update_height();

  return y;
}

inline BasePtr avlnode_rotate_right(BasePtr x, BasePtr& root) noexcept {
  //          |                   |
  //          x                   y
  //         /                   / \
  //        y                   a   x
  //       / \                     /
  //      a  [b]                 [b]

  BasePtr y = x->left;
  x->left = y->right;
  if (x->left != nullptr)
    x->left->parent = x;
  y->parent = x->parent;
  __avlnode_replace_child(x, y, x->parent, root);
  y->right = x;
  x->parent = y;
  x->update_height();
  y->update_height();

  return y;
}

template <typename ValueType> struct AVLNode : public AVLNodeBase {
  ValueType value;
};

struct AVLIterBase {
  BasePtr _node{};

  AVLIterBase() noexcept {}
  AVLIterBase(BasePtr x) noexcept : _node(x) {}
  AVLIterBase(ConstBasePtr x) noexcept : _node(const_cast<BasePtr>(x)) {}

  void increment() noexcept {
    if (_node->right != nullptr) {
      _node = _node->right;
      while (_node->left != nullptr)
        _node = _node->left;
    }
    else {
      BasePtr y = _node->parent;
      while (_node == y->right) {
        _node = y;
        y = y->parent;
      }
      if (_node->right != y)
        _node = y;
    }
  }

  void decrement() noexcept {
    if (_node->height == kHeightMask && _node->parent->parent == _node) {
      _node = _node->right;
    }
    else if (_node->left != nullptr) {
      _node = _node->left;
      while (_node->right != nullptr)
        _node = _node->right;
    }
    else {
      BasePtr y = _node->parent;
      while (_node == y->left) {
        _node = y;
        y = y->parent;
      }
      _node = y;
    }
  }
};

template <typename _Tp, typename _Ref, typename _Ptr>
struct AVLIter : public AVLIterBase {
  using Iter      = AVLIter<_Tp, _Tp&, _Tp*>;
  using Self      = AVLIter<_Tp, _Ref, _Ptr>;
  using Ref       = _Ref;
  using Ptr       = _Ptr;
  using Link      = AVLNode<_Tp>*;
  using ConstLink = const AVLNode<_Tp>*;

  AVLIter() noexcept {}
  AVLIter(BasePtr x) noexcept : AVLIterBase(x) {}
  AVLIter(ConstBasePtr x) noexcept : AVLIterBase(x) {}
  AVLIter(const Iter& x) noexcept : AVLIterBase(x._node) {}

  inline Link node() noexcept { return Link(_node); }
  inline ConstLink node() const noexcept { return ConstLink(_node); }

  inline bool operator==(const Self& r) const noexcept { return _node == r._node; }
  inline bool operator!=(const Self& r) const noexcept { return _node != r._node; }
  inline Ref operator*() const noexcept { return Link(_node)->value; }
  inline Ptr operator->() const noexcept { return &Link(_node)->value; }
  Self& operator++() noexcept { increment(); return *this; }
  Self operator++(int) noexcept { Self tmp(*this); increment(); return tmp; }
  Self& operator--() noexcept { decrement(); return *this; }
  Self operator--(int) noexcept { Self tmp(*this); decrement(); return tmp; }
};

template <typename Tp,
         typename Less = std::less<Tp>, typename Equal = std::equal_to<Tp>>
class AVLTree final : private UnCopyable {
public:
  using ValueType = Tp;
  using SizeType  = std::size_t;
  using Iter      = AVLIter<Tp, Tp&, Tp*>;
  using ConstIter = AVLIter<Tp, const Tp&, const Tp*>;
  using Ref       = Tp&;
  using ConstRef  = const Tp&;
private:
  using Node      = AVLNode<ValueType>;
  using Link      = Node*;
  using ConstLink = const Node*;
  using Alloc     = Xt::SimpleAlloc<Node>;

  SizeType size_{};
  Node head_{};
  Less less_comp_{};
  Equal equal_comp_{};

  inline Link& _root() noexcept { return (Link&)head_.parent; }
  inline ConstLink& _root() const noexcept { return (ConstLink&)head_.parent; }
  inline Link& _tail() noexcept { return (Link&)&head_; }
  inline ConstLink& _tail() const noexcept { return (ConstLink&)&head_; }
  inline Link& _lmost() noexcept { return (Link&)head_.left; }
  inline ConstLink& _lmost() const noexcept { return (ConstLink&)head_.left; }
  inline Link& _rmost() noexcept { return (Link&)head_.right; }
  inline ConstLink& _rmost() const noexcept { return (ConstLink&)head_.right; }

  static inline Link _parent(BasePtr& x) noexcept { return Link(x->parent); }
  static inline ConstLink _parent(ConstBasePtr x) noexcept { return _parent(const_cast<BasePtr>(x)); }
  static inline Link _left(BasePtr x) noexcept { return Link(x->left); }
  static inline ConstLink _left(ConstBasePtr x) noexcept { return _left(const_cast<BasePtr>(x)); }
  static inline Link _right(BasePtr x) noexcept { return Link(x->right); }
  static inline ConstLink _right(ConstBasePtr x) noexcept { return _right(const_cast<BasePtr>(x)); }

  inline Link get_node(const ValueType& x) { return Alloc::allocate(); }
  inline void put_node(Link p) { Alloc::deallocate(p); }

  inline void init() noexcept {
    size_ = 0;
    head_.parent = nullptr;
    head_.left = head_.right = &head_;
    head_.height = kHeightMask;
  }

  Link create_node(const ValueType& x) {
    Link tmp = get_node(x);
    try {
      Xt::construct(&tmp->value, x);
    }
    catch (...) {
      put_node(tmp);
      throw;
    }
    return tmp;
  }

  void destroy_node(Link p) {
    Xt::destroy(&p->value);
    put_node(p);
  }
public:
  AVLTree() noexcept { init(); }
  ~AVLTree() noexcept {}
};

}

void test_avl7() {
  avl7::AVLTree<int> t;
}
<commit_msg>:construction: chore(avl): add insert and erase methods for avl-tree<commit_after>// Copyright (c) 2019 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#include <iostream>
#include <tuple>
#include "common.hh"

namespace avl7 {

struct AVLNodeBase;
using BasePtr       = AVLNodeBase*;
using ConstBasePtr  = const AVLNodeBase*;

static constexpr int kHeightMask = 0xff;

struct AVLNodeBase {
  BasePtr parent;
  BasePtr left;
  BasePtr right;
  int height;

  inline int lheight() const noexcept { return left ? left->height : 0; }
  inline int rheight() const noexcept { return right ? right->height : 0; }
  inline void update_height() noexcept { height = Xt::max(lheight(), rheight()) + 1; }

  static inline BasePtr _minimum(BasePtr x) noexcept {
    while (x->left != nullptr)
      x = x->left;
    return x;
  }

  static inline ConstBasePtr _minimum(ConstBasePtr x) noexcept {
    return _minimum(const_cast<BasePtr>(x));
  }

  static inline BasePtr _maximum(BasePtr x) noexcept {
    while (x->right != nullptr)
      x = x->right;
    return x;
  }

  static inline ConstBasePtr _maximum(ConstBasePtr x) noexcept {
    return _maximum(const_cast<BasePtr>(x));
  }
};

inline void __avlnode_replace_child(
    BasePtr x, BasePtr y, BasePtr p, BasePtr& root) noexcept {
  if (p != nullptr) {
    if (root == x)
      root = y;
    else if (p->left == x)
      p->left = y;
    else
      p->right = y;
  }
  else {
    root = y;
  }
}

inline BasePtr avlnode_rotate_left(BasePtr x, BasePtr& root) noexcept {
  //          |                   |
  //          x                   y
  //           \                 / \
  //            y               x   b
  //           / \               \
  //         [a]  b              [a]

  BasePtr y = x->right;
  x->right = y->left;
  if (x->right != nullptr)
    x->right->parent = x;
  y->parent = x->parent;
  __avlnode_replace_child(x, y, x->parent, root);
  y->left = x;
  x->parent = y;
  x->update_height();
  y->update_height();

  return y;
}

inline BasePtr avlnode_rotate_right(BasePtr x, BasePtr& root) noexcept {
  //          |                   |
  //          x                   y
  //         /                   / \
  //        y                   a   x
  //       / \                     /
  //      a  [b]                 [b]

  BasePtr y = x->left;
  x->left = y->right;
  if (x->left != nullptr)
    x->left->parent = x;
  y->parent = x->parent;
  __avlnode_replace_child(x, y, x->parent, root);
  y->right = x;
  x->parent = y;
  x->update_height();
  y->update_height();

  return y;
}

inline BasePtr avlnode_fix_left(BasePtr a, BasePtr& root) noexcept {
  //          |                   |                   |
  //          a                   a                   c
  //         / \                 / \                 / \
  //       [d]  b              [d]  c               /   \
  //           / \                 / \             a     b
  //          c  [g]              e   b           / \   / \
  //         / \                     / \        [d]  e f  [g]
  //        e   f                   f  [g]

  BasePtr b = a->right;
  if (b->lheight() > b->rheight())
    avlnode_rotate_right(b, root);
  a = avlnode_rotate_left(a, root);

  return a;
}

inline BasePtr avlnode_fix_right(BasePtr a, BasePtr& root) noexcept {
  //          |                   |                   |
  //          a                   a                   c
  //         / \                 / \                 / \
  //        b  [g]              c  [g]              /   \
  //       / \                 / \                 b     a
  //     [d]  c               b   f               / \   / \
  //         / \             / \                [d]  e f  [g]
  //        e   f          [d]  e

  BasePtr b = a->left;
  if (b->lheight() < b->rheight())
    avlnode_rotate_left(b, root);
  a = avlnode_rotate_right(a, root);

  return a;
}

inline void avlnode_rebalance(BasePtr node, BasePtr& root) noexcept {
  while (node != root) {
    int lh = node->lheight();
    int rh = node->rheight();
    int height = Xt::max(lh, rh) + 1;
    int diff = lh - rh;

    if (node->height != height)
      node->height = height;
    else if (diff >= -1 && diff <= 1)
      break;

    if (diff <= -2)
      node = avlnode_fix_left(node, root);
    else if (diff >= 2)
      node = avlnode_fix_right(node, root);

    node = node->parent;
  }
}

inline void avlnode_insert(
    bool insert_left, BasePtr x, BasePtr p, AVLNodeBase& header) noexcept {
  BasePtr& root = header.parent;

  x->parent = p;
  x->left = x->right = nullptr;
  x->height = 0;

  if (insert_left) {
    p->left = x;
    if (p == &header)
      header.parent = header.right = x;
    else if (p == header.left)
      header.left = x;
  }
  else {
    p->right = x;
    if (p == header.right)
      header.right = x;
  }
  avlnode_rebalance(x, root);
}

inline void avlnode_erase(BasePtr x, AVLNodeBase& header) noexcept {
  BasePtr& root = header.parent;
  BasePtr& lmost = header.left;
  BasePtr& rmost = header.right;
  BasePtr orig = x;

  BasePtr p = nullptr;
  BasePtr y = nullptr;
  if (x->left != nullptr && x->right != nullptr) {
    x = x->right;
    while (x->left != nullptr)
      x = x->left;
    y = x->right;
    p = x->parent;
    if (y != nullptr)
      y->parent = p;
    __avlnode_replace_child(x, y, p, root);
    if (x->parent == orig)
      p = x;
    x->parent = orig->parent;
    x->left = orig->left;
    x->right = orig->right;
    x->height = orig->height;
    __avlnode_replace_child(orig, x, x->parent, root);
    if (x->right != nullptr)
      x->right->parent = x;
  }
  else {
    y = x->left != nullptr ? x->left : x->right;
    p = x->parent;
    __avlnode_replace_child(x, y, p, root);
    if (y != nullptr)
      y->parent = p;
  }
  if (p != nullptr)
    avlnode_rebalance(p, root);

  if (root == orig)
    root = y;

  if (lmost == orig || lmost == nullptr)
    lmost = root != nullptr ? AVLNodeBase::_minimum(root) : &header;
  if (rmost == orig || rmost == nullptr)
    rmost = root != nullptr ? AVLNodeBase::_maximum(root) : &header;
}

template <typename ValueType> struct AVLNode : public AVLNodeBase {
  ValueType value;
};

struct AVLIterBase {
  BasePtr _node{};

  AVLIterBase() noexcept {}
  AVLIterBase(BasePtr x) noexcept : _node(x) {}
  AVLIterBase(ConstBasePtr x) noexcept : _node(const_cast<BasePtr>(x)) {}

  void increment() noexcept {
    if (_node->right != nullptr) {
      _node = _node->right;
      while (_node->left != nullptr)
        _node = _node->left;
    }
    else {
      BasePtr y = _node->parent;
      while (_node == y->right) {
        _node = y;
        y = y->parent;
      }
      if (_node->right != y)
        _node = y;
    }
  }

  void decrement() noexcept {
    if (_node->height == kHeightMask && _node->parent->parent == _node) {
      _node = _node->right;
    }
    else if (_node->left != nullptr) {
      _node = _node->left;
      while (_node->right != nullptr)
        _node = _node->right;
    }
    else {
      BasePtr y = _node->parent;
      while (_node == y->left) {
        _node = y;
        y = y->parent;
      }
      _node = y;
    }
  }
};

template <typename _Tp, typename _Ref, typename _Ptr>
struct AVLIter : public AVLIterBase {
  using Iter      = AVLIter<_Tp, _Tp&, _Tp*>;
  using Self      = AVLIter<_Tp, _Ref, _Ptr>;
  using Ref       = _Ref;
  using Ptr       = _Ptr;
  using Link      = AVLNode<_Tp>*;
  using ConstLink = const AVLNode<_Tp>*;

  AVLIter() noexcept {}
  AVLIter(BasePtr x) noexcept : AVLIterBase(x) {}
  AVLIter(ConstBasePtr x) noexcept : AVLIterBase(x) {}
  AVLIter(const Iter& x) noexcept : AVLIterBase(x._node) {}

  inline Link node() noexcept { return Link(_node); }
  inline ConstLink node() const noexcept { return ConstLink(_node); }

  inline bool operator==(const Self& r) const noexcept { return _node == r._node; }
  inline bool operator!=(const Self& r) const noexcept { return _node != r._node; }
  inline Ref operator*() const noexcept { return Link(_node)->value; }
  inline Ptr operator->() const noexcept { return &Link(_node)->value; }
  Self& operator++() noexcept { increment(); return *this; }
  Self operator++(int) noexcept { Self tmp(*this); increment(); return tmp; }
  Self& operator--() noexcept { decrement(); return *this; }
  Self operator--(int) noexcept { Self tmp(*this); decrement(); return tmp; }
};

template <typename Tp,
         typename Less = std::less<Tp>, typename Equal = std::equal_to<Tp>>
class AVLTree final : private UnCopyable {
public:
  using ValueType = Tp;
  using SizeType  = std::size_t;
  using Iter      = AVLIter<Tp, Tp&, Tp*>;
  using ConstIter = AVLIter<Tp, const Tp&, const Tp*>;
  using Ref       = Tp&;
  using ConstRef  = const Tp&;
private:
  using Node      = AVLNode<ValueType>;
  using Link      = Node*;
  using ConstLink = const Node*;
  using Alloc     = Xt::SimpleAlloc<Node>;

  SizeType size_{};
  Node head_{};
  Less less_comp_{};
  Equal equal_comp_{};

  inline Link& _root() noexcept { return (Link&)head_.parent; }
  inline ConstLink& _root() const noexcept { return (ConstLink&)head_.parent; }
  inline Link& _lmost() noexcept { return (Link&)head_.left; }
  inline ConstLink& _lmost() const noexcept { return (ConstLink&)head_.left; }
  inline Link& _rmost() noexcept { return (Link&)head_.right; }
  inline ConstLink& _rmost() const noexcept { return (ConstLink&)head_.right; }

  static inline Link _parent(BasePtr& x) noexcept { return Link(x->parent); }
  static inline ConstLink _parent(ConstBasePtr x) noexcept { return _parent(const_cast<BasePtr>(x)); }
  static inline Link _left(BasePtr x) noexcept { return Link(x->left); }
  static inline ConstLink _left(ConstBasePtr x) noexcept { return _left(const_cast<BasePtr>(x)); }
  static inline Link _right(BasePtr x) noexcept { return Link(x->right); }
  static inline ConstLink _right(ConstBasePtr x) noexcept { return _right(const_cast<BasePtr>(x)); }

  inline Link get_node(const ValueType& x) { return Alloc::allocate(); }
  inline void put_node(Link p) { Alloc::deallocate(p); }

  inline void init() noexcept {
    size_ = 0;
    head_.parent = nullptr;
    head_.left = head_.right = &head_;
    head_.height = kHeightMask;
  }

  Link create_node(const ValueType& x) {
    Link tmp = get_node(x);
    try {
      Xt::construct(&tmp->value, x);
    }
    catch (...) {
      put_node(tmp);
      throw;
    }
    return tmp;
  }

  void destroy_node(Link p) {
    Xt::destroy(&p->value);
    put_node(p);
  }

  inline std::tuple<bool, Link, bool> find_insert_pos(const ValueType& value) {
    Link x = _root();
    Link y = &head_;
    while (x != nullptr) {
      if (equal_comp_(value, x->value))
        return std::make_tuple(false, nullptr, false);

      y = x;
      x = less_comp_(value, x->value) ? _left(x) : _right(x);
    }

    bool insert_left = x != nullptr || y == &head_ || less_comp_(value, y->value);
    return std::make_tuple(true, y, insert_left);
  }

  void insert_aux(const ValueType& value) {
    auto [r, p, insert_left] = find_insert_pos(value);
    if (r) {
      avlnode_insert(insert_left, create_node(value), p, head_);
      ++size_;
    }
  }

  void erase_aux(Link p) {
    if (!empty()) {
      avlnode_erase(p, head_);
      destroy_node(p);
      --size_;
    }
  }
public:
  AVLTree() noexcept { init(); }
  ~AVLTree() noexcept {}

  inline bool empty() const noexcept { return size_ == 0; }
  inline SizeType size() const noexcept { return size_; }
  inline Iter begin() noexcept { return Iter(head_.left); }
  inline ConstIter begin() const noexcept { return ConstIter(head_.left); }
  inline Iter end() noexcept { return Iter(&head_); }
  inline ConstIter end() const noexcept { return ConstIter(&head_); }
  inline Ref get_head() noexcept { return *begin(); }
  inline ConstRef get_head() const noexcept { return *begin(); }
  inline Ref get_tail() noexcept { return *(--end()); }
  inline ConstRef get_tail() const noexcept { return *(--end()); }

  template <typename Function> inline void for_each(Function&& fn) {
    for (auto i = begin(); i != end(); ++i)
      fn(*i);
  }

  void insert(const ValueType& x) { insert_aux(x); }
  void erase(ConstIter pos) { erase_aux(pos.node()); }
};

}

void test_avl7() {
  avl7::AVLTree<int> t;
  auto show_avl = [&t] {
    std::cout << "\navl-tree count is: " << t.size() << std::endl;
    if (!t.empty())
      std::cout << "avl-tree {" << t.get_head() << ", " << t.get_tail() << "}" << std::endl;
    t.for_each([](int value) {
        std::cout << "avl-tree item value is: " << value << std::endl;
        });
  };

  auto show_reverse = [&t] {
    for (auto i = t.end(); i != t.begin();)
      std::cout << "avl-tree reverse item value is: " << *(--i) << std::endl;
  };

  t.insert(34);
  t.insert(67);
  t.insert(56);
  t.insert(45);
  t.insert(23);
  t.insert(13);
  t.insert(3);
  t.insert(7);
  show_avl();
  show_reverse();

  t.erase(t.begin());
  show_avl();
  show_reverse();
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <pistache/net.h>

#include <stdexcept>
#include <iostream>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace Pistache;

TEST(net_test, port_creation)
{
    Port port1(3000);
    ASSERT_FALSE(port1.isReserved());
    uint16_t value1 = port1;
    ASSERT_EQ(value1, 3000);
    ASSERT_EQ(port1.toString(), "3000");

    Port port2(80);
    ASSERT_TRUE(port2.isReserved());
    uint16_t value2 = port2;
    ASSERT_EQ(value2, 80);
    ASSERT_EQ(port2.toString(), "80");
}

TEST(net_test, address_creation)
{
    Address address1("127.0.0.1:8080");
    ASSERT_EQ(address1.host(), "127.0.0.1");
    ASSERT_EQ(address1.family(), AF_INET);
    ASSERT_EQ(address1.port(), 8080);

    std::string addr = "127.0.0.1";
    Address address2(addr, Port(8080));
    ASSERT_EQ(address2.host(), "127.0.0.1");
    ASSERT_EQ(address2.family(), AF_INET);
    ASSERT_EQ(address2.port(), 8080);

    Address address3(Ipv4(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address3.host(), "127.0.0.1");
    ASSERT_EQ(address3.family(), AF_INET);
    ASSERT_EQ(address3.port(), 8080);

    Address address4(Ipv4::any(), Port(8080));
    ASSERT_EQ(address4.host(), "0.0.0.0");
    ASSERT_EQ(address4.family(), AF_INET);
    ASSERT_EQ(address4.port(), 8080);

    Address address5("*:8080");
    ASSERT_EQ(address5.host(), "0.0.0.0");
    ASSERT_EQ(address5.family(), AF_INET);
    ASSERT_EQ(address5.port(), 8080);

    Address address6("[::1]:8080");
    ASSERT_EQ(address6.host(), "::1");
    ASSERT_EQ(address6.family(), AF_INET6);
    ASSERT_EQ(address6.port(), 8080);

    std::string addr2 = "[::1]";
    Address address7(addr2, Port(8080));
    ASSERT_EQ(address7.host(), "::1");
    ASSERT_EQ(address7.family(), AF_INET6);
    ASSERT_EQ(address7.port(), 8080);

    Address address8(Ipv6(0, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address8.host(), "::1");
    ASSERT_EQ(address8.family(), AF_INET6);
    ASSERT_EQ(address8.port(), 8080);

    Address address9(Ipv6::any(true), Port(8080));
    ASSERT_EQ(address9.host(), "::");
    ASSERT_EQ(address9.family(), AF_INET6);
    ASSERT_EQ(address9.port(), 8080);

    Address address10("[::]:8080");
    ASSERT_EQ(address10.host(), "::");
    ASSERT_EQ(address10.family(), AF_INET6);
    ASSERT_EQ(address10.port(), 8080);

    Address address11("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(address11.host(), "2001:db8:aabb:ccdd:eeff:11:2233:4455");
    ASSERT_EQ(address11.family(), AF_INET6);
    ASSERT_EQ(address11.port(), 8080);

    Address address12(Ipv4::loopback(), Port(8080));
    ASSERT_EQ(address12.host(), "127.0.0.1");
    ASSERT_EQ(address12.family(), AF_INET);
    ASSERT_EQ(address12.port(), 8080);

    Address address13(Ipv6::loopback(true), Port(8080));
    ASSERT_EQ(address13.host(), "::1");
    ASSERT_EQ(address13.family(), AF_INET6);
    ASSERT_EQ(address13.port(), 8080);

    Address address14("127.0.0.1");
    ASSERT_EQ(address14.host(), "127.0.0.1");
    ASSERT_EQ(address14.family(), AF_INET);
    ASSERT_EQ(address14.port(), 80);

    Address address15("www.example.com");
    ASSERT_EQ(address15.host(), "93.184.216.34");
    ASSERT_EQ(address15.family(), AF_INET);
    ASSERT_EQ(address15.port(), 80);

    Address address16(IP(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address16.host(), "127.0.0.1");
    ASSERT_EQ(address16.family(), AF_INET);
    ASSERT_EQ(address16.port(), 8080);

    Address address17(IP::any(), Port(8080));
    ASSERT_EQ(address17.host(), "0.0.0.0");
    ASSERT_EQ(address17.family(), AF_INET);
    ASSERT_EQ(address17.port(), 8080);

    Address address18(IP(2, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address18.host(), "2::1");
    ASSERT_EQ(address18.family(), AF_INET6);
    ASSERT_EQ(address18.port(), 8080);

    Address address19(IP::any(true), Port(8080));
    ASSERT_EQ(address19.host(), "::");
    ASSERT_EQ(address19.family(), AF_INET6);
    ASSERT_EQ(address19.port(), 8080);

    Address address20(IP::loopback(true), Port(8080));
    ASSERT_EQ(address20.host(), "::1");
    ASSERT_EQ(address20.family(), AF_INET6);
    ASSERT_EQ(address20.port(), 8080);

    Address address21(IP::loopback(), Port(8080));
    ASSERT_EQ(address21.host(), "127.0.0.1");
    ASSERT_EQ(address21.family(), AF_INET);
    ASSERT_EQ(address21.port(), 8080);

    Address address22("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]");
    ASSERT_EQ(address11.host(), "2001:db8:aabb:ccdd:eeff:11:2233:4455");
    ASSERT_EQ(address11.family(), AF_INET6);
    ASSERT_EQ(address11.port(), 8080);

}

TEST(net_test, invalid_address)
{
    ASSERT_THROW(Address("127.0.0.1:9999999"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:-10"), std::invalid_argument);

    ASSERT_THROW(Address("[GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("[::GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("256.256.256.256:8080");, std::invalid_argument);
    ASSERT_THROW(Address("1.0.0.256:8080");, std::invalid_argument);
}

TEST(net_test, address_parser)
{
    AddressParser ap1("127.0.0.1:80");
    ASSERT_EQ(ap1.rawHost(), "127.0.0.1");
    ASSERT_EQ(ap1.rawPort(), "80");
    ASSERT_EQ(ap1.family(), AF_INET);
    ASSERT_EQ(ap1.hasColon(), true);

    AddressParser ap2("example.com");
    ASSERT_EQ(ap2.rawHost(), "example.com");
    ASSERT_EQ(ap2.rawPort(), "");
    ASSERT_EQ(ap2.family(), AF_INET);
    ASSERT_EQ(ap2.hasColon(), false);

    AddressParser ap3("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(ap3.rawHost(), "[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]");
    ASSERT_EQ(ap3.rawPort(), "8080");
    ASSERT_EQ(ap3.family(), AF_INET6);

    ASSERT_THROW(AddressParser("127.0.0.1:");, std::invalid_argument);
    ASSERT_THROW(AddressParser("[::]:");, std::invalid_argument);
}
<commit_msg>Fixed typo in unit test address22 and added address23<commit_after>#include "gtest/gtest.h"

#include <pistache/net.h>

#include <stdexcept>
#include <iostream>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace Pistache;

TEST(net_test, port_creation)
{
    Port port1(3000);
    ASSERT_FALSE(port1.isReserved());
    uint16_t value1 = port1;
    ASSERT_EQ(value1, 3000);
    ASSERT_EQ(port1.toString(), "3000");

    Port port2(80);
    ASSERT_TRUE(port2.isReserved());
    uint16_t value2 = port2;
    ASSERT_EQ(value2, 80);
    ASSERT_EQ(port2.toString(), "80");
}

TEST(net_test, address_creation)
{
    Address address1("127.0.0.1:8080");
    ASSERT_EQ(address1.host(), "127.0.0.1");
    ASSERT_EQ(address1.family(), AF_INET);
    ASSERT_EQ(address1.port(), 8080);

    std::string addr = "127.0.0.1";
    Address address2(addr, Port(8080));
    ASSERT_EQ(address2.host(), "127.0.0.1");
    ASSERT_EQ(address2.family(), AF_INET);
    ASSERT_EQ(address2.port(), 8080);

    Address address3(Ipv4(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address3.host(), "127.0.0.1");
    ASSERT_EQ(address3.family(), AF_INET);
    ASSERT_EQ(address3.port(), 8080);

    Address address4(Ipv4::any(), Port(8080));
    ASSERT_EQ(address4.host(), "0.0.0.0");
    ASSERT_EQ(address4.family(), AF_INET);
    ASSERT_EQ(address4.port(), 8080);

    Address address5("*:8080");
    ASSERT_EQ(address5.host(), "0.0.0.0");
    ASSERT_EQ(address5.family(), AF_INET);
    ASSERT_EQ(address5.port(), 8080);

    Address address6("[::1]:8080");
    ASSERT_EQ(address6.host(), "::1");
    ASSERT_EQ(address6.family(), AF_INET6);
    ASSERT_EQ(address6.port(), 8080);

    std::string addr2 = "[::1]";
    Address address7(addr2, Port(8080));
    ASSERT_EQ(address7.host(), "::1");
    ASSERT_EQ(address7.family(), AF_INET6);
    ASSERT_EQ(address7.port(), 8080);

    Address address8(Ipv6(0, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address8.host(), "::1");
    ASSERT_EQ(address8.family(), AF_INET6);
    ASSERT_EQ(address8.port(), 8080);

    Address address9(Ipv6::any(true), Port(8080));
    ASSERT_EQ(address9.host(), "::");
    ASSERT_EQ(address9.family(), AF_INET6);
    ASSERT_EQ(address9.port(), 8080);

    Address address10("[::]:8080");
    ASSERT_EQ(address10.host(), "::");
    ASSERT_EQ(address10.family(), AF_INET6);
    ASSERT_EQ(address10.port(), 8080);

    Address address11("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(address11.host(), "2001:db8:aabb:ccdd:eeff:11:2233:4455");
    ASSERT_EQ(address11.family(), AF_INET6);
    ASSERT_EQ(address11.port(), 8080);

    Address address12(Ipv4::loopback(), Port(8080));
    ASSERT_EQ(address12.host(), "127.0.0.1");
    ASSERT_EQ(address12.family(), AF_INET);
    ASSERT_EQ(address12.port(), 8080);

    Address address13(Ipv6::loopback(true), Port(8080));
    ASSERT_EQ(address13.host(), "::1");
    ASSERT_EQ(address13.family(), AF_INET6);
    ASSERT_EQ(address13.port(), 8080);

    Address address14("127.0.0.1");
    ASSERT_EQ(address14.host(), "127.0.0.1");
    ASSERT_EQ(address14.family(), AF_INET);
    ASSERT_EQ(address14.port(), 80);

    Address address15("www.example.com");
    ASSERT_EQ(address15.host(), "93.184.216.34");
    ASSERT_EQ(address15.family(), AF_INET);
    ASSERT_EQ(address15.port(), 80);

    Address address16(IP(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address16.host(), "127.0.0.1");
    ASSERT_EQ(address16.family(), AF_INET);
    ASSERT_EQ(address16.port(), 8080);

    Address address17(IP::any(), Port(8080));
    ASSERT_EQ(address17.host(), "0.0.0.0");
    ASSERT_EQ(address17.family(), AF_INET);
    ASSERT_EQ(address17.port(), 8080);

    Address address18(IP(2, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address18.host(), "2::1");
    ASSERT_EQ(address18.family(), AF_INET6);
    ASSERT_EQ(address18.port(), 8080);

    Address address19(IP::any(true), Port(8080));
    ASSERT_EQ(address19.host(), "::");
    ASSERT_EQ(address19.family(), AF_INET6);
    ASSERT_EQ(address19.port(), 8080);

    Address address20(IP::loopback(true), Port(8080));
    ASSERT_EQ(address20.host(), "::1");
    ASSERT_EQ(address20.family(), AF_INET6);
    ASSERT_EQ(address20.port(), 8080);

    Address address21(IP::loopback(), Port(8080));
    ASSERT_EQ(address21.host(), "127.0.0.1");
    ASSERT_EQ(address21.family(), AF_INET);
    ASSERT_EQ(address21.port(), 8080);

    Address address22("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]");
    ASSERT_EQ(address22.host(), "2001:db8:aabb:ccdd:eeff:11:2233:4455");
    ASSERT_EQ(address22.family(), AF_INET6);
    ASSERT_EQ(address22.port(), 80);

    Address address23("[::]");
    ASSERT_EQ(address23.host(), "::");
    ASSERT_EQ(address23.family(), AF_INET6);
    ASSERT_EQ(address23.port(), 80);

}

TEST(net_test, invalid_address)
{
    ASSERT_THROW(Address("127.0.0.1:9999999"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:-10"), std::invalid_argument);

    ASSERT_THROW(Address("[GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("[::GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("256.256.256.256:8080");, std::invalid_argument);
    ASSERT_THROW(Address("1.0.0.256:8080");, std::invalid_argument);
}

TEST(net_test, address_parser)
{
    AddressParser ap1("127.0.0.1:80");
    ASSERT_EQ(ap1.rawHost(), "127.0.0.1");
    ASSERT_EQ(ap1.rawPort(), "80");
    ASSERT_EQ(ap1.family(), AF_INET);
    ASSERT_EQ(ap1.hasColon(), true);

    AddressParser ap2("example.com");
    ASSERT_EQ(ap2.rawHost(), "example.com");
    ASSERT_EQ(ap2.rawPort(), "");
    ASSERT_EQ(ap2.family(), AF_INET);
    ASSERT_EQ(ap2.hasColon(), false);

    AddressParser ap3("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(ap3.rawHost(), "[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]");
    ASSERT_EQ(ap3.rawPort(), "8080");
    ASSERT_EQ(ap3.family(), AF_INET6);

    ASSERT_THROW(AddressParser("127.0.0.1:");, std::invalid_argument);
    ASSERT_THROW(AddressParser("[::]:");, std::invalid_argument);
}
<|endoftext|>