<commit_before>/*
 * capture.cpp
 *
 *  Created on: 24 juin 2014
 *      Author: Maël Valais
 *
 *	Classe de traitement (contrairement à fenetreprincipale.cpp qui gère l'interface)
 *	gérant :
 *		- la connexion et déconnexion avec la caméra,
 *		- la capture des images avec la caméra,
 *		- le calcul de la position par corrélation.
 *
 *	Les résultats des captures sont envoyées à la classe Guidage (grâce au signal
 *	resultats(...)).
 *
 *	Cette classe gère aussi le diamètre du soleil (on lui envoie les nouveaux diamètres
 *	ou alors elle utilise le calcul du diamètre automatique de diametre_soleil.c)
 *
 *	L'instance de cette classe doit être exécuté dans un thread différent car dans le cas contraire,
 *	l'interface serait bloquée.
 *
 *
 */

#include <QtCore/QSettings>
// Les paramètres sont enregistrés (sous Linux) dans ~/.config/irap/climso-auto.conf

#include "capture.h"
#include "diametre_soleil.h"

/**
 * Paramètres chargés pour la capture (fichier ~/.config/irap/climso-auto.conf sous linux)
 * On peut modifier les paramètres par défaut en modifiant la valeur du
 * second paramètres de value(): value("le-nom-du-parametre",valeurParDéfaut)
 * Certains de ces paramètres sont aussi modifiables depuis le logiciel (menu > paramètres)
 */
void Capture::chargerParametres() {
	QSettings parametres("irap", "climso-auto");
	diametre = parametres.value("diametre-soleil-en-pixel", 275).toInt(); // diamètre du soleil en pixels
	modifierDiametre(diametre);
	emit diametreSoleil(diametre);
}

void Capture::enregistrerParametres() {
	QSettings parametres("irap", "climso-auto");
	parametres.setValue("diametre-soleil-en-pixel", diametre);
}

Capture::Capture() {
	cam = NULL;
	img = NULL;
	ref_lapl = NULL;
	position_c = position_l = 0;
	diametre = 0;
	QObject::connect(&timerProchaineCapture,SIGNAL(timeout()),this,SLOT(captureEtPosition()));
	timerProchaineCapture.setSingleShot(true);
	timerProchaineCapture.setInterval(DUREE_ENTRE_CAPTURES);
	qRegisterMetaType<EtatCamera>("EtatCamera");
	captureEtPosition(); // Lancement de la première capture
}

Capture::~Capture() {
	enregistrerParametres();
	deconnecterCamera();
//	if(cam) delete cam; cam=NULL;
//	if(img) delete img; img=NULL;
//	if(ref_lapl) delete ref_lapl; ref_lapl = NULL;
	cout << "Caméra deconnectée" <<endl;
	// FIXME: Quand on a fait le quit(), les events sont tous traités ?
}

/**
 * Connecte la caméra
 */
void Capture::connecterCamera() {
    PAR_ERROR err;
    if(cam != NULL)
        delete cam;
    cam = new CSBIGCam(DEV_USB); // Creation du device USB
    if ((err = cam->GetError()) != CE_NO_ERROR) {
        emit message("Erreur avec la camera lors de la creation de l'objet camera : "+QString::fromStdString(cam->GetErrorString()));
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    else if ((err=cam->EstablishLink()) != CE_NO_ERROR) { // Connexion à la camera
        emit message("Erreur avec la camera lors de l'etablissement du lien: "+QString::fromStdString(cam->GetErrorString()));
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    else { // Pas d'erreurs, on met en binning 3x3
        cam->SetReadoutMode(RM_3X3);
        cam->SetExposureTime(DUREE_EXPOSITION * 0.001);
        cam->SetFastReadout(true);
        cam->SetABGState((ABG_STATE7)ABG_LOW7);

        emit message("Camera connectee");
        etatCamera = CAMERA_CONNEXION_ON;
    }
    emit envoiEtatCamera(etatCamera);
}

/**
 * Déconnecte la caméra
 */
void Capture::deconnecterCamera() {
    if(cam) {
        cam->CloseDevice();
        emit message("Camera deconnectee");
        delete cam; cam = NULL;
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    else {
        emit message("Aucune camera n'est connectee");
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    emit envoiEtatCamera(etatCamera);
}

/**
 * Vérifie la bonne connexion avec la caméra
 * @return
 */
bool Capture::cameraConnectee() {
    return cam && cam->EstablishLink() == CE_NO_ERROR;
}

/**
 * Méthode appelée régulièrement et permettant de reconnecter
 * la caméra dans le cas d'une déconnexion
 */
void Capture::connexionAuto() {
	if(!cameraConnectee()) {
		etatCamera = CAMERA_CONNEXION_OFF;
		emit stopperGuidage();
		connecterCamera();
	} else {
		etatCamera = CAMERA_CONNEXION_ON;
	}
	emit envoiEtatCamera(etatCamera);
}

/**
 * Conversion d'une Image en QImage pour l'affichage dans la fenêtre principale
 * @param img
 * @return
 */
QImage versQImage(Image* img) {
	unsigned char *img_uchar = img->versUchar();
	// Creation de l'index (34 va donner 34...) car Qt ne gère pas les nuances de gris
	QImage *temp = new QImage(img_uchar, img->getColonnes(), img->getLignes(),img->getColonnes(), QImage::Format_Indexed8);
	for(int i=0;i<256;++i) { // Pour construire une image en nuances de gris (n'existe pas sinon sous Qt)
		temp->setColor(i, qRgb(i,i,i));
	}
	return *temp;
}

/**
 * Etape de capture d'une image et de binning 2x2
 * @return
 */
bool Capture::capturerImage() {
    if (!cameraConnectee()) {
        emit message("La camera n'est pas connectee");
        return false;
    }
    CSBIGImg* img_sbig = new CSBIGImg();
    if(cam->GrabImage(img_sbig, SBDF_LIGHT_ONLY) != CE_NO_ERROR) {
        emit message("Impossible de lire capturer l'image : "+QString::fromStdString(cam->GetErrorString()));
        return false;
    }
    Image* img_temp = Image::depuisSBIGImg(*img_sbig);
    delete img_sbig; // On supprime l'image CSBIGImg

    if(img) delete img; // On supprime la derniere image
    img = img_temp->reduire(2);
    imgPourAffichage = versQImage(img);
	delete img_temp;
	return true;
}

/**
 * Etape de recherche de position
 */
void Capture::trouverPosition() {
	if(img == NULL) {
		return;
	}
	Image *obj_lapl = img->convoluerParDerivee();
	Image *correl = obj_lapl->correlation_rapide_centree(*ref_lapl, SEUIL_CORRELATION);
	correl->maxParInterpolation(&position_l, &position_c);
	signalbruit = correl->calculerSignalSurBruit(position_l,position_c);

#if DEBUG
	img->versTiff(emplacement+"t_obj.tif");
	correl->versTiff(emplacement+"t_correl.tif");
	obj_lapl->versTiff(emplacement+"t_obj_lapl.tif");
#endif

	delete correl;
	delete obj_lapl;
}

QTime t; // pour debug de durée de correl/capture
/**
 * Méthode appelée régulièrement par un timer et lançant
 * la capture puis la recherche de position, et envoyant
 * ensuite le résultat à l'instance de la classe Guidage
 */
void Capture::captureEtPosition() {
	connexionAuto();
	t.start();
	if(capturerImage() && ref_lapl) {
		cout << "Temps ecoulé après capture : " << t.elapsed() << "ms" <<endl;
		trouverPosition();
		cout << "Temps ecoulé après corrélation : " << t.elapsed() << "ms" <<endl;
		// ENVOI DES RESULTATS
		emit resultats(imgPourAffichage,position_l,position_c,diametre,signalbruit);
	}
	timerProchaineCapture.start();
}

/**
 * Slot de modification du diamètre du soleil
 * @param diametre
 */
void Capture::modifierDiametre(int diametre) {
	if(ref_lapl) delete ref_lapl;
	Image *ref = Image::tracerFormeSoleil(diametre);
	ref_lapl = ref->convoluerParDerivee();

#if DEBUG
	ref->versTiff(emplacement+"t_ref.tif");
	ref_lapl->versTiff(emplacement+"t_ref_lapl.tif");
#endif

	delete ref;
	this->diametre = diametre;
}

/**
 * Recherche le meilleur diamètre pour la recherche du centre du soleil,
 * il faut avoir déjà initialisé le diametre car ne recherche qu'autour
 * du diamètre déjà présent (5 pixels autour)
 * @return le diamètre
 */
int Capture::chercherDiametreProche() {
	double signalbruit_max = 0; // On recherche le meilleur signal/bruit possible
	double diametre_optimise;
	Image* ref;
	for(int diam = diametre-5; diam < diametre+5; diam++) {
		ref = Image::tracerFormeSoleil(diam);
		if(ref_lapl) delete ref_lapl;
		ref_lapl = ref->convoluerParDerivee();
		delete ref;
		trouverPosition();
		if(signalbruit > signalbruit_max) {
			signalbruit_max = signalbruit;
			diametre_optimise = diam;
		}
	}
	emit diametreSoleil(diametre_optimise);
	modifierDiametre(diametre_optimise);
	return diametre_optimise;
}
<commit_msg>Correction de la fuite de mémoire présumée<commit_after>/*
 * capture.cpp
 *
 *  Created on: 24 juin 2014
 *      Author: Maël Valais
 *
 *	Classe de traitement (contrairement à fenetreprincipale.cpp qui gère l'interface)
 *	gérant :
 *		- la connexion et déconnexion avec la caméra,
 *		- la capture des images avec la caméra,
 *		- le calcul de la position par corrélation.
 *
 *	Les résultats des captures sont envoyées à la classe Guidage (grâce au signal
 *	resultats(...)).
 *
 *	Cette classe gère aussi le diamètre du soleil (on lui envoie les nouveaux diamètres
 *	ou alors elle utilise le calcul du diamètre automatique de diametre_soleil.c)
 *
 *	L'instance de cette classe doit être exécuté dans un thread différent car dans le cas contraire,
 *	l'interface serait bloquée.
 *
 *
 */

#include <QtCore/QSettings>
// Les paramètres sont enregistrés (sous Linux) dans ~/.config/irap/climso-auto.conf

#include "capture.h"
#include "diametre_soleil.h"

/**
 * Paramètres chargés pour la capture (fichier ~/.config/irap/climso-auto.conf sous linux)
 * On peut modifier les paramètres par défaut en modifiant la valeur du
 * second paramètres de value(): value("le-nom-du-parametre",valeurParDéfaut)
 * Certains de ces paramètres sont aussi modifiables depuis le logiciel (menu > paramètres)
 */
void Capture::chargerParametres() {
	QSettings parametres("irap", "climso-auto");
	diametre = parametres.value("diametre-soleil-en-pixel", 275).toInt(); // diamètre du soleil en pixels
	modifierDiametre(diametre);
	emit diametreSoleil(diametre);
}

void Capture::enregistrerParametres() {
	QSettings parametres("irap", "climso-auto");
	parametres.setValue("diametre-soleil-en-pixel", diametre);
}

Capture::Capture() {
	cam = NULL;
	img = NULL;
	ref_lapl = NULL;
	position_c = position_l = 0;
	diametre = 0;
	QObject::connect(&timerProchaineCapture,SIGNAL(timeout()),this,SLOT(captureEtPosition()));
	timerProchaineCapture.setSingleShot(true);
	timerProchaineCapture.setInterval(DUREE_ENTRE_CAPTURES);
	qRegisterMetaType<EtatCamera>("EtatCamera");
	captureEtPosition(); // Lancement de la première capture
}

Capture::~Capture() {
	enregistrerParametres();
	deconnecterCamera();
//	if(cam) delete cam; cam=NULL;
//	if(img) delete img; img=NULL;
//	if(ref_lapl) delete ref_lapl; ref_lapl = NULL;
	cout << "Caméra deconnectée" <<endl;
	// FIXME: Quand on a fait le quit(), les events sont tous traités ?
}

/**
 * Connecte la caméra
 */
void Capture::connecterCamera() {
    PAR_ERROR err;
    if(cam != NULL)
        delete cam;
    cam = new CSBIGCam(DEV_USB); // Creation du device USB
    if ((err = cam->GetError()) != CE_NO_ERROR) {
        emit message("Erreur avec la camera lors de la creation de l'objet camera : "+QString::fromStdString(cam->GetErrorString()));
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    else if ((err=cam->EstablishLink()) != CE_NO_ERROR) { // Connexion à la camera
        emit message("Erreur avec la camera lors de l'etablissement du lien: "+QString::fromStdString(cam->GetErrorString()));
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    else { // Pas d'erreurs, on met en binning 3x3
        cam->SetReadoutMode(RM_3X3);
        cam->SetExposureTime(DUREE_EXPOSITION * 0.001);
        cam->SetFastReadout(true);
        cam->SetABGState((ABG_STATE7)ABG_LOW7);

        emit message("Camera connectee");
        etatCamera = CAMERA_CONNEXION_ON;
    }
    emit envoiEtatCamera(etatCamera);
}

/**
 * Déconnecte la caméra
 */
void Capture::deconnecterCamera() {
    if(cam) {
        cam->CloseDevice();
        emit message("Camera deconnectee");
        delete cam; cam = NULL;
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    else {
        emit message("Aucune camera n'est connectee");
        etatCamera = CAMERA_CONNEXION_OFF;
    }
    emit envoiEtatCamera(etatCamera);
}

/**
 * Vérifie la bonne connexion avec la caméra
 * @return
 */
bool Capture::cameraConnectee() {
    return cam && cam->EstablishLink() == CE_NO_ERROR;
}

/**
 * Méthode appelée régulièrement et permettant de reconnecter
 * la caméra dans le cas d'une déconnexion
 */
void Capture::connexionAuto() {
	if(!cameraConnectee()) {
		etatCamera = CAMERA_CONNEXION_OFF;
		emit stopperGuidage();
		connecterCamera();
	} else {
		etatCamera = CAMERA_CONNEXION_ON;
	}
	emit envoiEtatCamera(etatCamera);
}

/**
 * Conversion d'une Image en QImage pour l'affichage dans la fenêtre principale
 * cette image est "normalisée".
 * @param img
 * @return
 */
QImage versQImage(Image* img) {
	static unsigned char *img_uchar = NULL;
	if(img_uchar) delete img_uchar;
	img_uchar = img->versUchar();
	// Creation de l'index (34 va donner 34...) car Qt ne gère pas les nuances de gris
	QImage *temp = new QImage(img_uchar, img->getColonnes(), img->getLignes(),img->getColonnes(), QImage::Format_Indexed8);
	for(int i=0;i<256;++i) { // Pour construire une image en nuances de gris (n'existe pas sinon sous Qt)
		temp->setColor(i, qRgb(i,i,i));
	}
	return *temp;
}

/**
 * Etape de capture d'une image et de binning 2x2
 * @return
 */
bool Capture::capturerImage() {
    if (!cameraConnectee()) {
        emit message("La camera n'est pas connectee");
        return false;
    }
    CSBIGImg* img_sbig = new CSBIGImg();
    if(cam->GrabImage(img_sbig, SBDF_LIGHT_ONLY) != CE_NO_ERROR) {
        emit message("Impossible de lire capturer l'image : "+QString::fromStdString(cam->GetErrorString()));
        return false;
    }
    Image* img_temp = Image::depuisSBIGImg(*img_sbig);
    delete img_sbig; // On supprime l'image CSBIGImg

    if(img) delete img; // On supprime la derniere image
    img = img_temp->reduire(2);
    imgPourAffichage = versQImage(img);
	delete img_temp;
	return true;
}

/**
 * Etape de recherche de position
 */
void Capture::trouverPosition() {
	if(img == NULL) {
		return;
	}
	Image *obj_lapl = img->convoluerParDerivee();
	Image *correl = obj_lapl->correlation_rapide_centree(*ref_lapl, SEUIL_CORRELATION);
	correl->maxParInterpolation(&position_l, &position_c);
	signalbruit = correl->calculerSignalSurBruit(position_l,position_c);

#if DEBUG
	img->versTiff(emplacement+"t_obj.tif");
	correl->versTiff(emplacement+"t_correl.tif");
	obj_lapl->versTiff(emplacement+"t_obj_lapl.tif");
#endif

	delete correl;
	delete obj_lapl;
}

QTime t; // pour debug de durée de correl/capture
/**
 * Méthode appelée régulièrement par un timer et lançant
 * la capture puis la recherche de position, et envoyant
 * ensuite le résultat à l'instance de la classe Guidage
 */
void Capture::captureEtPosition() {
	connexionAuto();
	t.start();
	if(capturerImage() && ref_lapl) {
		cout << "Temps ecoulé après capture : " << t.elapsed() << "ms" <<endl;
		trouverPosition();
		cout << "Temps ecoulé après corrélation : " << t.elapsed() << "ms" <<endl;
		// ENVOI DES RESULTATS
		emit resultats(imgPourAffichage,position_l,position_c,diametre,signalbruit);
	}
	timerProchaineCapture.start();
}

/**
 * Slot de modification du diamètre du soleil
 * @param diametre
 */
void Capture::modifierDiametre(int diametre) {
	if(ref_lapl) delete ref_lapl;
	Image *ref = Image::tracerFormeSoleil(diametre);
	ref_lapl = ref->convoluerParDerivee();

#if DEBUG
	ref->versTiff(emplacement+"t_ref.tif");
	ref_lapl->versTiff(emplacement+"t_ref_lapl.tif");
#endif

	delete ref;
	this->diametre = diametre;
}

/**
 * Recherche le meilleur diamètre pour la recherche du centre du soleil,
 * il faut avoir déjà initialisé le diametre car ne recherche qu'autour
 * du diamètre déjà présent (5 pixels autour)
 * @return le diamètre
 */
int Capture::chercherDiametreProche() {
	double signalbruit_max = 0; // On recherche le meilleur signal/bruit possible
	double diametre_optimise;
	Image* ref;
	for(int diam = diametre-5; diam < diametre+5; diam++) {
		ref = Image::tracerFormeSoleil(diam);
		if(ref_lapl) delete ref_lapl;
		ref_lapl = ref->convoluerParDerivee();
		delete ref;
		trouverPosition();
		if(signalbruit > signalbruit_max) {
			signalbruit_max = signalbruit;
			diametre_optimise = diam;
		}
	}
	emit diametreSoleil(diametre_optimise);
	modifierDiametre(diametre_optimise);
	return diametre_optimise;
}
<|endoftext|>


<commit_before>#include <list>

#ifdef DEBUG
#include <iostream>
#endif

#ifndef CPX_INFBOUND
#include <climits>
#define INFBOUND INT_MAX
#else
#define INFBOUND CPX_INFBOUND
#endif

#include "cluster.h"
#include "sense.h"
#include "thread.h"
#include "lockingvars.h"
#include "symgroup.h" // S[n].size()

Cluster::Cluster(int nThreads, int nObj, Sense sense, bool spread_threads,
    int nObjLeft, int * ordering, int ** share_to_, int ** share_from_,
    int ** share_bounds_, int ** share_limit_, std::list<Thread*> & threads,
    Locking_Vars ** locks) {
  if (nThreads == 1) {
    // Build perm
    int * perm = new int[nObj];
    int i;
    for(i = 0; i < nObj; ++i) {
      perm[i] = ordering[i];
    }
#ifdef DEBUG
    std::cout << "Thread " << threads.size() << " using permutation ";
    std::cout << perm[0];
    for(int d = 1; d < nObj; ++d) {
      std::cout << "," << perm[d];
    }
    std::cout << std::endl;
#endif
    // If there is only one objective left to add, then at the previous stage
    // we must've had 2 objectives left, and 2 threads to use (else the Thread
    // object would be constructed there), so this thread would have a partner.
    bool has_partner = (nObjLeft == 1);
    // Build thread
    Thread *t = new Thread(threads.size(), nObj, perm, share_to_, share_from_,
        share_bounds_, share_limit_, locks, has_partner);
    threads.push_back(t);
//    threads.push_back( new Thread(threads.size(), nObj, perm, shared_limits));
  } else {
    int *my_ordering = new int[nObj];
#ifdef DEBUG
    std::cout << "Working with permutation ";
    std::cout << ordering[0];
    for(int d = 1; d < nObj; ++d) {
      std::cout << "," << ordering[d];
    }
    std::cout << " and " << nObjLeft << " objectives left.";
    std::cout << std::endl;
#endif
    for(int i = 0; i < nObj; ++i) {
      my_ordering[i] = ordering[i];
    }
    int ** share_to = new int*[nObj];
    int ** share_from = new int*[nObj];
    int ** share_limit = new int*[nObj];
    int ** share_bounds = new int*[nObj];
    for(int j = 0; j < nObj; ++j) {
      share_to[j] = share_to_[j];
      share_bounds[j] = share_bounds_[j];
      share_from[j] = share_from_[j];
      share_limit[j] = share_limit_[j];
    }
    // Work out how many different objectives will occur
    // in position "nObjLeft - 1"
    int ind = nObjLeft;
    int ** new_shares = new int*[nObj] {nullptr};
    int ** new_bounds = new int*[nObj] {nullptr};
    int ** new_limit = new int*[nObj] {nullptr};
    int num_sub_clusters = (ind < nThreads) ? ind : nThreads;
    for(int j = 0; j < num_sub_clusters; ++j) {
      int pos = my_ordering[nObjLeft - j - 1];
      new_shares[pos] = new int;
      new_bounds[pos] = new int;
      new_limit[pos] = new int;
      if (sense == MIN) {
        *new_shares[pos] = INFBOUND;
        *new_bounds[pos] = -INFBOUND;
        *new_limit[pos] = INFBOUND;
      } else {
        *new_shares[pos] = -INFBOUND;
        *new_bounds[pos] = INFBOUND;
        *new_limit[pos] = -INFBOUND;
      }
    }

    if (spread_threads) {
      // Split up threads
      int perCluster = nThreads / nObjLeft;
      int withExtra = nThreads % nObjLeft;
      int i;
      for(i = 0; i < withExtra ; ++i) {
        int pos = my_ordering[nObjLeft-1];
        locks[pos] = new Locking_Vars(perCluster + 1);
        int * old_share_to = share_to[pos];
        int * old_share_bounds = share_bounds[pos];
        int * old_share_limit = share_limit[pos];
        int ** old_from = new int*[nObj];
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          old_from[obj] = share_from[obj];
        }
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          if (obj == pos) {
            share_to[obj] = new_shares[obj];
            share_bounds[obj] = new_bounds[obj];
            share_limit[obj] = new_limit[obj];
          } else {
            share_from[obj] = new_shares[obj];
          }
        }
        Cluster(perCluster + 1, nObj, sense, spread_threads, nObjLeft - 1,
            my_ordering, share_to, share_from, share_bounds, share_limit, threads, locks);
        share_to[pos] = old_share_to;
        share_bounds[pos] = old_share_bounds;
        share_limit[pos] = old_share_limit;
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          share_from[obj] = old_from[obj];
        }
        // Rotate ordering
        int first = my_ordering[0];
        for (int c = 0; c < nObjLeft-1; ++c) {
          my_ordering[c] = my_ordering[c+1];
        }
        my_ordering[nObjLeft - 1] = first;
        locks[pos] = nullptr;
      }
      if (perCluster > 0) {
        for( ; i < nObjLeft ; ++i) {
          int pos = my_ordering[nObjLeft-1];
          int * old_share_to = share_to[pos];
          int * old_share_bounds = share_bounds[pos];
          int * old_share_limit = share_limit[pos];
          locks[pos] = new Locking_Vars(perCluster);
          int ** old_from = new int*[nObj];
          for(int j = 0; j < nObjLeft; ++j) {
            int obj = my_ordering[j];
            old_from[obj] = share_from[obj];
          }
          for(int j = 0; j < nObjLeft; ++j) {
            int obj = my_ordering[j];
            if (obj == pos) {
              share_to[obj] = new_shares[obj];
              share_bounds[obj] = new_bounds[obj];
              share_limit[obj] = new_limit[obj];
            } else {
              share_from[obj] = new_shares[obj];
            }
          }
          Cluster(perCluster, nObj, sense, spread_threads, nObjLeft - 1,
              my_ordering, share_to, share_from, share_bounds, share_limit, threads, locks);
          share_to[pos] = old_share_to;
          share_bounds[pos] = old_share_bounds;
          share_limit[pos] = old_share_limit;
          for(int j = 0; j < nObjLeft; ++j) {
            int obj = my_ordering[j];
            share_from[obj] = old_from[obj];
          }
          // Rotate ordering
          int first = my_ordering[0];
          for (int c = 0; c < nObjLeft-1; ++c) {
            my_ordering[c] = my_ordering[c+1];
          }
          my_ordering[nObjLeft - 1] = first;
          locks[pos] = nullptr;
        }
      }
    } else { // grouping threads "near" each other
      int threads_remaining = nThreads;
      while (threads_remaining > 0) {
        int threads_to_use = (S[nObjLeft-1].size() > threads_remaining) ? threads_remaining : S[nObjLeft-1].size();
        int pos = my_ordering[nObjLeft-1];
        locks[pos] = new Locking_Vars(threads_to_use);
        int * old_share_to = share_to[pos];
        int * old_share_bounds = share_bounds[pos];
        int * old_share_limit = share_limit[pos];
        int ** old_from = new int*[nObj];
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          old_from[obj] = share_from[obj];
        }
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          if (obj == pos) {
            share_to[obj] = new_shares[obj];
            share_bounds[pos] = new_bounds[obj];
            share_limit[obj] = new_limit[obj];
          } else {
            share_from[obj] = new_shares[obj];
          }
        }
        Cluster(threads_to_use, nObj, sense, spread_threads, nObjLeft - 1,
            my_ordering, share_to, share_from, share_bounds, share_limit, threads, locks);
        threads_remaining -= threads_to_use;
        share_to[pos] = old_share_to;
        share_bounds[pos] = old_share_bounds;
        share_limit[pos] = old_share_limit;
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          share_from[obj] = old_from[obj];
        }
        // Rotate ordering
        int first = my_ordering[0];
        for (int c = 0; c < nObjLeft-1; ++c) {
          my_ordering[c] = my_ordering[c+1];
        }
        my_ordering[nObjLeft - 1] = first;
        locks[pos] = nullptr;
      }
    }
    delete[] my_ordering;
    delete[] new_shares;
    delete[] new_limit;
    delete[] share_to;
    delete[] share_from;
    delete[] share_limit;
    delete[] share_bounds;
  }
}
<commit_msg>Tweak debugging output<commit_after>#include <list>

#ifdef DEBUG
#include <iostream>
#endif

#ifndef CPX_INFBOUND
#include <climits>
#define INFBOUND INT_MAX
#else
#define INFBOUND CPX_INFBOUND
#endif

#include "cluster.h"
#include "sense.h"
#include "thread.h"
#include "lockingvars.h"
#include "symgroup.h" // S[n].size()

Cluster::Cluster(int nThreads, int nObj, Sense sense, bool spread_threads,
    int nObjLeft, int * ordering, int ** share_to_, int ** share_from_,
    int ** share_bounds_, int ** share_limit_, std::list<Thread*> & threads,
    Locking_Vars ** locks) {
  if (nThreads == 1) {
    // Build perm
    int * perm = new int[nObj];
    int i;
    for(i = 0; i < nObj; ++i) {
      perm[i] = ordering[i];
    }
#ifdef DEBUG
    std::cout << "Thread " << threads.size() << " using permutation ";
    std::cout << perm[0];
    for(int d = 1; d < nObj; ++d) {
      std::cout << "," << perm[d];
    }
    std::cout << std::endl;
#endif
    // If there is only one objective left to add, then at the previous stage
    // we must've had 2 objectives left, and 2 threads to use (else the Thread
    // object would be constructed there), so this thread would have a partner.
    bool has_partner = (nObjLeft == 1);
    // Build thread
    Thread *t = new Thread(threads.size(), nObj, perm, share_to_, share_from_,
        share_bounds_, share_limit_, locks, has_partner);
    threads.push_back(t);
//    threads.push_back( new Thread(threads.size(), nObj, perm, shared_limits));
  } else {
    int *my_ordering = new int[nObj];
#ifdef DEBUG
    std::cout << "Working with permutation ";
    std::cout << ordering[0];
    for(int d = 1; d < nObj; ++d) {
      std::cout << "," << ordering[d];
    }
    std::cout << ", " << nThreads << " threads left,";
    std::cout << " and " << nObjLeft << " objectives left.";
    std::cout << std::endl;
#endif
    for(int i = 0; i < nObj; ++i) {
      my_ordering[i] = ordering[i];
    }
    int ** share_to = new int*[nObj];
    int ** share_from = new int*[nObj];
    int ** share_limit = new int*[nObj];
    int ** share_bounds = new int*[nObj];
    for(int j = 0; j < nObj; ++j) {
      share_to[j] = share_to_[j];
      share_bounds[j] = share_bounds_[j];
      share_from[j] = share_from_[j];
      share_limit[j] = share_limit_[j];
    }
    // Work out how many different objectives will occur
    // in position "nObjLeft - 1"
    int ind = nObjLeft;
    int ** new_shares = new int*[nObj] {nullptr};
    int ** new_bounds = new int*[nObj] {nullptr};
    int ** new_limit = new int*[nObj] {nullptr};
    int num_sub_clusters = (ind < nThreads) ? ind : nThreads;
    for(int j = 0; j < num_sub_clusters; ++j) {
      int pos = my_ordering[nObjLeft - j - 1];
      new_shares[pos] = new int;
      new_bounds[pos] = new int;
      new_limit[pos] = new int;
      if (sense == MIN) {
        *new_shares[pos] = INFBOUND;
        *new_bounds[pos] = -INFBOUND;
        *new_limit[pos] = INFBOUND;
      } else {
        *new_shares[pos] = -INFBOUND;
        *new_bounds[pos] = INFBOUND;
        *new_limit[pos] = -INFBOUND;
      }
    }

    if (spread_threads) {
      // Split up threads
      int perCluster = nThreads / nObjLeft;
      int withExtra = nThreads % nObjLeft;
      int i;
      for(i = 0; i < withExtra ; ++i) {
        int pos = my_ordering[nObjLeft-1];
        locks[pos] = new Locking_Vars(perCluster + 1);
        int * old_share_to = share_to[pos];
        int * old_share_bounds = share_bounds[pos];
        int * old_share_limit = share_limit[pos];
        int ** old_from = new int*[nObj];
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          old_from[obj] = share_from[obj];
        }
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          if (obj == pos) {
            share_to[obj] = new_shares[obj];
            share_bounds[obj] = new_bounds[obj];
            share_limit[obj] = new_limit[obj];
          } else {
            share_from[obj] = new_shares[obj];
          }
        }
        Cluster(perCluster + 1, nObj, sense, spread_threads, nObjLeft - 1,
            my_ordering, share_to, share_from, share_bounds, share_limit, threads, locks);
        share_to[pos] = old_share_to;
        share_bounds[pos] = old_share_bounds;
        share_limit[pos] = old_share_limit;
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          share_from[obj] = old_from[obj];
        }
        // Rotate ordering
        int first = my_ordering[0];
        for (int c = 0; c < nObjLeft-1; ++c) {
          my_ordering[c] = my_ordering[c+1];
        }
        my_ordering[nObjLeft - 1] = first;
        locks[pos] = nullptr;
      }
      if (perCluster > 0) {
        for( ; i < nObjLeft ; ++i) {
          int pos = my_ordering[nObjLeft-1];
          int * old_share_to = share_to[pos];
          int * old_share_bounds = share_bounds[pos];
          int * old_share_limit = share_limit[pos];
          locks[pos] = new Locking_Vars(perCluster);
          int ** old_from = new int*[nObj];
          for(int j = 0; j < nObjLeft; ++j) {
            int obj = my_ordering[j];
            old_from[obj] = share_from[obj];
          }
          for(int j = 0; j < nObjLeft; ++j) {
            int obj = my_ordering[j];
            if (obj == pos) {
              share_to[obj] = new_shares[obj];
              share_bounds[obj] = new_bounds[obj];
              share_limit[obj] = new_limit[obj];
            } else {
              share_from[obj] = new_shares[obj];
            }
          }
          Cluster(perCluster, nObj, sense, spread_threads, nObjLeft - 1,
              my_ordering, share_to, share_from, share_bounds, share_limit, threads, locks);
          share_to[pos] = old_share_to;
          share_bounds[pos] = old_share_bounds;
          share_limit[pos] = old_share_limit;
          for(int j = 0; j < nObjLeft; ++j) {
            int obj = my_ordering[j];
            share_from[obj] = old_from[obj];
          }
          // Rotate ordering
          int first = my_ordering[0];
          for (int c = 0; c < nObjLeft-1; ++c) {
            my_ordering[c] = my_ordering[c+1];
          }
          my_ordering[nObjLeft - 1] = first;
          locks[pos] = nullptr;
        }
      }
    } else { // grouping threads "near" each other
      int threads_remaining = nThreads;
      while (threads_remaining > 0) {
        int threads_to_use = (S[nObjLeft-1].size() > threads_remaining) ? threads_remaining : S[nObjLeft-1].size();
        int pos = my_ordering[nObjLeft-1];
        locks[pos] = new Locking_Vars(threads_to_use);
        int * old_share_to = share_to[pos];
        int * old_share_bounds = share_bounds[pos];
        int * old_share_limit = share_limit[pos];
        int ** old_from = new int*[nObj];
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          old_from[obj] = share_from[obj];
        }
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          if (obj == pos) {
            share_to[obj] = new_shares[obj];
            share_bounds[pos] = new_bounds[obj];
            share_limit[obj] = new_limit[obj];
          } else {
            share_from[obj] = new_shares[obj];
          }
        }
        Cluster(threads_to_use, nObj, sense, spread_threads, nObjLeft - 1,
            my_ordering, share_to, share_from, share_bounds, share_limit, threads, locks);
        threads_remaining -= threads_to_use;
        share_to[pos] = old_share_to;
        share_bounds[pos] = old_share_bounds;
        share_limit[pos] = old_share_limit;
        for(int j = 0; j < nObjLeft; ++j) {
          int obj = my_ordering[j];
          share_from[obj] = old_from[obj];
        }
        // Rotate ordering
        int first = my_ordering[0];
        for (int c = 0; c < nObjLeft-1; ++c) {
          my_ordering[c] = my_ordering[c+1];
        }
        my_ordering[nObjLeft - 1] = first;
        locks[pos] = nullptr;
      }
    }
    delete[] my_ordering;
    delete[] new_shares;
    delete[] new_limit;
    delete[] share_to;
    delete[] share_from;
    delete[] share_limit;
    delete[] share_bounds;
  }
}
<|endoftext|>


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

#include <iostream>
#include <stdexcept>

#include "UsbHandler.h"
#include "LibusbDevice.h"

#include "logging.h"

#include <cstring>

namespace tcam
{

UsbHandler& UsbHandler::get_instance ()
{
    static UsbHandler instance;

    return instance;
}

UsbHandler::UsbHandler ():
    session(new UsbSession())
{}

UsbHandler::~UsbHandler()
{}

struct libusb_device_handle* UsbHandler::open_device (const std::string& serial)
{
    struct libusb_device_handle* ret = nullptr;

    libusb_device** devs;

    int cnt = libusb_get_device_list(this->session->get_session(), &devs);

    if (cnt < 0)
    {
        throw std::runtime_error("Unable to retrieve device list. " + std::to_string(cnt));
    }

    for (ssize_t i = 0; i < cnt; i++)
    {
        libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(devs[i], &desc);
        if (r < 0)
        {
            throw std::runtime_error("Unable to retrieve device descriptor. " + std::to_string(cnt));
        }

        // ignore all devices that are not from TIS or otherwise needed
        if (desc.idVendor != 0x199e)
            continue;

        if (desc.idProduct != 0x8209 && desc.idProduct != 0x0804)
            continue;

        r = libusb_open(devs[i], &ret);

        if (r < 0)
        {
            tcam_log(TCAM_LOG_ERROR, "Unable to open device.");
            continue;
        }

        char tmp_str[sizeof(tcam_device_info::serial_number)];

        libusb_get_string_descriptor_ascii(ret, desc.iSerialNumber,
                                           (unsigned char*)tmp_str,
                                           sizeof(tcam_device_info::serial_number));
        if (serial.compare(tmp_str) == 0)
        {

            break;
        }

        libusb_close(ret);

    }

    libusb_free_device_list(devs, 1);

    return ret;
}

std::vector<DeviceInfo> UsbHandler::get_device_list ()
{
    libusb_device** devs;

    int cnt = libusb_get_device_list(this->session->get_session(), &devs);

    if (cnt < 0)
    {
        throw std::runtime_error("Unable to retrieve device list. " + std::to_string(cnt));
    }

    std::vector<DeviceInfo> ret;
    ret.reserve(5);

    for (ssize_t i = 0; i < cnt; i++)
    {
        libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(devs[i], &desc);
        if (r < 0)
        {
            throw std::runtime_error("Unable to retrieve device descriptor. " + std::to_string(cnt));
        }

        // ignore all devices that are not from TIS or otherwise needed
        if (desc.idVendor != 0x199e)
            continue;

        if (desc.idProduct != 0x8209 && desc.idProduct != 0x0804)
            continue;

        tcam_device_info d = { };

        d.type = TCAM_DEVICE_TYPE_LIBUSB;

        // d.idVendor = desc.idVendor;
        // d.idProduct = desc.idProduct;

        // strcpy(d.name, "AFU050");
        // strcpy(d.serial_number, "47614135");
        // strcpy(d.additional_identifier, "9209");

        libusb_device_handle* dh;
        r = libusb_open(devs[i], &dh);

        if (r < 0)
        {
            tcam_log(TCAM_LOG_ERROR, "Unable to open device.");
            continue;
        }

        libusb_get_string_descriptor_ascii(dh, desc.iProduct, (unsigned char*)d.name, sizeof(d.name));

        // libusb_get_string_descriptor_ascii(dh, desc.iManufacturer, (unsigned char*)d.manufacturer, sizeof(d.manufacturer));
        // int lib_ret = libusb_get_port_numbers(dh, (uint8_t*)d.identifier, sizeof(d.identifier))

        libusb_get_string_descriptor_ascii(dh, desc.idProduct, (unsigned char*)d.additional_identifier, sizeof(d.additional_identifier));
        libusb_get_string_descriptor_ascii(dh, desc.iSerialNumber, (unsigned char*)d.serial_number, sizeof(d.serial_number));

        libusb_close(dh);
        ret.push_back(DeviceInfo(d));
    }

    libusb_free_device_list(devs, 1);

    return ret;
}

// std::shared_ptr<UsbCamera> UsbHandler::open_camera (std::string serial_number)
// {
//     auto list = get_device_list();
//     device_info d;

//     for (auto& dev : list)
//     {
//         // std::cout << "Comparing |" << dev.serial << "|" << (unsigned char*)serial_number.c_str() << "|" << std::endl;
//         if (serial_number.compare(dev.serial) == 0)
//         {
//              // std::cout << "dev.serial " << dev.serial << ";serial " << serial_number << std::endl;
//             d = dev;
//             break;
//         }
//     }

//     camera_type t = find_camera_type(d.idVendor, d.idProduct);

//     switch(t.camera_type)
//     {
//         case USB33:
//             return std::make_shared<Usb33Camera>(this->session, d);
//         case USB3:
//             return std::make_shared<Usb3Camera>(this->session, d);
//         case USB2:
//             return std::make_shared<Usb2Camera>(this->session, d);
//         case UNKNOWN:
//         default:
//             return nullptr;
//     }
// }

std::shared_ptr<UsbSession> UsbHandler::get_session ()
{
    return this->session;
}

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

#include <iostream>
#include <stdexcept>

#include "UsbHandler.h"
#include "LibusbDevice.h"

#include "logging.h"

#include <cstring>

namespace tcam
{

UsbHandler& UsbHandler::get_instance ()
{
    static UsbHandler instance;

    return instance;
}

UsbHandler::UsbHandler ():
    session(new UsbSession())
{}

UsbHandler::~UsbHandler()
{}

struct libusb_device_handle* UsbHandler::open_device (const std::string& serial)
{
    struct libusb_device_handle* ret = nullptr;

    libusb_device** devs;

    int cnt = libusb_get_device_list(this->session->get_session(), &devs);

    if (cnt < 0)
    {
        throw std::runtime_error("Unable to retrieve device list. " + std::to_string(cnt));
    }

    for (ssize_t i = 0; i < cnt; i++)
    {
        libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(devs[i], &desc);
        if (r < 0)
        {
            throw std::runtime_error("Unable to retrieve device descriptor. " + std::to_string(cnt));
        }

        // ignore all devices that are not from TIS or otherwise needed
        if (desc.idVendor != 0x199e)
            continue;

        if (desc.idProduct != 0x8209 && desc.idProduct != 0x0804)
            continue;

        r = libusb_open(devs[i], &ret);

        if (r < 0)
        {
            tcam_log(TCAM_LOG_ERROR, "Unable to open device.");
            continue;
        }

        char tmp_str[sizeof(tcam_device_info::serial_number)];

        libusb_get_string_descriptor_ascii(ret, desc.iSerialNumber,
                                           (unsigned char*)tmp_str,
                                           sizeof(tcam_device_info::serial_number));
        if (serial.compare(tmp_str) == 0)
        {

            break;
        }

        libusb_close(ret);

    }

    libusb_free_device_list(devs, 1);

    return ret;
}

std::vector<DeviceInfo> UsbHandler::get_device_list ()
{
    libusb_device** devs;

    int cnt = libusb_get_device_list(this->session->get_session(), &devs);

    if (cnt < 0)
    {
        throw std::runtime_error("Unable to retrieve device list. " + std::to_string(cnt));
    }

    std::vector<DeviceInfo> ret;
    ret.reserve(5);

    for (ssize_t i = 0; i < cnt; i++)
    {
        libusb_device_descriptor desc;
        int r = libusb_get_device_descriptor(devs[i], &desc);
        if (r < 0)
        {
            throw std::runtime_error("Unable to retrieve device descriptor. " + std::to_string(cnt));
        }

        // ignore all devices that are not from TIS or otherwise needed
        if (desc.idVendor != 0x199e)
            continue;

        if (desc.idProduct != 0x8209 && desc.idProduct != 0x0804)
            continue;

        tcam_device_info d = { };

        d.type = TCAM_DEVICE_TYPE_LIBUSB;

        libusb_device_handle* dh;
        r = libusb_open(devs[i], &dh);

        if (r < 0)
        {
            tcam_log(TCAM_LOG_ERROR, "Unable to open device.");
            continue;
        }

        libusb_get_string_descriptor_ascii(dh, desc.iProduct, (unsigned char*)d.name, sizeof(d.name));
        libusb_get_string_descriptor_ascii(dh, desc.idProduct, (unsigned char*)d.additional_identifier, sizeof(d.additional_identifier));
        libusb_get_string_descriptor_ascii(dh, desc.iSerialNumber, (unsigned char*)d.serial_number, sizeof(d.serial_number));

        libusb_close(dh);
        ret.push_back(DeviceInfo(d));
    }

    libusb_free_device_list(devs, 1);

    return ret;
}

std::shared_ptr<UsbSession> UsbHandler::get_session ()
{
    return this->session;
}

}; /* namespace tis */
<|endoftext|>


<commit_before>#include "internal.hpp"
#include "external.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// Compactifying removes holes generated by inactive variables (fixed,
// eliminated or substituted) by mapping active variables indices down to a
// contiguous interval of indices.

/*------------------------------------------------------------------------*/

bool Internal::compactifying () {
  if (!opts.compact) return false;
  if (stats.conflicts < lim.compact) return false;
  int inactive = max_var - active_variables ();
  assert (inactive >= 0);
  if (!inactive) return false;
  return inactive >= opts.compactlim * max_var;
}

/*------------------------------------------------------------------------*/

// Map data in old array 'NAME' to new position as given by 'map'.

#define MAP_ARRAY(TYPE,NAME) \
do { \
  TYPE * TMP = new TYPE [new_vsize]; \
  for (int SRC = 1; SRC <= max_var; SRC++) { \
    const int DST = map[SRC]; \
    if (!DST) continue; \
    TMP[DST] = NAME[SRC]; \
  } \
  memset (TMP, 0, sizeof TMP[0]); \
  delete [] NAME; \
  NAME = TMP; \
} while (0)

/*------------------------------------------------------------------------*/

// Same as 'MAP_ARRAY' but two sided (positive & negative literal).

#define MAP2_ARRAY(TYPE,NAME) \
do { \
  TYPE * TMP = new TYPE [2*new_vsize]; \
  for (int SRC = 1; SRC <= max_var; SRC++) { \
    const int DST = map[SRC]; \
    if (!DST) continue; \
    TMP[2*DST] = NAME[2*SRC]; \
    TMP[2*DST+1] = NAME[2*SRC+1]; \
  } \
  memset (TMP, 0, sizeof TMP[0]); \
  delete [] NAME; \
  NAME = TMP; \
} while (0)

/*------------------------------------------------------------------------*/

// Map a 'vector<int>' of literals, flush inactive literals, resize and
// shrink it to fit its new size after flushing.

#define MAP_AND_FLUSH_INT_VECTOR(V) \
do { \
  const const_int_iterator end = V.end (); \
  int_iterator j = V.begin (); \
  const_int_iterator i; \
  for (i = j; i != end; i++) { \
    const int SRC = *i; \
    int DST = map[abs (SRC)]; \
    if (!DST) continue; \
    if (SRC < 0) DST = -DST; \
    *j++ = DST; \
  } \
  V.resize (j - V.begin ()); \
  shrink_vector (V); \
} while (0)

/*------------------------------------------------------------------------*/

void Internal::compact () {
  START (compact);
  stats.compacts++;

  if (level) backtrack ();

  assert (!conflict);
  assert (clause.empty ());
  assert (levels.empty ());
  assert (analyzed.empty ());
  assert (minimized.empty ());
  assert (control.size () == 1);
  assert (resolved.empty ());

  // We produce a compactifying garbage collector like map of old 'src' to
  // new 'dst' variables.  Inactive variables are just skipped except for
  // fixed ones which will be mapped to the first fixed variable (in the
  // appropriate phase).  This avoids to handle the case 'fixed value'
  // seperately as it is done in Lingeling, where fixed variables are
  // mapped to the internal variable '1'.
  //
  int * map, dst = 0, first_fixed = 0;
  NEW (map, int, max_var + 1);
  map[0] = 0;
  for (int src = 1; src <= max_var; src++) {
    const Flags & f = flags (src);
    if (f.active ()) map[src] = ++dst;
    else if (!f.fixed () || first_fixed) map[src] = 0;
    else map[first_fixed = src] = ++dst;
  }

  if (first_fixed) LOG ("found first fixed %d", first_fixed);
  else LOG ("no variable fixed");

  const int new_max_var = dst;
  const size_t new_vsize = dst + 1;	// Adjust to fit 'new_max_var'.

  /*----------------------------------------------------------------------*/
  // In this first part we only map stuff without reallocation.
  /*----------------------------------------------------------------------*/

  // Flush the external indices.  This has to occur before we map 'vals'.
  {
    const int first_fixed_val = first_fixed ? val (first_fixed) : 0;
    for (int eidx = 1; eidx <= external->max_var; eidx++) {
      const int src = external->e2i[eidx];
      int dst, tmp;
      if (!src) dst = 0;
      else if (!(dst = map[src]) && (tmp = val (src))) {
	assert (first_fixed_val);
	dst = (tmp != first_fixed_val) ? -first_fixed : first_fixed;
      }
      LOG ("external %d mapped to internal %d", eidx, dst);
      external->e2i[eidx] = dst;
    }
  }

  // Map the literals in all clauses.
  {
    const const_clause_iterator end = clauses.end ();
    const_clause_iterator i;
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      assert (!c->garbage);
      const const_literal_iterator eoc = c->end ();
      literal_iterator j;
      for (j = c->begin (); j != eoc; j++) {
	const int lit = *j;
	assert (active (lit));
	int dst = map[abs (lit)];
	if (lit < 0) dst = -dst;
	assert (dst);
	*j = dst;
      }
    }
  }

  // Map the blocking literals in all watches.
  //
  if (watches ()) {
    for (int idx = 1; idx <= max_var; idx++) {
      for (int sign = -1; sign <= 1; sign += 2) {
	const int lit = sign*idx;
	Watches & ws = watches (lit);
	const const_watch_iterator end = ws.end ();
	watch_iterator i;
	for (i = ws.begin (); i != end; i++) {
	  const int blit = i->blit;
	  assert (active (blit));
	  int dst = map[abs (blit)];
	  if (blit < 0) dst = -dst;
	  assert (dst);
	  i->blit = dst;
	}
      }
    }
  }

  // We first flush inactive variables and map the links in the queue.  This
  // has to be done before we map the actual links data structure 'ltab'.
  {
    int prev = 0, mapped_prev = 0, next;
    for (int idx = queue.first; idx; idx = next) {
      Link * l = ltab + idx;
      next = l->next;
      if (idx == first_fixed) continue;
      const int dst = map[idx];
      if (!dst) continue;
      assert (active (idx));
      if (prev) ltab[prev].next = dst; else queue.first = dst;
      l->prev = mapped_prev;
      mapped_prev = dst;
      prev = idx;
    }
    if (prev) ltab[prev].next = 0; else queue.first = 0;
    queue.unassigned = queue.last = mapped_prev;
  }

  /*----------------------------------------------------------------------*/
  // In this second part we not only map stuff but also reallocate memory.
  /*----------------------------------------------------------------------*/

  // Now we continue in reverse order of allocated bytes, e.g., see
  // 'Internal::enlarge' which reallocates in order of allocated bytes.

  MAP_ARRAY (Flags, ftab);
  MAP_ARRAY (signed char, marks);
  MAP_ARRAY (signed char, phases);

  // Special case for 'val' as always since for 'val' we trade branch less
  // code for memory and always allocated an [-maxvar,...,maxvar] array.
  {
    signed char * new_vals = new signed char [2*new_vsize];
    new_vals += new_vsize;
    for (int src = -max_var; src <= -1; src++)
      new_vals[-map[-src]] = vals[src];
    for (int src = 1; src <= max_var; src++)
      new_vals[map[src]] = vals[src];
    new_vals[0] = 0;
    vals -= vsize;
    delete [] vals;
    vals = new_vals;
  }

  MAP_ARRAY (int, i2e);
  MAP2_ARRAY (int, ptab);
  MAP_ARRAY (long, btab);
  if (ntab2) MAP_ARRAY (long, ntab2);
  MAP_ARRAY (Link, ltab);
  MAP_ARRAY (Var, vtab);
  if (ntab) MAP2_ARRAY (long, ntab);
  if (wtab) MAP2_ARRAY (Watches, wtab);
  if (otab) MAP2_ARRAY (Occs, otab);
  if (big) MAP2_ARRAY (Bins, big);

  assert (propagated == trail.size ());
  MAP_AND_FLUSH_INT_VECTOR (trail);
  propagated = trail.size ();

  if (!probes.empty ()) MAP_AND_FLUSH_INT_VECTOR (probes);

  // The simplest way to map the elimination schedule is to get all elements
  // from the heap and reinsert them.  This could be slightly improved in
  // terms of speed if we add a 'flush (int * map)' function to 'Heap', but
  // is pretty complicated and would require that the 'Heap' knows that
  // mapped elements with 'zero' destination should be flushed.  Note that
  // we use stable heap sorting.
  //
  if (!esched.empty ()) {
    vector<int> saved;
    while (!esched.empty ()) {
      const int src = esched.front ();
      esched.pop_front ();
      const int dst = map [src];
      if (dst && src != first_fixed) saved.push_back (dst);
    }
    esched.clear ();
    const const_int_iterator end = saved.end ();
    const_int_iterator i;
    for (i = saved.begin (); i != end; i++)
      esched.push_back (*i);
    esched.shrink ();
  }

  /*----------------------------------------------------------------------*/

  DEL (map, int, max_var);

  VRB ("compact", stats.compacts,
    "reducing internal variables from %d to %d",
    max_var, new_max_var);

  max_var = new_max_var;
  vsize = new_vsize;

  stats.now.fixed = first_fixed ? 1 : 0;
  stats.now.substituted = stats.now.eliminated = 0;

  inc.compact += opts.compactint;
  lim.compact = stats.conflicts + inc.compact;
  report ('c');
  STOP (compact);
}

};
<commit_msg>fixed another compact issue<commit_after>#include "internal.hpp"
#include "external.hpp"
#include "macros.hpp"
#include "message.hpp"

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// Compactifying removes holes generated by inactive variables (fixed,
// eliminated or substituted) by mapping active variables indices down to a
// contiguous interval of indices.

/*------------------------------------------------------------------------*/

bool Internal::compactifying () {
  if (!opts.compact) return false;
  if (stats.conflicts < lim.compact) return false;
  int inactive = max_var - active_variables ();
  assert (inactive >= 0);
  if (!inactive) return false;
  return inactive >= opts.compactlim * max_var;
}

/*------------------------------------------------------------------------*/

// Map data in old array 'NAME' to new position as given by 'map'.

#define MAP_ARRAY(TYPE,NAME) \
do { \
  TYPE * TMP = new TYPE [new_vsize]; \
  for (int SRC = 1; SRC <= max_var; SRC++) { \
    const int DST = map[SRC]; \
    if (!DST) continue; \
    TMP[DST] = NAME[SRC]; \
  } \
  memset (TMP, 0, sizeof TMP[0]); \
  delete [] NAME; \
  NAME = TMP; \
} while (0)

/*------------------------------------------------------------------------*/

// Same as 'MAP_ARRAY' but two sided (positive & negative literal).

#define MAP2_ARRAY(TYPE,NAME) \
do { \
  TYPE * TMP = new TYPE [2*new_vsize]; \
  for (int SRC = 1; SRC <= max_var; SRC++) { \
    const int DST = map[SRC]; \
    if (!DST) continue; \
    TMP[2*DST] = NAME[2*SRC]; \
    TMP[2*DST+1] = NAME[2*SRC+1]; \
  } \
  memset (TMP, 0, sizeof TMP[0]); \
  delete [] NAME; \
  NAME = TMP; \
} while (0)

/*------------------------------------------------------------------------*/

// Map a 'vector<int>' of literals, flush inactive literals, resize and
// shrink it to fit its new size after flushing.

#define MAP_AND_FLUSH_INT_VECTOR(V) \
do { \
  const const_int_iterator end = V.end (); \
  int_iterator j = V.begin (); \
  const_int_iterator i; \
  for (i = j; i != end; i++) { \
    const int SRC = *i; \
    int DST = map[abs (SRC)]; \
    if (!DST) continue; \
    if (SRC < 0) DST = -DST; \
    *j++ = DST; \
  } \
  V.resize (j - V.begin ()); \
  shrink_vector (V); \
} while (0)

/*------------------------------------------------------------------------*/

void Internal::compact () {
  START (compact);
  stats.compacts++;

  if (level) backtrack ();

  assert (!conflict);
  assert (clause.empty ());
  assert (levels.empty ());
  assert (analyzed.empty ());
  assert (minimized.empty ());
  assert (control.size () == 1);
  assert (resolved.empty ());

  // We produce a compactifying garbage collector like map of old 'src' to
  // new 'dst' variables.  Inactive variables are just skipped except for
  // fixed ones which will be mapped to the first fixed variable (in the
  // appropriate phase).  This avoids to handle the case 'fixed value'
  // seperately as it is done in Lingeling, where fixed variables are
  // mapped to the internal variable '1'.
  //
  int * map, dst = 0, first_fixed = 0;
  NEW (map, int, max_var + 1);
  map[0] = 0;
  for (int src = 1; src <= max_var; src++) {
    const Flags & f = flags (src);
    if (f.active ()) map[src] = ++dst;
    else if (!f.fixed () || first_fixed) map[src] = 0;
    else map[first_fixed = src] = ++dst;
  }

  if (first_fixed) LOG ("found first fixed %d", first_fixed);
  else LOG ("no variable fixed");

  const int new_max_var = dst;
  const size_t new_vsize = dst + 1;	// Adjust to fit 'new_max_var'.

  /*----------------------------------------------------------------------*/
  // In this first part we only map stuff without reallocation.
  /*----------------------------------------------------------------------*/

  // Flush the external indices.  This has to occur before we map 'vals'.
  {
    const int first_fixed_val = first_fixed ? val (first_fixed) : 0;
    for (int eidx = 1; eidx <= external->max_var; eidx++) {
      const int src = external->e2i[eidx];
      int dst, tmp;
      if (!src) dst = 0;
      else if (!(dst = map[src]) && (tmp = val (src))) {
	assert (first_fixed_val);
	dst = map[first_fixed];
	if (tmp != first_fixed_val) dst = -dst;
      }
      LOG ("compact %ld maps external %d to internal %d",
        stats.compacts, eidx, dst);
      external->e2i[eidx] = dst;
    }
  }

  // Map the literals in all clauses.
  {
    const const_clause_iterator end = clauses.end ();
    const_clause_iterator i;
    for (i = clauses.begin (); i != end; i++) {
      Clause * c = *i;
      assert (!c->garbage);
      const const_literal_iterator eoc = c->end ();
      literal_iterator j;
      for (j = c->begin (); j != eoc; j++) {
	const int lit = *j;
	assert (active (lit));
	int dst = map[abs (lit)];
	if (lit < 0) dst = -dst;
	assert (dst);
	*j = dst;
      }
    }
  }

  // Map the blocking literals in all watches.
  //
  if (watches ()) {
    for (int idx = 1; idx <= max_var; idx++) {
      for (int sign = -1; sign <= 1; sign += 2) {
	const int lit = sign*idx;
	Watches & ws = watches (lit);
	const const_watch_iterator end = ws.end ();
	watch_iterator i;
	for (i = ws.begin (); i != end; i++) {
	  const int blit = i->blit;
	  assert (active (blit));
	  int dst = map[abs (blit)];
	  if (blit < 0) dst = -dst;
	  assert (dst);
	  i->blit = dst;
	}
      }
    }
  }

  // We first flush inactive variables and map the links in the queue.  This
  // has to be done before we map the actual links data structure 'ltab'.
  {
    int prev = 0, mapped_prev = 0, next;
    for (int idx = queue.first; idx; idx = next) {
      Link * l = ltab + idx;
      next = l->next;
      if (idx == first_fixed) continue;
      const int dst = map[idx];
      if (!dst) continue;
      assert (active (idx));
      if (prev) ltab[prev].next = dst; else queue.first = dst;
      l->prev = mapped_prev;
      mapped_prev = dst;
      prev = idx;
    }
    if (prev) ltab[prev].next = 0; else queue.first = 0;
    queue.unassigned = queue.last = mapped_prev;
  }

  /*----------------------------------------------------------------------*/
  // In this second part we not only map stuff but also reallocate memory.
  /*----------------------------------------------------------------------*/

  // Now we continue in reverse order of allocated bytes, e.g., see
  // 'Internal::enlarge' which reallocates in order of allocated bytes.

  MAP_ARRAY (Flags, ftab);
  MAP_ARRAY (signed char, marks);
  MAP_ARRAY (signed char, phases);

  // Special case for 'val' as always since for 'val' we trade branch less
  // code for memory and always allocated an [-maxvar,...,maxvar] array.
  {
    signed char * new_vals = new signed char [2*new_vsize];
    new_vals += new_vsize;
    for (int src = -max_var; src <= -1; src++)
      new_vals[-map[-src]] = vals[src];
    for (int src = 1; src <= max_var; src++)
      new_vals[map[src]] = vals[src];
    new_vals[0] = 0;
    vals -= vsize;
    delete [] vals;
    vals = new_vals;
  }

  MAP_ARRAY (int, i2e);
  MAP2_ARRAY (int, ptab);
  MAP_ARRAY (long, btab);
  if (ntab2) MAP_ARRAY (long, ntab2);
  MAP_ARRAY (Link, ltab);
  MAP_ARRAY (Var, vtab);
  if (ntab) MAP2_ARRAY (long, ntab);
  if (wtab) MAP2_ARRAY (Watches, wtab);
  if (otab) MAP2_ARRAY (Occs, otab);
  if (big) MAP2_ARRAY (Bins, big);

  assert (propagated == trail.size ());
  MAP_AND_FLUSH_INT_VECTOR (trail);
  propagated = trail.size ();

  if (!probes.empty ()) MAP_AND_FLUSH_INT_VECTOR (probes);

  // The simplest way to map the elimination schedule is to get all elements
  // from the heap and reinsert them.  This could be slightly improved in
  // terms of speed if we add a 'flush (int * map)' function to 'Heap', but
  // is pretty complicated and would require that the 'Heap' knows that
  // mapped elements with 'zero' destination should be flushed.  Note that
  // we use stable heap sorting.
  //
  if (!esched.empty ()) {
    vector<int> saved;
    while (!esched.empty ()) {
      const int src = esched.front ();
      esched.pop_front ();
      const int dst = map [src];
      if (dst && src != first_fixed) saved.push_back (dst);
    }
    esched.clear ();
    const const_int_iterator end = saved.end ();
    const_int_iterator i;
    for (i = saved.begin (); i != end; i++)
      esched.push_back (*i);
    esched.shrink ();
  }

  /*----------------------------------------------------------------------*/

  DEL (map, int, max_var);

  VRB ("compact", stats.compacts,
    "reducing internal variables from %d to %d",
    max_var, new_max_var);

  max_var = new_max_var;
  vsize = new_vsize;

  stats.now.fixed = first_fixed ? 1 : 0;
  stats.now.substituted = stats.now.eliminated = 0;

  inc.compact += opts.compactint;
  lim.compact = stats.conflicts + inc.compact;
  report ('c');
  STOP (compact);
}

};
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

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 "amr_includes.H"

#include "amr_forestclaw.H"
#include "amr_utils.H"
#include "fclaw2d_typedefs.h"
#include "amr_regrid.H"

/* -----------------------------------------------------------------
   Callback routine for tagging
   ----------------------------------------------------------------- */
static
void cb_tag4refinement(fclaw2d_domain_t *domain,
                       fclaw2d_patch_t *this_patch,
                       int this_block_idx,
                       int this_patch_idx,
                       void *user)
{
    const amr_options_t *gparms = get_domain_parms(domain);

    int maxlevel = gparms->maxlevel;
    int level = this_patch->level;

    if (level < maxlevel)
    {
        fclaw2d_regrid_functions_t* rf = get_regrid_functions(domain);

        int initflag = 0;
        fclaw_bool refine_patch =
            (rf->f_patch_tag4refinement)(domain,this_patch,this_block_idx,
                                         this_patch_idx,initflag);
        if (refine_patch)
        {
            fclaw2d_patch_mark_refine(domain, this_block_idx, this_patch_idx);
        }
    }
}

/* Tag family for coarsening */
static
void cb_tag4coarsening(fclaw2d_domain_t *domain,
                       fclaw2d_patch_t *fine_patches,
                       int blockno,
                       int fine0_patchno,
                       void *user)
{
    const amr_options_t *gparms = get_domain_parms(domain);
    int minlevel = gparms->minlevel;

    int level = fine_patches[0].level;

    if (level > minlevel)
    {
        /* --------------------------------------------------------------
           Create temporary patch to hold coarsened data that we will use
           to determine if we need to coarsen data
          ----------------------------------------------------------------- */

        fclaw2d_patch_t *temp_coarse_patch = FCLAW2D_ALLOC(fclaw2d_patch_t,1);
        init_patch_data(temp_coarse_patch);

        temp_coarse_patch->xlower = fine_patches[0].xlower;
        temp_coarse_patch->ylower = fine_patches[0].ylower;
        temp_coarse_patch->xupper = fine_patches[NumSiblings-1].xupper;
        temp_coarse_patch->yupper = fine_patches[NumSiblings-1].yupper;
        temp_coarse_patch->level  = level;
        int coarse_patchno = -1;

        set_clawpatch(domain,temp_coarse_patch,blockno,coarse_patchno);

        // One-time setup of patch
        fclaw2d_solver_functions_t *sf = get_solver_functions(domain);
        (sf->f_patch_setup)(domain,temp_coarse_patch,blockno,coarse_patchno);

        fclaw2d_regrid_functions_t *rf = get_regrid_functions(domain);
        (rf->f_patch_average2coarse)(domain,fine_patches,temp_coarse_patch,
                                     blockno,coarse_patchno, fine0_patchno);

        /* --------------------------------------------------------------
           Test to see if temporary patch needs refining.  If so, then we
           shouldn't coarsen it.
          ----------------------------------------------------------------- */
        fclaw_bool patch_coarsened =
            (rf->f_patch_tag4coarsening)(domain, temp_coarse_patch, blockno,
                                         coarse_patchno);

        delete_clawpatch(domain, temp_coarse_patch);
        delete_patch_data(temp_coarse_patch);
        FCLAW2D_FREE(temp_coarse_patch);

        if (patch_coarsened)
        {
            for (int igrid = 0; igrid < NumSiblings; igrid++)
            {
                int fine_patchno = fine0_patchno + igrid;
                fclaw2d_patch_mark_coarsen(domain, blockno, fine_patchno);
            }
        }
    }
}

static
void cb_domain_adapt(fclaw2d_domain_t * old_domain,
                     fclaw2d_patch_t * old_patch,
                     fclaw2d_domain_t * new_domain,
                     fclaw2d_patch_t * new_patch,
                     fclaw2d_patch_relation_t newsize,
                     int blockno,
                     int old_patchno, int new_patchno,
                     void *user)
{
    if (newsize == FCLAW2D_PATCH_SAMESIZE)
    {
        // Grid doesn't change
        // set_clawpatch(new_domain,new_patch,blockno,new_patchno);

        // Setup new patch using solver specific routine
        // fclaw2d_solver_functions_t *sf = get_solver_functions(old_domain);
        // (sf->f_patch_setup)(new_domain,new_patch,blockno,new_patchno);

        // Need a copy function in regrid_functions
        fclaw2d_regrid_functions_t *rf = get_regrid_functions(old_domain);
        (rf->f_patch_copy2samesize)(new_domain,old_patch,new_patch,blockno,old_patchno,
                                    new_patchno);
    }
    else if (newsize == FCLAW2D_PATCH_HALFSIZE)
    {
        // Old grid is the coarse patch; new grids are the finer patches

        fclaw2d_patch_t *coarse_patch = old_patch;
        int coarse_patchno = old_patchno;

        fclaw2d_patch_t *fine_siblings = new_patch;

        // Loop over four siblings (z-ordering)
        for (int igrid = 0; igrid < NumSiblings; igrid++)
        {
            fclaw2d_patch_t *fine_patch = &fine_siblings[igrid];
            int fine_patchno = new_patchno + igrid;

            // Create new ClawPatch and assign patch pointer to it.
            // set_clawpatch(new_domain, fine_patch, blockno, fine_patchno);

            // Do one-time setup on new patch
            // fclaw2d_solver_functions_t *sf = get_solver_functions(old_domain);
            // (sf->f_patch_setup)(new_domain,fine_patch,blockno,fine_patchno);

            // Initialize new fine patch by either calling an init function or
            // by interpolating from coarser grid.
            fclaw2d_regrid_functions_t *rf = get_regrid_functions(old_domain);
            (rf->f_patch_interpolate2fine)(new_domain,coarse_patch,fine_patch,
                                           blockno,coarse_patchno,fine_patchno,igrid);
        }
    }
    else if (newsize == FCLAW2D_PATCH_DOUBLESIZE)
    {
        // Old grids are the finer grids;  new grid is the coarsened grid
        fclaw2d_patch_t *fine_siblings = old_patch;
        int fine_patchno = old_patchno;

        fclaw2d_patch_t *coarse_patch = new_patch;
        int coarse_patchno = new_patchno;

        // set_clawpatch(new_domain,coarse_patch,blockno,coarse_patchno);

        // fclaw2d_solver_functions_t *sf = get_solver_functions(old_domain);
        // (sf->f_patch_setup)(new_domain,coarse_patch,blockno,coarse_patchno);

        fclaw2d_regrid_functions_t *rf = get_regrid_functions(old_domain);
        (rf->f_patch_average2coarse)(new_domain,fine_siblings,coarse_patch,
                                     blockno,coarse_patchno, fine_patchno);
    }
    else
    {
        printf("cb_adapt_domain : newsize not recognized\n");
        exit(1);
    }
}

void regrid(fclaw2d_domain_t **domain)
{
#if 0
    const amr_options_t *gparms = get_domain_parms(*domain);
    // double t = get_domain_time(*domain);
#endif

    fclaw2d_domain_data_t* ddata = get_domain_data(*domain);
    fclaw2d_timer_start (&ddata->timers[FCLAW2D_TIMER_REGRID]);

    // First determine which families should be coarsened.
    fclaw2d_domain_iterate_families(*domain, cb_tag4coarsening,
                                    (void*) NULL);

    // Then refine.
    fclaw2d_domain_iterate_patches(*domain, cb_tag4refinement,
                                   (void *) NULL);

    // Rebuild domain if necessary
    // Will return be NULL if no refining was done
    fclaw2d_domain_t *new_domain = fclaw2d_domain_adapt(*domain);
    fclaw_bool have_new_refinement = new_domain != NULL;

    // Domain data may go out of scope now.
    ddata = NULL;

    if (have_new_refinement)
    {
        // allocate memory for user patch data and user domain data in the new
        // domain;  copy data from the old to new the domain.
        rebuild_domain(*domain, new_domain);
        // Average to new coarse grids and interpolate to new fine grids
        fclaw2d_domain_iterate_adapted(*domain, new_domain,cb_domain_adapt,
                                       (void *) NULL);

        /* TODO: can we use global min/maxlevels here? */
        /* DAC : I am not sure - The coarse/fine exchanges will
           probably break if passed levels on which there are no
           patches.  This could of course be fixed, but it doesn't
           seem necessary at this point.
        */
        // Do a level exchange to make sure all data is valid;
        // Coarse and fine grid exchanges will happen during time stepping as needed.
#if 0
        /* currently unused */
        minlevel = new_domain->global_minlevel;
        maxlevel = new_domain->global_maxlevel;
#endif

        // free memory associated with old domain
        amrreset(domain);
        *domain = new_domain;
        new_domain = NULL;

        // Repartition for load balancing
        repartition_domain(domain, -1);

        /* Update all ghost patches and ghost cells */
        update_ghost_all_levels (*domain,FCLAW2D_TIMER_REGRID);

        // Print global minimum and maximum levels
        if ((*domain)->mpirank == 0) {
            printf ("Global minlevel %d maxlevel %d\n",
                    (*domain)->global_minlevel, (*domain)->global_maxlevel);
        }
    }

    // Stop timer
    ddata = get_domain_data(*domain);
    fclaw2d_timer_stop (&ddata->timers[FCLAW2D_TIMER_REGRID]);

    // Count calls to this function
    ++ddata->count_amr_regrid;
}
<commit_msg>add brief comment about regridding strategy<commit_after>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

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 "amr_includes.H"

#include "amr_forestclaw.H"
#include "amr_utils.H"
#include "fclaw2d_typedefs.h"
#include "amr_regrid.H"

/* -----------------------------------------------------------------
   Callback routine for tagging
   ----------------------------------------------------------------- */
static
void cb_tag4refinement(fclaw2d_domain_t *domain,
                       fclaw2d_patch_t *this_patch,
                       int this_block_idx,
                       int this_patch_idx,
                       void *user)
{
    const amr_options_t *gparms = get_domain_parms(domain);

    int maxlevel = gparms->maxlevel;
    int level = this_patch->level;

    if (level < maxlevel)
    {
        fclaw2d_regrid_functions_t* rf = get_regrid_functions(domain);

        int initflag = 0;
        fclaw_bool refine_patch =
            (rf->f_patch_tag4refinement)(domain,this_patch,this_block_idx,
                                         this_patch_idx,initflag);
        if (refine_patch)
        {
            fclaw2d_patch_mark_refine(domain, this_block_idx, this_patch_idx);
            /* refine all of the neighbors */
        }
    }
}

/* Tag family for coarsening */
static
void cb_tag4coarsening(fclaw2d_domain_t *domain,
                       fclaw2d_patch_t *fine_patches,
                       int blockno,
                       int fine0_patchno,
                       void *user)
{
    const amr_options_t *gparms = get_domain_parms(domain);
    int minlevel = gparms->minlevel;

    int level = fine_patches[0].level;

    if (level > minlevel)
    {
        /* --------------------------------------------------------------
           Create temporary patch to hold coarsened data that we will use
           to determine if we need to coarsen data
          ----------------------------------------------------------------- */

        fclaw2d_patch_t *temp_coarse_patch = FCLAW2D_ALLOC(fclaw2d_patch_t,1);
        init_patch_data(temp_coarse_patch);

        temp_coarse_patch->xlower = fine_patches[0].xlower;
        temp_coarse_patch->ylower = fine_patches[0].ylower;
        temp_coarse_patch->xupper = fine_patches[NumSiblings-1].xupper;
        temp_coarse_patch->yupper = fine_patches[NumSiblings-1].yupper;
        temp_coarse_patch->level  = level;
        int coarse_patchno = -1;

        set_clawpatch(domain,temp_coarse_patch,blockno,coarse_patchno);

        // One-time setup of patch
        fclaw2d_solver_functions_t *sf = get_solver_functions(domain);
        (sf->f_patch_setup)(domain,temp_coarse_patch,blockno,coarse_patchno);

        fclaw2d_regrid_functions_t *rf = get_regrid_functions(domain);
        (rf->f_patch_average2coarse)(domain,fine_patches,temp_coarse_patch,
                                     blockno,coarse_patchno, fine0_patchno);

        /* --------------------------------------------------------------
           Test to see if temporary patch needs refining.  If so, then we
           shouldn't coarsen it.
          ----------------------------------------------------------------- */
        fclaw_bool patch_coarsened =
            (rf->f_patch_tag4coarsening)(domain, temp_coarse_patch, blockno,
                                         coarse_patchno);

        delete_clawpatch(domain, temp_coarse_patch);
        delete_patch_data(temp_coarse_patch);
        FCLAW2D_FREE(temp_coarse_patch);

        if (patch_coarsened)
        {
            for (int igrid = 0; igrid < NumSiblings; igrid++)
            {
                int fine_patchno = fine0_patchno + igrid;
                fclaw2d_patch_mark_coarsen(domain, blockno, fine_patchno);
            }
        }
    }
}

static
void cb_domain_adapt(fclaw2d_domain_t * old_domain,
                     fclaw2d_patch_t * old_patch,
                     fclaw2d_domain_t * new_domain,
                     fclaw2d_patch_t * new_patch,
                     fclaw2d_patch_relation_t newsize,
                     int blockno,
                     int old_patchno, int new_patchno,
                     void *user)
{
    if (newsize == FCLAW2D_PATCH_SAMESIZE)
    {
        // Grid doesn't change
        // set_clawpatch(new_domain,new_patch,blockno,new_patchno);

        // Setup new patch using solver specific routine
        // fclaw2d_solver_functions_t *sf = get_solver_functions(old_domain);
        // (sf->f_patch_setup)(new_domain,new_patch,blockno,new_patchno);

        // Need a copy function in regrid_functions
        fclaw2d_regrid_functions_t *rf = get_regrid_functions(old_domain);
        (rf->f_patch_copy2samesize)(new_domain,old_patch,new_patch,blockno,old_patchno,
                                    new_patchno);
    }
    else if (newsize == FCLAW2D_PATCH_HALFSIZE)
    {
        // Old grid is the coarse patch; new grids are the finer patches

        fclaw2d_patch_t *coarse_patch = old_patch;
        int coarse_patchno = old_patchno;

        fclaw2d_patch_t *fine_siblings = new_patch;

        // Loop over four siblings (z-ordering)
        for (int igrid = 0; igrid < NumSiblings; igrid++)
        {
            fclaw2d_patch_t *fine_patch = &fine_siblings[igrid];
            int fine_patchno = new_patchno + igrid;

            // Create new ClawPatch and assign patch pointer to it.
            // set_clawpatch(new_domain, fine_patch, blockno, fine_patchno);

            // Do one-time setup on new patch
            // fclaw2d_solver_functions_t *sf = get_solver_functions(old_domain);
            // (sf->f_patch_setup)(new_domain,fine_patch,blockno,fine_patchno);

            // Initialize new fine patch by either calling an init function or
            // by interpolating from coarser grid.
            fclaw2d_regrid_functions_t *rf = get_regrid_functions(old_domain);
            (rf->f_patch_interpolate2fine)(new_domain,coarse_patch,fine_patch,
                                           blockno,coarse_patchno,fine_patchno,igrid);
        }
    }
    else if (newsize == FCLAW2D_PATCH_DOUBLESIZE)
    {
        // Old grids are the finer grids;  new grid is the coarsened grid
        fclaw2d_patch_t *fine_siblings = old_patch;
        int fine_patchno = old_patchno;

        fclaw2d_patch_t *coarse_patch = new_patch;
        int coarse_patchno = new_patchno;

        // set_clawpatch(new_domain,coarse_patch,blockno,coarse_patchno);

        // fclaw2d_solver_functions_t *sf = get_solver_functions(old_domain);
        // (sf->f_patch_setup)(new_domain,coarse_patch,blockno,coarse_patchno);

        fclaw2d_regrid_functions_t *rf = get_regrid_functions(old_domain);
        (rf->f_patch_average2coarse)(new_domain,fine_siblings,coarse_patch,
                                     blockno,coarse_patchno, fine_patchno);
    }
    else
    {
        printf("cb_adapt_domain : newsize not recognized\n");
        exit(1);
    }
}

void regrid(fclaw2d_domain_t **domain)
{
#if 0
    const amr_options_t *gparms = get_domain_parms(*domain);
    // double t = get_domain_time(*domain);
#endif

    fclaw2d_domain_data_t* ddata = get_domain_data(*domain);
    fclaw2d_timer_start (&ddata->timers[FCLAW2D_TIMER_REGRID]);

    // First determine which families should be coarsened.
    fclaw2d_domain_iterate_families(*domain, cb_tag4coarsening,
                                    (void*) NULL);

    // Then refine.
    fclaw2d_domain_iterate_patches(*domain, cb_tag4refinement,
                                   (void *) NULL);

    // Rebuild domain if necessary
    // Will return be NULL if no refining was done
    fclaw2d_domain_t *new_domain = fclaw2d_domain_adapt(*domain);
    fclaw_bool have_new_refinement = new_domain != NULL;

    // Domain data may go out of scope now.
    ddata = NULL;

    if (have_new_refinement)
    {
        // allocate memory for user patch data and user domain data in the new
        // domain;  copy data from the old to new the domain.
        rebuild_domain(*domain, new_domain);
        // Average to new coarse grids and interpolate to new fine grids
        fclaw2d_domain_iterate_adapted(*domain, new_domain,cb_domain_adapt,
                                       (void *) NULL);

        /* TODO: can we use global min/maxlevels here? */
        /* DAC : I am not sure - The coarse/fine exchanges will
           probably break if passed levels on which there are no
           patches.  This could of course be fixed, but it doesn't
           seem necessary at this point.
        */
        // Do a level exchange to make sure all data is valid;
        // Coarse and fine grid exchanges will happen during time stepping as needed.
#if 0
        /* currently unused */
        minlevel = new_domain->global_minlevel;
        maxlevel = new_domain->global_maxlevel;
#endif

        // free memory associated with old domain
        amrreset(domain);
        *domain = new_domain;
        new_domain = NULL;

        // Repartition for load balancing
        repartition_domain(domain, -1);

        /* Update all ghost patches and ghost cells */
        update_ghost_all_levels (*domain,FCLAW2D_TIMER_REGRID);

        // Print global minimum and maximum levels
        if ((*domain)->mpirank == 0) {
            printf ("Global minlevel %d maxlevel %d\n",
                    (*domain)->global_minlevel, (*domain)->global_maxlevel);
        }
    }

    // Stop timer
    ddata = get_domain_data(*domain);
    fclaw2d_timer_stop (&ddata->timers[FCLAW2D_TIMER_REGRID]);

    // Count calls to this function
    ++ddata->count_amr_regrid;
}
<|endoftext|>


<commit_before>#ifndef HEADER_GUARD_CLASS_CONTENTS_H
#define HEADER_GUARD_CLASS_CONTENTS_H

#include <vector>
#include <string>
#include <memory>

#include "change.hh"
#include "mode.hh"

namespace vick {

/*!
 * \file contents.hh
 *
 * \brief Defines the class contents, which contains all the
 * information about the buffer.
 */

/*!
 * \brief Define \c move_t so that code can be more descriptive and
 * can change it from one place.
 */
using move_t = unsigned long;

/*!
 * \brief Define \c move_ts to be a signed version of \c move_t
 *
 * \see move_t
 */
using move_ts = long;

/*!
 * \class contents contents.hh "../../../src/contents.hh"
 *
 * \brief Defines all the information about the buffer.
 */
class contents {
public:
    std::map < char, std::function < boost::optional< std::shared_ptr<change> >
                                     (contents&, boost::optional<int>) > >
        normal_map /*!< \brief The contents buffer (file) specfic
                    * normal mode character mappings. */,
        insert_map /*!< \brief The contents buffer (file) specfic
                    * insert mode character mappings. */;

    /*!
     * \brief The type of file the buffer is.
     *
     * Default mode is fundamental;
     */
    mode* buffer_mode;

    /*!
     * \brief The literal contents of the buffer
     */
    std::vector<std::string> cont;

    /*!
     * \brief The list of changes to the buffer.  This is public so
     * that treed-undo (a la Emacs) can be implemented the same as
     * linear is.
     */
    std::vector<std::shared_ptr<change> > changes;

    /*!
     * \brief The current change the buffer is in
     */
    size_t changes_i = 0;

    move_t
        y = 0 /*!< \brief The y (vertical) position in the buffer. */,
        x = 0 /*!< \brief The x (horizontal) position in the buffer. */,
        desired_x = 0 /*!< \brief This will be set to the x value we
                       * want when you move to a different line but
                       * the line you move to is too short
                       *
                       * \see waiting_for_desired */,
        y_offset = 0 /*!< \brief The number of lines that are not
                      * displayed (off the top) */,
        max_y /*!< \brief The vertical height the buffer has been
               * allocated - [0, max_y) */,
        max_x /*!< \brief The horizontal width the buffer has been
               * allocated - [0, max_x) */;

    bool waiting_for_desired = false /*!< \brief Controls if the x
                                      * value will try to adjust to
                                      * desired_x
                                      *
                                      * \see desired_x */,
         refresh = true /*!< \brief Controls if the screen should
                         * refresh everytime something happens */,
         delete_mode = false /*!< \brief Controls if the private mode
                              * pointer variable will be deleted in the
                              * destructor */,
         is_inserting = false /*!< \brief Will be true if the user is
                               * currently inserting text into the
                               * buffer.  This will cause the
                               * print_contents method to not have
                               * undefined behavior if x is too
                               * large. */,
        windows_file_endings = false /*!< \brief If true, then when
                                      * saving, appends the byte 13 to
                                      * each line.  We use this to
                                      * maintain plugin consistency
                                      * across platforms.  (The buffer
                                      * is in no way affected by this
                                      * variable)
                                      */;

    explicit contents(std::vector<std::string> cont = std::vector<std::string>(),
                      mode* buffer_mode = &fundamental_mode);
    explicit contents(mode* buffer_mode);
    contents(move_t y, move_t x, mode* buffer_mode = &fundamental_mode);

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents(const contents&);
    contents(contents&&) = default;

    /*!
     * \brief If delete_mode is true, then it will delete the private
     * mode pointer member.
     *
     * \see delete_mode
     */
    ~contents();

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents& operator=(const contents&);
    contents& operator=(contents&&);

    bool operator()(char);

    /*!
     * \brief Updates the values of ``max_y`` and ``max_x``
     *
     * \see max_y
     * \see max_x
     */
    void refreshmaxyx();

    /*!
     * \brief Calls ``cont.push_back(str)``
     *
     * \see cont
     *
     * \param str The string to be put at the end of the vector of strings, cont
     */
    void push_back(const std::string& str);
};

}

#endif
<commit_msg>Add documentation to contents::operator()<commit_after>#ifndef HEADER_GUARD_CLASS_CONTENTS_H
#define HEADER_GUARD_CLASS_CONTENTS_H

#include <vector>
#include <string>
#include <memory>

#include "change.hh"
#include "mode.hh"

namespace vick {

/*!
 * \file contents.hh
 *
 * \brief Defines the class contents, which contains all the
 * information about the buffer.
 */

/*!
 * \brief Define \c move_t so that code can be more descriptive and
 * can change it from one place.
 */
using move_t = unsigned long;

/*!
 * \brief Define \c move_ts to be a signed version of \c move_t
 *
 * \see move_t
 */
using move_ts = long;

/*!
 * \class contents contents.hh "../../../src/contents.hh"
 *
 * \brief Defines all the information about the buffer.
 */
class contents {
public:
    std::map < char, std::function < boost::optional< std::shared_ptr<change> >
                                     (contents&, boost::optional<int>) > >
        normal_map /*!< \brief The contents buffer (file) specfic
                    * normal mode character mappings. */,
        insert_map /*!< \brief The contents buffer (file) specfic
                    * insert mode character mappings. */;

    /*!
     * \brief The type of file the buffer is.
     *
     * Default mode is fundamental;
     */
    mode* buffer_mode;

    /*!
     * \brief The literal contents of the buffer
     */
    std::vector<std::string> cont;

    /*!
     * \brief The list of changes to the buffer.  This is public so
     * that treed-undo (a la Emacs) can be implemented the same as
     * linear is.
     */
    std::vector<std::shared_ptr<change> > changes;

    /*!
     * \brief The current change the buffer is in
     */
    size_t changes_i = 0;

    move_t
        y = 0 /*!< \brief The y (vertical) position in the buffer. */,
        x = 0 /*!< \brief The x (horizontal) position in the buffer. */,
        desired_x = 0 /*!< \brief This will be set to the x value we
                       * want when you move to a different line but
                       * the line you move to is too short
                       *
                       * \see waiting_for_desired */,
        y_offset = 0 /*!< \brief The number of lines that are not
                      * displayed (off the top) */,
        max_y /*!< \brief The vertical height the buffer has been
               * allocated - [0, max_y) */,
        max_x /*!< \brief The horizontal width the buffer has been
               * allocated - [0, max_x) */;

    bool waiting_for_desired = false /*!< \brief Controls if the x
                                      * value will try to adjust to
                                      * desired_x
                                      *
                                      * \see desired_x */,
         refresh = true /*!< \brief Controls if the screen should
                         * refresh everytime something happens */,
         delete_mode = false /*!< \brief Controls if the private mode
                              * pointer variable will be deleted in the
                              * destructor */,
         is_inserting = false /*!< \brief Will be true if the user is
                               * currently inserting text into the
                               * buffer.  This will cause the
                               * print_contents method to not have
                               * undefined behavior if x is too
                               * large. */,
        windows_file_endings = false /*!< \brief If true, then when
                                      * saving, appends the byte 13 to
                                      * each line.  We use this to
                                      * maintain plugin consistency
                                      * across platforms.  (The buffer
                                      * is in no way affected by this
                                      * variable)
                                      */;

    explicit contents(std::vector<std::string> cont = std::vector<std::string>(),
                      mode* buffer_mode = &fundamental_mode);
    explicit contents(mode* buffer_mode);
    contents(move_t y, move_t x, mode* buffer_mode = &fundamental_mode);

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents(const contents&);
    contents(contents&&) = default;

    /*!
     * \brief If delete_mode is true, then it will delete the private
     * mode pointer member.
     *
     * \see delete_mode
     */
    ~contents();

    /*!
     * \brief Constructs this contents object as a copy of the other
     * contents object.
     *
     * This forces the private mode member to make a deep copy.
     */
    contents& operator=(const contents&);
    contents& operator=(contents&&);

    /*!
     * \brief Calls the private mode member's `operator()` with
     * `*this` and the character given to this function.
     */
    bool operator()(char);

    /*!
     * \brief Updates the values of ``max_y`` and ``max_x``
     *
     * \see max_y
     * \see max_x
     */
    void refreshmaxyx();

    /*!
     * \brief Calls ``cont.push_back(str)``
     *
     * \see cont
     *
     * \param str The string to be put at the end of the vector of strings, cont
     */
    void push_back(const std::string& str);
};

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "dynamic_string.h"
#include "os.h"
#include "string_stream.h"
#include "temp_allocator.h"
#include "vector.h"
#include <string.h> // strcmp

#if CROWN_PLATFORM_POSIX
	#include <dirent.h> // opendir, readdir
#endif

namespace crown
{
namespace os
{
	void list_files(const char* path, Vector<DynamicString>& files)
	{
#if CROWN_PLATFORM_POSIX
		DIR *dir;
		struct dirent *entry;

		if (!(dir = opendir(path)))
			return;

		while ((entry = readdir(dir)))
		{
			const char* dname = entry->d_name;

			if (!strcmp(dname, ".") || !strcmp(dname, ".."))
				continue;

			TempAllocator512 ta;
			DynamicString fname(ta);
			fname.set(dname, strlen32(dname));
			vector::push_back(files, fname);
		}

		closedir(dir);
#elif CROWN_PLATFORM_WINDOWS
		TempAllocator1024 ta;
		DynamicString cur_path(ta);
		cur_path += path;
		cur_path += "\\*";

		WIN32_FIND_DATA ffd;
		HANDLE file = FindFirstFile(cur_path.c_str(), &ffd);
		if (file == INVALID_HANDLE_VALUE)
			return;

		do
		{
			const char* filename = ffd.cFileName;

			if (!strcmp(fname, ".") || !strcmp(fname, ".."))
				continue;

			TempAllocator512 ta;
			DynamicString fname(ta);
			fname.set(filename, strlen32(filename));
			vector::push_back(files, fname);
		}
		while (FindNextFile(file, &ffd) != 0);

		FindClose(file);
#endif
	}

	int execute_process(const char* path, const char* args, StringStream& output)
	{
#if CROWN_PLATFORM_POSIX
		TempAllocator512 ta;
		DynamicString cmd(ta);
		cmd += path;
		cmd += " 2>&1 ";
		cmd += args;
		FILE* file = popen(cmd.c_str(), "r");

		char buf[1024];
		while (fgets(buf, sizeof(buf), file) != NULL)
			output << buf;

		return pclose(file);
#elif CROWN_PLATFORM_WINDOWS
		STARTUPINFO info;
		memset(&info, 0, sizeof(info));
		info.cb = sizeof(info);

		PROCESS_INFORMATION process;
		memset(&process, 0, sizeof(process));

		int err = CreateProcess(path, (LPSTR)args, NULL, NULL, TRUE, 0, NULL, NULL, &info, &process);
		CE_ASSERT(err != 0, "CreateProcess: GetLastError = %d", GetLastError());
		CE_UNUSED(err);

		DWORD exitcode = 1;
		::WaitForSingleObject(process.hProcess, INFINITE);
  		GetExitCodeProcess(process.hProcess, &exitcode);
		CloseHandle(process.hProcess);
		CloseHandle(process.hThread);
		return (int)exitcode;
#endif
	}
} // namespace os

} // namespace crown
<commit_msg>Fix build<commit_after>/*
 * Copyright (c) 2012-2016 Daniele Bartolini and individual contributors.
 * License: https://github.com/taylor001/crown/blob/master/LICENSE
 */

#include "dynamic_string.h"
#include "os.h"
#include "string_stream.h"
#include "temp_allocator.h"
#include "vector.h"
#include <string.h> // strcmp

#if CROWN_PLATFORM_POSIX
	#include <dirent.h> // opendir, readdir
#endif

namespace crown
{
namespace os
{
	void list_files(const char* path, Vector<DynamicString>& files)
	{
#if CROWN_PLATFORM_POSIX
		DIR *dir;
		struct dirent *entry;

		if (!(dir = opendir(path)))
			return;

		while ((entry = readdir(dir)))
		{
			const char* dname = entry->d_name;

			if (!strcmp(dname, ".") || !strcmp(dname, ".."))
				continue;

			TempAllocator512 ta;
			DynamicString fname(ta);
			fname.set(dname, strlen32(dname));
			vector::push_back(files, fname);
		}

		closedir(dir);
#elif CROWN_PLATFORM_WINDOWS
		TempAllocator1024 ta;
		DynamicString cur_path(ta);
		cur_path += path;
		cur_path += "\\*";

		WIN32_FIND_DATA ffd;
		HANDLE file = FindFirstFile(cur_path.c_str(), &ffd);
		if (file == INVALID_HANDLE_VALUE)
			return;

		do
		{
			const char* dname = ffd.cFileName;

			if (!strcmp(dname, ".") || !strcmp(dname, ".."))
				continue;

			TempAllocator512 ta;
			DynamicString fname(ta);
			fname.set(dname, strlen32(dname));
			vector::push_back(files, fname);
		}
		while (FindNextFile(file, &ffd) != 0);

		FindClose(file);
#endif
	}

	int execute_process(const char* path, const char* args, StringStream& output)
	{
#if CROWN_PLATFORM_POSIX
		TempAllocator512 ta;
		DynamicString cmd(ta);
		cmd += path;
		cmd += " 2>&1 ";
		cmd += args;
		FILE* file = popen(cmd.c_str(), "r");

		char buf[1024];
		while (fgets(buf, sizeof(buf), file) != NULL)
			output << buf;

		return pclose(file);
#elif CROWN_PLATFORM_WINDOWS
		STARTUPINFO info;
		memset(&info, 0, sizeof(info));
		info.cb = sizeof(info);

		PROCESS_INFORMATION process;
		memset(&process, 0, sizeof(process));

		int err = CreateProcess(path, (LPSTR)args, NULL, NULL, TRUE, 0, NULL, NULL, &info, &process);
		CE_ASSERT(err != 0, "CreateProcess: GetLastError = %d", GetLastError());
		CE_UNUSED(err);

		DWORD exitcode = 1;
		::WaitForSingleObject(process.hProcess, INFINITE);
  		GetExitCodeProcess(process.hProcess, &exitcode);
		CloseHandle(process.hProcess);
		CloseHandle(process.hThread);
		return (int)exitcode;
#endif
	}
} // namespace os

} // namespace crown
<|endoftext|>