<commit_before>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cassert>
#include <vector>
#include "arbrecubes.hpp"

/**
 * @file arbreCubes.cpp
 * @author D.Robbes
 * @since 01/05/2015
 * @brief implémentation des méthodes de la classe arbrecubes
 *
**/
#include "arbrecubes.hpp"

using namespace std;

      /**
       * @brief Constructeur, crée un arbre avec les cubes donnés dans un fichier
       * @param nomfic Le nom du fichier texte
       */
arbrecubes::arbrecubes(std::string nomfic)
{   _racine=NULL;
	ifstream fic(nomfic);
	assert(fic.is_open());
	string ligne;
	getline(fic,ligne);
	while(!fic.eof())
	{         cout <<"   "<< "j'ai lu " << ligne << endl;
      stringstream ss(ligne);
      int x,y,largeur;
	   ss >> x >> y >> largeur;
      point P(x,y);
      cube CC(P,largeur);
	  ajouter(CC);         // suppose que l'on peut ajouter même si _racine==NULL
	  getline(fic,ligne);
	}
}

      /**
       * @brief Donne la liste des cubes directement supportés par le paramètre
       * @param CC un cube supposé présent dans l'arbre
       * @return un vecteur de cubes ayant tous CC comme père
       */
vector<cube> arbrecubes::dessus(const cube & CC) const
    {
        // à compléter
        //
        // etape 1 : retrouver le cube

        _noeud * courant = _racine;
        bool trouve = false;
        while(!trouve){

          if(courant->cube == CC)
            trouve = true;

          else{
            point limiteSupG(courant->cube.centre().x - (courant->cube.cote()-1)/2 , courant->cube.centre().y + (courant->cube.cote()-1)/2);
            point limiteInfG(courant->cube.centre().x - (courant->cube.cote()-1)/2 , courant->cube.centre().y - (courant->cube.cote()-1)/2);
            point limiteSupD(courant->cube.centre().x + (courant->cube.cote()-1)/2 , courant->cube.centre().y + (courant->cube.cote()-1)/2);
            point limiteInfD(courant->cube.centre().x + (courant->cube.cote()-1)/2 , courant->cube.centre().y - (courant->cube.cote()-1)/2);
              if(CC.centre()>limiteSupG && CC.centre()>limiteInfG && CC.centre()>limiteSupD && CC.centre()>limiteInfD)
                courant = courant->fils;
              else
                courant = courant->frere;
            }

        }

        //etape 2 : créer le vecteur
        vector<cube> cubes;
        courant = courant->fils ;

        while(courant !=NULL){
			cubes.push_back(courant->bloc);
			courant = courant->frere;
		}
        return cubes;
    }

      /**
       * @brief Donne le cube sur lequel est empilé le paramètre
       * @param CC un cube supposé présent dans l'arbre
       * @return le cube père de CC
       */
const cube soutien(const cube & CC) const
    {
        // à compléter
        if(_racine->cube == CC)
          return CC;
        else{

          _noeud * pere = _racine;
          _noeud * courant = _racine->fils;
          bool trouve = false;
          while(!trouve){

            if(courant->cube == CC)
              trouve = true;

            else{
              int limiteSupY(courant->cube.centre().y + (courant->cube.cote()-1)/2);
              int limiteInfY(courant->cube.centre().y - (courant->cube.cote()-1)/2);
              int limiteSupX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
              int limiteInfX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
                if(CC.centre().y<limiteSupY && CC.centre().y>limiteInfY && CC.centre().x<limiteSupX && CC.centre().x>limiteInfX){
                  pere = courant
                  courant = courant->fils;
                }
                else
                  courant = courant->frere;
              }

          }
          return pere->cube;
      }

    }

      /**
       * @brief ajoute un cube dans l'arbre, à sa place
       * @param CC un cube à ajouter
       *
       * ajoute CC dans la liste des fils du plus petit cube qui peut le supporter
       *    ( dans l'ordre )
       * et prend comme fils tous les cubes qu'il peut supporter
       */
void arbrecubes::ajouter(const cube & CC){
        // à compléter
        _noeud * newneuneu;
        if(_racine == NULL){

			newneuneu->bloc = CC;
			newneuneu->fils = NULL;
			newneuneu->pere = NULL;

			_racine =  newneuneu;
		}
		else{
      bool trouve = false;
      bool sortir = false;

      _noeud * courant = _racine->fils;
      while(courant != NULL && trouve == false && sortir == false){
        if(courant->cube.cote()<CC.cote()){
          courant = courant->frere;
        }
        else{
          point limiteSupG(courant->cube.centre().x - (courant->cube.cote()-1)/2 , courant->cube.centre().y + (courant->cube.cote()-1)/2);
          point limiteInfG(courant->cube.centre().x - (courant->cube.cote()-1)/2 , courant->cube.centre().y - (courant->cube.cote()-1)/2);
          point limiteSupD(courant->cube.centre().x + (courant->cube.cote()-1)/2 , courant->cube.centre().y + (courant->cube.cote()-1)/2);
          point limiteInfD(courant->cube.centre().x + (courant->cube.cote()-1)/2 , courant->cube.centre().y - (courant->cube.cote()-1)/2);

          //fonctionne puisque les cubes sont censé pouvoir supporter la contrainte
          if(CC.centre()>limiteSupG && CC.centre()>limiteInfG && CC.centre()>limiteSupD && CC.centre()>limiteInfD){
              courant->ajouter(CC);
              trouve = true;
          }
          else if(CC.centre()<courant->cube.centre())//REVOIR cette sortie !!!!!!!
            sortir = true;
          else
            courant = courant->frere;

        }
      }

      if(trouve == false){
        newneuneu->bloc = CC;
        newneuneu->fils = _racine->fils; // TOUS les fils ????????????????
        newneuneu->pere = _racine;
      }

		}
}

      /**
       * @brief supprime un cube de l'arbre
       * @param CC un cube supposé présent dans l'arbre (sauf la table)
       *
       * supprime CC de la liste des fils de son père
       * et transmet ses fils à son père
       */
void arbrecubes::supprimer(const cube & CC)
    {
        // à compléter
    }

      /**
       * @brief Donne le cube empilé le plus haut dont la projection au sol contient M
       * @param M un point (du plan)
       * @return un cube tel que M ne soit pas plus loin de centre() que cote()/2
       */
const cube arbrecubes::cubede(const point & M) const
    {
        // à compléter
    }

      /**
       * @brief Donne l'altitude de la face supérieure du cubede(M)
       * @param M un point (du plan)
       * @return une altitude entière (somme des cote() des cubes empilés sous M)
       */
int arbrecubes::hauteur(const point & M) const
    {
        // à compléter
    }
<commit_msg>blblbl<commit_after>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cassert>
#include <vector>
#include "arbrecubes.hpp"

/**
 * @file arbreCubes.cpp
 * @author D.Robbes
 * @since 01/05/2015
 * @brief implémentation des méthodes de la classe arbrecubes
 *
**/
#include "arbrecubes.hpp"

using namespace std;

      /**
       * @brief Constructeur, crée un arbre avec les cubes donnés dans un fichier
       * @param nomfic Le nom du fichier texte
       */
arbrecubes::arbrecubes(std::string nomfic)
{   _racine=NULL;
	ifstream fic(nomfic);
	assert(fic.is_open());
	string ligne;
	getline(fic,ligne);
	while(!fic.eof())
	{         cout <<"   "<< "j'ai lu " << ligne << endl;
      stringstream ss(ligne);
      int x,y,largeur;
	   ss >> x >> y >> largeur;
      point P(x,y);
      cube CC(P,largeur);
	  ajouter(CC);         // suppose que l'on peut ajouter même si _racine==NULL
	  getline(fic,ligne);
	}
}

      /**
       * @brief Donne la liste des cubes directement supportés par le paramètre
       * @param CC un cube supposé présent dans l'arbre
       * @return un vecteur de cubes ayant tous CC comme père
       */
vector<cube> arbrecubes::dessus(const cube & CC) const
    {
        // à compléter
        //
        // etape 1 : retrouver le cube

        _noeud * courant = _racine;
        bool trouve = false;
        while(!trouve){

          if(courant->cube == CC)
            trouve = true;

          else{
            int limiteSupY(courant->cube.centre().y + (courant->cube.cote()-1)/2);
              int limiteInfY(courant->cube.centre().y - (courant->cube.cote()-1)/2);
              int limiteSupX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
              int limiteInfX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
                if(CC.centre().y<limiteSupY && CC.centre().y>limiteInfY && CC.centre().x<limiteSupX && CC.centre().x>limiteInfX)
                courant = courant->fils;
              else
                courant = courant->frere;
            }

        }

        //etape 2 : créer le vecteur
        vector<cube> cubes;
        courant = courant->fils ;

        while(courant !=NULL){
			cubes.push_back(courant->bloc);
			courant = courant->frere;
		}
        return cubes;
    }

      /**
       * @brief Donne le cube sur lequel est empilé le paramètre
       * @param CC un cube supposé présent dans l'arbre
       * @return le cube père de CC
       */
const cube soutien(const cube & CC) const
    {
        // à compléter
        if(_racine->cube == CC)
          return CC;
        else{

          _noeud * pere = _racine;
          _noeud * courant = _racine->fils;
          bool trouve = false;
          while(!trouve){

            if(courant->cube == CC)
              trouve = true;

            else{
              int limiteSupY(courant->cube.centre().y + (courant->cube.cote()-1)/2);
              int limiteInfY(courant->cube.centre().y - (courant->cube.cote()-1)/2);
              int limiteSupX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
              int limiteInfX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
                if(CC.centre().y<limiteSupY && CC.centre().y>limiteInfY && CC.centre().x<limiteSupX && CC.centre().x>limiteInfX){
                  pere = courant
                  courant = courant->fils;
                }
                else
                  courant = courant->frere;
              }

          }
          return pere->cube;
      }

    }

      /**
       * @brief ajoute un cube dans l'arbre, à sa place
       * @param CC un cube à ajouter
       *
       * ajoute CC dans la liste des fils du plus petit cube qui peut le supporter
       *    ( dans l'ordre )
       * et prend comme fils tous les cubes qu'il peut supporter
       */
void arbrecubes::ajouter(const cube & CC){
        // à compléter
        _noeud * newneuneu;
        if(_racine == NULL){

			newneuneu->bloc = CC;
			newneuneu->fils = NULL;
			newneuneu->pere = NULL;

			_racine =  newneuneu;
		}
		else{
      bool trouve = false;
      bool sortir = false;

      _noeud * courant = _racine->fils;
      while(courant != NULL && trouve == false && sortir == false){
        if(courant->cube.cote()<CC.cote()){
          courant = courant->frere;
        }
        else{
          int limiteSupY(courant->cube.centre().y + (courant->cube.cote()-1)/2);
              int limiteInfY(courant->cube.centre().y - (courant->cube.cote()-1)/2);
              int limiteSupX(courant->cube.centre().x + (courant->cube.cote()-1)/2);
              int limiteInfX(courant->cube.centre().x + (courant->cube.cote()-1)/2);

                if(CC.centre().y<limiteSupY && CC.centre().y>limiteInfY && CC.centre().x<limiteSupX && CC.centre().x>limiteInfX){
              courant->ajouter(CC);
              trouve = true;
          }
          else if(CC.centre()<courant->cube.centre())//REVOIR cette sortie !!!!!!!
            sortir = true;
          else
            courant = courant->frere;

        }
      }

      if(trouve == false){
        newneuneu->bloc = CC;
        newneuneu->fils = _racine->fils; // TOUS les fils ????????????????
        newneuneu->pere = _racine;
      }

		}
}

      /**
       * @brief supprime un cube de l'arbre
       * @param CC un cube supposé présent dans l'arbre (sauf la table)
       *
       * supprime CC de la liste des fils de son père
       * et transmet ses fils à son père
       */
void arbrecubes::supprimer(const cube & CC)
    {
        // à compléter
    }

      /**
       * @brief Donne le cube empilé le plus haut dont la projection au sol contient M
       * @param M un point (du plan)
       * @return un cube tel que M ne soit pas plus loin de centre() que cote()/2
       */
const cube arbrecubes::cubede(const point & M) const
    {
        // à compléter
    }

      /**
       * @brief Donne l'altitude de la face supérieure du cubede(M)
       * @param M un point (du plan)
       * @return une altitude entière (somme des cote() des cubes empilés sous M)
       */
int arbrecubes::hauteur(const point & M) const
    {
        // à compléter
    }
<|endoftext|>


<commit_before>// Observable Library
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "obs/signal.h"
#include "test.h"

using namespace obs;

int main() {
  {
    signal<void()> sig;
    int c = 0;
    sig.connect([&](){ ++c; });
    sig.connect([&](){ ++c; });
    sig();
    sig();
    EXPECT_EQ(c, 4);
  }

  {
    signal<int()> sig;
    sig.connect([](){ return 1; });
    sig.connect([](){ return 4; });
    int res = sig();
    EXPECT_EQ(res, 4);
  }

  {
    int a=0, b=0;
    double c=0.0;
    signal<void(int, int, double)> sig;
    sig.connect([&](int x, int y, double z) {
                  a = x;
                  b = y;
                  c = z;
                });
    sig(1, 2, 3.4);
    EXPECT_EQ(1, a);
    EXPECT_EQ(2, b);
    EXPECT_EQ(3.4, c);
  }

  // Alternative signal sintax

  {
    signal0<void> sig;
    int x = 2;
    sig.connect([&x](){ ++x; });
    EXPECT_EQ(x, 2);
    sig();
    EXPECT_EQ(x, 3);
    sig();
    EXPECT_EQ(x, 4);
  }

  {
    signal1<void, int> sig;
    int x = 2;
    sig.connect([&x](int y){ x += y; });
    sig(3);
    sig(4);
    EXPECT_EQ(x, 9);
  }

  {
    signal2<void, int, int> sig;
    int c = 0;
    sig.connect([&](int x, int y){ c = x+y; });
    sig(3, 4);
    EXPECT_EQ(c, 7);
  }
}
<commit_msg>Add tests for signal<> with member functions<commit_after>// Observable Library
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "obs/signal.h"
#include "test.h"

using namespace obs;

struct Entity {
  int a;
  Entity() : a(0) { }
  void set_a(int v) { a = v; }
  int set_a_return_old(int v) {
    int old = a;
    a = v;
    return old;
  }
};

int main() {
  {
    signal<void()> sig;
    int c = 0;
    sig.connect([&](){ ++c; });
    sig.connect([&](){ ++c; });
    sig();
    sig();
    EXPECT_EQ(c, 4);
  }

  {
    signal<int()> sig;
    sig.connect([](){ return 1; });
    sig.connect([](){ return 4; });
    int res = sig();
    EXPECT_EQ(res, 4);
  }

  {
    int a=0, b=0;
    double c=0.0;
    signal<void(int, int, double)> sig;
    sig.connect([&](int x, int y, double z) {
                  a = x;
                  b = y;
                  c = z;
                });
    sig(1, 2, 3.4);
    EXPECT_EQ(1, a);
    EXPECT_EQ(2, b);
    EXPECT_EQ(3.4, c);
  }

  {
    signal<void(int)> sig;
    Entity ent;
    sig.connect(&Entity::set_a, &ent);
    EXPECT_EQ(ent.a, 0);
    sig(32);
    EXPECT_EQ(ent.a, 32);
  }

  {
    signal<int(int)> sig;
    Entity ent;
    sig.connect(&Entity::set_a_return_old, &ent);
    ent.a = 2;
    EXPECT_EQ(ent.a, 2);
    int old = sig(32);
    EXPECT_EQ(old, 2);
    EXPECT_EQ(ent.a, 32);
  }

  // Alternative signal sintax

  {
    signal0<void> sig;
    int x = 2;
    sig.connect([&x](){ ++x; });
    EXPECT_EQ(x, 2);
    sig();
    EXPECT_EQ(x, 3);
    sig();
    EXPECT_EQ(x, 4);
  }

  {
    signal1<void, int> sig;
    int x = 2;
    sig.connect([&x](int y){ x += y; });
    sig(3);
    sig(4);
    EXPECT_EQ(x, 9);
  }

  {
    signal2<void, int, int> sig;
    int c = 0;
    sig.connect([&](int x, int y){ c = x+y; });
    sig(3, 4);
    EXPECT_EQ(c, 7);
  }
}
<|endoftext|>


<commit_before>/**
* @file background.cpp
* @brief Purpose: Contains methods that ensure background handling.
*
* MIT License
* Copyright (c) 2017 MindScape
*
* https://github.com/TecProg2017-2/mindscape/blob/master/LICENSE.md
*/
#include "background.hpp"
#include "log.hpp"
#include <assert.h>

using namespace mindscape;
/**
* @brief Updates the background on game event.
*
* The game event may change how the background is presented to the player
*
* @param GameEvent containing the game event that may affect the background.
* @return void.
*/
void Background::on_event(GameEvent game_event){
	/* Object verification */
	assert(!game_event.game_event_name.empty());

	/* Variable declaration */
    std::string event_name = game_event.game_event_name;

    if (event_name == "MOVE_LEFT" && !engine::GameObject::on_limit_of_level) {
        /* When character is moving left */

        /* Moves background x coordinate to the right */
        set_position_x(get_position_x() + paralax);
    }
    else if (event_name == "MOVE_RIGHT" && !engine::GameObject::on_limit_of_level) {
        /* When character is moving right */

        /* Moves background x coordinate to the left */
        set_position_x(get_position_x() - paralax);
    }
    else {
        INFO("Caracter is stopped");
    }
}
/**
* @brief Sets paralax behavior to the background.
*
* Paralax effect is important to the game visual experience
*
* @param int containig the position of the paralax
* @return void.
*/
void Background::set_paralax(int p_paralax) {
	/* Parameter verification */
	assert(p_paralax >= 0);

    if (p_paralax > 10 || p_paralax < 0) {
        /* If paralax is out of valid range */

        paralax = 10; /* Sets paralax to a valid value */
    }
    else {
        paralax = p_paralax; /* Sets paralax to the given parameter */
    }
}

/**
* @brief Gets the backgrounds' paralax value.
*
* If the value of the paralax is needed, there must be a getter for it
*
* @return int containing the paralax value.
*/
int Background::get_paralax() {
    return paralax;
}
<commit_msg>[Fix] Fix menu parallax movement<commit_after>/**
* @file background.cpp
* @brief Purpose: Contains methods that ensure background handling.
*
* MIT License
* Copyright (c) 2017 MindScape
*
* https://github.com/TecProg2017-2/mindscape/blob/master/LICENSE.md
*/
#include "background.hpp"
#include "log.hpp"
#include <assert.h>

using namespace mindscape;
/**
* @brief Updates the background on game event.
*
* The game event may change how the background is presented to the player
*
* @param GameEvent containing the game event that may affect the background.
* @return void.
*/
void Background::on_event(GameEvent game_event){
	/* Object verification */
	assert(!game_event.game_event_name.empty());

	/* Variable declaration */
    std::string event_name = game_event.game_event_name;

		if (this->name == "main_background") {
			/* This avoids making parallax event happen in the menu */
			return;
		}

    if (event_name == "MOVE_LEFT" && !engine::GameObject::on_limit_of_level) {
        /* When character is moving left */

        /* Moves background x coordinate to the right */
        set_position_x(get_position_x() + paralax);
    }
    else if (event_name == "MOVE_RIGHT" && !engine::GameObject::on_limit_of_level) {
        /* When character is moving right */

        /* Moves background x coordinate to the left */
        set_position_x(get_position_x() - paralax);
    }
    else {
        INFO("Caracter is stopped");
    }
}
/**
* @brief Sets paralax behavior to the background.
*
* Paralax effect is important to the game visual experience
*
* @param int containig the position of the paralax
* @return void.
*/
void Background::set_paralax(int p_paralax) {
	/* Parameter verification */
	assert(p_paralax >= 0);

    if (p_paralax > 10 || p_paralax < 0) {
        /* If paralax is out of valid range */

        paralax = 10; /* Sets paralax to a valid value */
    }
    else {
        paralax = p_paralax; /* Sets paralax to the given parameter */
    }
}

/**
* @brief Gets the backgrounds' paralax value.
*
* If the value of the paralax is needed, there must be a getter for it
*
* @return int containing the paralax value.
*/
int Background::get_paralax() {
    return paralax;
}
<|endoftext|>


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

#ifndef __BASE_REFCNT_HH__
#define __BASE_REFCNT_HH__

class RefCounted
{
  private:
    mutable int count;

  private:
    // Don't allow a default copy constructor or copy operator on
    // these objects because the default operation will copy the
    // reference count as well and we certainly don't want that.
    RefCounted(const RefCounted &);
    RefCounted &operator=(const RefCounted &);

  public:
    RefCounted() : count(0) {}
    virtual ~RefCounted() {}

    void incref() { ++count; }
    void decref() { if (--count <= 0) delete this; }
};

template <class T>
class RefCountingPtr
{
  protected:
    T *data;

    void copy(T *d)
    {
        data = d;
        if (data)
            data->incref();
    }
    void del()
    {
        if (data)
            data->decref();
    }
    void set(T *d)
    {
        if (data == d)
            return;

        del();
        copy(d);
    }

  public:
    RefCountingPtr() : data(0) {}
    RefCountingPtr(T *data) { copy(data); }
    RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
    ~RefCountingPtr() { del(); }

    T *operator->() const { return data; }
    T &operator*() const { return *data; }
    T *get() const { return data; }

    const RefCountingPtr &operator=(T *p) { set(p); return *this; }
    const RefCountingPtr &operator=(const RefCountingPtr &r)
    { return operator=(r.data); }

    bool operator!() const { return data == 0; }
    operator bool() const { return data != 0; }
};

template<class T>
bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() == r.get(); }

template<class T>
bool operator==(const RefCountingPtr<T> &l, const T *r)
{ return l.get() == r; }

template<class T>
bool operator==(const T *l, const RefCountingPtr<T> &r)
{ return l == r.get(); }

template<class T>
bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() != r.get(); }

template<class T>
bool operator!=(const RefCountingPtr<T> &l, const T *r)
{ return l.get() != r; }

template<class T>
bool operator!=(const T *l, const RefCountingPtr<T> &r)
{ return l != r.get(); }

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

#ifndef __BASE_REFCNT_HH__
#define __BASE_REFCNT_HH__

class RefCounted
{
  private:
    mutable int count;

  private:
    // Don't allow a default copy constructor or copy operator on
    // these objects because the default operation will copy the
    // reference count as well and we certainly don't want that.
    RefCounted(const RefCounted &);
    RefCounted &operator=(const RefCounted &);

  public:
    RefCounted() : count(0) {}
    virtual ~RefCounted() {}

    void incref() { ++count; }
    void decref() { if (--count <= 0) delete this; }
};

template <class T>
class RefCountingPtr
{
  protected:
    T *data;

    void copy(T *d)
    {
        data = d;
        if (data)
            data->incref();
    }
    void del()
    {
        if (data)
            data->decref();
    }
    void set(T *d)
    {
        if (data == d)
            return;

        del();
        copy(d);
    }

  public:
    RefCountingPtr() : data(0) {}
    RefCountingPtr(T *data) { copy(data); }
    RefCountingPtr(const RefCountingPtr &r) { copy(r.data); }
    ~RefCountingPtr() { del(); }

    T *operator->() const { return data; }
    T &operator*() const { return *data; }
    T *get() const { return data; }

    const RefCountingPtr &operator=(T *p) { set(p); return *this; }
    const RefCountingPtr &operator=(const RefCountingPtr &r)
    { return operator=(r.data); }

    bool operator!() const { return data == 0; }
    operator bool() const { return data != 0; }
};

template<class T>
inline bool operator==(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() == r.get(); }

template<class T>
inline bool operator==(const RefCountingPtr<T> &l, const T *r)
{ return l.get() == r; }

template<class T>
inline bool operator==(const T *l, const RefCountingPtr<T> &r)
{ return l == r.get(); }

template<class T>
inline bool operator!=(const RefCountingPtr<T> &l, const RefCountingPtr<T> &r)
{ return l.get() != r.get(); }

template<class T>
inline bool operator!=(const RefCountingPtr<T> &l, const T *r)
{ return l.get() != r; }

template<class T>
inline bool operator!=(const T *l, const RefCountingPtr<T> &r)
{ return l != r.get(); }

#endif // __BASE_REFCNT_HH__
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010, Nicholas Campbell <nicholas.j.campbell@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the <ORGANIZATION> nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * 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 <node.h>
#include <node_version.h>

#include <string>
#include <cstring>

#include <openssl/rand.h>
#include <openssl/crypto.h>
#include "node_blf.h"

//pulled from node commit - 97cada0
#ifdef _WIN32
# include <windows.h>
#else
# include <pthread.h>
#endif

#define NODE_LESS_THAN (!(NODE_VERSION_AT_LEAST(0, 5, 4)))

using namespace v8;
using namespace node;

#ifdef _WIN32

static HANDLE* locks;

static void crypto_lock_init(void) {
  int i, n;

  n = CRYPTO_num_locks();
  locks = new HANDLE[n];

  for (i = 0; i < n; i++)
    if (!(locks[i] = CreateMutex(NULL, FALSE, NULL)))
      abort();
}

static void crypto_lock_cb(int mode, int n, const char* file, int line) {
  if (mode & CRYPTO_LOCK)
    WaitForSingleObject(locks[type], INFINITE);
  else
    ReleaseMutex(locks[type]);
}

static unsigned long crypto_id_cb(void) {
  return (unsigned long) GetCurrentThreadId();
}

#else /* !_WIN32 */

static pthread_rwlock_t* locks;

static void crypto_lock_init(void) {
  int i, n;

  n = CRYPTO_num_locks();
  locks = new pthread_rwlock_t[n];

  for (i = 0; i < n; i++)
    if (pthread_rwlock_init(locks + i, NULL))
      abort();
}

static void crypto_lock_cb(int mode, int n, const char* file, int line) {
  if (mode & CRYPTO_LOCK) {
    if (mode & CRYPTO_READ) pthread_rwlock_rdlock(locks + n);
    if (mode & CRYPTO_WRITE) pthread_rwlock_wrlock(locks + n);
  } else {
    pthread_rwlock_unlock(locks + n);
  }
}

static unsigned long crypto_id_cb(void) {
  return (unsigned long) pthread_self();
}

#endif /* !_WIN32 */

namespace {

struct baton_base {
    v8::Persistent<v8::Function> callback;
    std::string error;

    virtual ~baton_base() {
        callback.Dispose();
    }
};

struct salt_baton : baton_base {
    std::string salt;
    int rand_len;
    ssize_t rounds;
};

struct encrypt_baton : baton_base {
    std::string salt;
    std::string input;
    std::string output;
};

struct compare_baton : baton_base {
    std::string input;
    std::string encrypted;
    bool result;
};

int GetSeed(uint8_t* seed, int size) {
    switch (RAND_bytes((unsigned char *)seed, size)) {
        case -1:
        case 0:
            switch (RAND_pseudo_bytes(seed, size)) {
                case -1:
                    return -1;
                case 0:
                    return 0;
                default:
                    return 1;
            }
        default:
            return 1;
    }
}

bool ValidateSalt(const char* salt) {

    if (!salt || *salt != '$') {
        return false;
    }

    // discard $
    salt++;

    if (*salt > BCRYPT_VERSION) {
        return false;
    }

    if (salt[1] != '$') {
        switch (salt[1]) {
        case 'a':
            salt++;
            break;
        default:
            return false;
        }
    }

    // discard version + $
    salt += 2;

    if (salt[2] != '$') {
        return false;
    }

    int n = atoi(salt);
    if (n > 31 || n < 0) {
        return false;
    }

    if (((uint8_t)1 << (uint8_t)n) < BCRYPT_MINROUNDS) {
        return false;
    }

    salt += 3;
    if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) {
        return false;
    }

    return true;
}

/* SALT GENERATION */
void GenSaltAsync(uv_work_t* req) {

    salt_baton* baton = static_cast<salt_baton*>(req->data);

    char* salt = new char[_SALT_LEN];
    uint8_t* seed = new uint8_t[baton->rand_len];
    switch(GetSeed(seed, baton->rand_len)) {
        case -1:
            baton->error = "Rand operation not supported.";
        case 0:
            baton->error = "Rand operation did not generate a cryptographically sound seed.";
    }

    bcrypt_gensalt(baton->rounds, seed, salt);
    baton->salt = std::string(salt);

    delete[] salt;
    delete[] seed;
}

void GenSaltAsyncAfter(uv_work_t* req) {
    HandleScope scope;

    salt_baton* baton = static_cast<salt_baton*>(req->data);
    delete req;

    Handle<Value> argv[2];

    if (!baton->error.empty()) {
        argv[0] = Exception::Error(String::New(baton->error.c_str()));
        argv[1] = Undefined();
    }
    else {
        argv[0] = Undefined();
        argv[1] = Encode(baton->salt.c_str(), baton->salt.size(), BINARY);
    }

    TryCatch try_catch; // don't quite see the necessity of this

    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught())
        FatalException(try_catch);

    delete baton;
}

Handle<Value> GenerateSalt(const Arguments &args) {
    HandleScope scope;

    const ssize_t rounds = args[0]->Int32Value();
    const int rand_len = args[1]->Int32Value();
    Local<Function> callback = Local<Function>::Cast(args[2]);

    salt_baton* baton = new salt_baton();

    baton->callback = Persistent<Function>::New(callback);
    baton->rand_len = rand_len;
    baton->rounds = rounds;

    uv_work_t* req = new uv_work_t;
    req->data = baton;
    uv_queue_work(uv_default_loop(), req, GenSaltAsync, GenSaltAsyncAfter);

    return Undefined();
}

Handle<Value> GenerateSaltSync(const Arguments& args) {
    HandleScope scope;

    const ssize_t rounds = args[0]->Int32Value();
    const int size = args[1]->Int32Value();

    uint8_t* seed = new uint8_t[size];
    switch(GetSeed(seed, size)) {
        case -1:
            return ThrowException(Exception::Error(String::New("Rand operation not supported.")));
        case 0:
            return ThrowException(Exception::Error(String::New("Rand operation did not generate a cryptographically sound seed.")));
    }

    char salt[_SALT_LEN];
    bcrypt_gensalt(rounds, seed, salt);
    delete[] seed;

    return scope.Close(Encode(salt, strlen(salt), BINARY));
}

/* ENCRYPT DATA - USED TO BE HASHPW */
void EncryptAsync(uv_work_t* req) {
    encrypt_baton* baton = static_cast<encrypt_baton*>(req->data);

    if (!(ValidateSalt(baton->salt.c_str()))) {
        baton->error = "Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue";
    }

    char* bcrypted = new char[_PASSWORD_LEN];
    bcrypt(baton->input.c_str(), baton->salt.c_str(), bcrypted);
    baton->output = std::string(bcrypted);

    delete[] bcrypted;
}

void EncryptAsyncAfter(uv_work_t* req) {
    HandleScope scope;

    encrypt_baton* baton = static_cast<encrypt_baton*>(req->data);
    delete req;

    Handle<Value> argv[2];

    if (!baton->error.empty()) {
        argv[0] = Exception::Error(String::New(baton->error.c_str()));
        argv[1] = Undefined();
    }
    else {
        argv[0] = Undefined();
        argv[1] = Encode(baton->output.c_str(), baton->output.size(), BINARY);
    }

    TryCatch try_catch; // don't quite see the necessity of this

    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught())
        FatalException(try_catch);

    delete baton;
}

Handle<Value> Encrypt(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value data(args[0]->ToString());
    String::Utf8Value salt(args[1]->ToString());
    Local<Function> callback = Local<Function>::Cast(args[2]);

    encrypt_baton* baton = new encrypt_baton();
    baton->callback = Persistent<Function>::New(callback);
    baton->input = std::string(*data);
    baton->salt = std::string(*salt);

    uv_work_t* req = new uv_work_t;
    req->data = baton;
    uv_queue_work(uv_default_loop(), req, EncryptAsync, EncryptAsyncAfter);

    return Undefined();
}

Handle<Value> EncryptSync(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value data(args[0]->ToString());
    String::Utf8Value salt(args[1]->ToString());

    if (!(ValidateSalt(*salt))) {
        return ThrowException(Exception::Error(String::New("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue")));
    }

    char bcrypted[_PASSWORD_LEN];
    bcrypt(*data, *salt, bcrypted);
    return scope.Close(Encode(bcrypted, strlen(bcrypted), BINARY));
}

/* COMPARATOR */
bool CompareStrings(const char* s1, const char* s2) {

    bool eq = true;
    int s1_len = strlen(s1);
    int s2_len = strlen(s2);

    if (s1_len != s2_len) {
        eq = false;
    }

    const int max_len = (s2_len < s1_len) ? s1_len : s2_len;

    // to prevent timing attacks, should check entire string
    // don't exit after found to be false
    for (int i = 0; i < max_len; ++i) {
      if (s1_len >= i && s2_len >= i && s1[i] != s2[i]) {
        eq = false;
      }
    }

    return eq;
}

void CompareAsync(uv_work_t* req) {
    compare_baton* baton = static_cast<compare_baton*>(req->data);

    char bcrypted[_PASSWORD_LEN];
    bcrypt(baton->input.c_str(), baton->encrypted.c_str(), bcrypted);
    baton->result = CompareStrings(bcrypted, baton->encrypted.c_str());
}

void CompareAsyncAfter(uv_work_t* req) {
    HandleScope scope;

    compare_baton* baton = static_cast<compare_baton*>(req->data);
    delete req;

    Handle<Value> argv[2];

    if (!baton->error.empty()) {
        argv[0] = Exception::Error(String::New(baton->error.c_str()));
        argv[1] = Undefined();
    } else {
        argv[0] = Undefined();
        argv[1] = Boolean::New(baton->result);
    }

    TryCatch try_catch; // don't quite see the necessity of this

    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught())
        FatalException(try_catch);

    // done with the baton
    // free the memory and callback
    delete baton;
}

Handle<Value> Compare(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value input(args[0]->ToString());
    String::Utf8Value encrypted(args[1]->ToString());
    Local<Function> callback = Local<Function>::Cast(args[2]);

    compare_baton* baton = new compare_baton();
    baton->callback = Persistent<Function>::New(callback);
    baton->input = std::string(*input);
    baton->encrypted = std::string(*encrypted);

    uv_work_t* req = new uv_work_t;
    req->data = baton;
    uv_queue_work(uv_default_loop(), req, CompareAsync, CompareAsyncAfter);

    return Undefined();
}

Handle<Value> CompareSync(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value pw(args[0]->ToString());
    String::Utf8Value hash(args[1]->ToString());

    char bcrypted[_PASSWORD_LEN];
    bcrypt(*pw, *hash, bcrypted);
    return Boolean::New(CompareStrings(bcrypted, *hash));
}

Handle<Value> GetRounds(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value hash(args[0]->ToString());
    u_int32_t rounds;
    if (!(rounds = bcrypt_get_rounds(*hash))) {
        return ThrowException(Exception::Error(String::New("invalid hash provided")));
    }

    return Integer::New(rounds);
}

} // anonymous namespace

// bind the bcrypt module
extern "C" void init(Handle<Object> target) {
    HandleScope scope;

    crypto_lock_init();
    CRYPTO_set_locking_callback(crypto_lock_cb);
    CRYPTO_set_id_callback(crypto_id_cb);

    NODE_SET_METHOD(target, "gen_salt_sync", GenerateSaltSync);
    NODE_SET_METHOD(target, "encrypt_sync", EncryptSync);
    NODE_SET_METHOD(target, "compare_sync", CompareSync);
    NODE_SET_METHOD(target, "get_rounds", GetRounds);
    NODE_SET_METHOD(target, "gen_salt", GenerateSalt);
    NODE_SET_METHOD(target, "encrypt", Encrypt);
    NODE_SET_METHOD(target, "compare", Compare);
};

<commit_msg>code cleanup<commit_after>/*
 * Copyright (c) 2010, Nicholas Campbell <nicholas.j.campbell@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the <ORGANIZATION> nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * 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 <node.h>
#include <node_version.h>

#include <string>
#include <cstring>

#include <openssl/rand.h>
#include <openssl/crypto.h>
#include "node_blf.h"

//pulled from node commit - 97cada0
#ifdef _WIN32
# include <windows.h>
#else
# include <pthread.h>
#endif

#define NODE_LESS_THAN (!(NODE_VERSION_AT_LEAST(0, 5, 4)))

using namespace v8;
using namespace node;

#ifdef _WIN32

static HANDLE* locks;

static void crypto_lock_init(void) {
  int i, n;

  n = CRYPTO_num_locks();
  locks = new HANDLE[n];

  for (i = 0; i < n; i++)
    if (!(locks[i] = CreateMutex(NULL, FALSE, NULL)))
      abort();
}

static void crypto_lock_cb(int mode, int n, const char* file, int line) {
  if (mode & CRYPTO_LOCK)
    WaitForSingleObject(locks[type], INFINITE);
  else
    ReleaseMutex(locks[type]);
}

static unsigned long crypto_id_cb(void) {
  return (unsigned long) GetCurrentThreadId();
}

#else /* !_WIN32 */

static pthread_rwlock_t* locks;

static void crypto_lock_init(void) {

  const int n = CRYPTO_num_locks();
  locks = new pthread_rwlock_t[n];

  for (int i = 0; i < n; i++)
    if (pthread_rwlock_init(locks + i, NULL))
      abort();
}

static void crypto_lock_cb(int mode, int n, const char* file, int line) {
  if (mode & CRYPTO_LOCK) {
    if (mode & CRYPTO_READ) pthread_rwlock_rdlock(locks + n);
    if (mode & CRYPTO_WRITE) pthread_rwlock_wrlock(locks + n);
  } else {
    pthread_rwlock_unlock(locks + n);
  }
}

static unsigned long crypto_id_cb(void) {
  return (unsigned long) pthread_self();
}

#endif /* !_WIN32 */

namespace {

struct baton_base {
    v8::Persistent<v8::Function> callback;
    std::string error;

    virtual ~baton_base() {
        callback.Dispose();
    }
};

struct salt_baton : baton_base {
    std::string salt;
    int rand_len;
    ssize_t rounds;
};

struct encrypt_baton : baton_base {
    std::string salt;
    std::string input;
    std::string output;
};

struct compare_baton : baton_base {
    std::string input;
    std::string encrypted;
    bool result;
};

int GetSeed(uint8_t* seed, int size) {

    // try to get good random bytes first
    if (RAND_bytes((unsigned char *)seed, size) > 0) {
        return 1;
    }

    return RAND_pseudo_bytes(seed, size);
}

bool ValidateSalt(const char* salt) {

    if (!salt || *salt != '$') {
        return false;
    }

    // discard $
    salt++;

    if (*salt > BCRYPT_VERSION) {
        return false;
    }

    if (salt[1] != '$') {
        switch (salt[1]) {
        case 'a':
            salt++;
            break;
        default:
            return false;
        }
    }

    // discard version + $
    salt += 2;

    if (salt[2] != '$') {
        return false;
    }

    int n = atoi(salt);
    if (n > 31 || n < 0) {
        return false;
    }

    if (((uint8_t)1 << (uint8_t)n) < BCRYPT_MINROUNDS) {
        return false;
    }

    salt += 3;
    if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) {
        return false;
    }

    return true;
}

/* SALT GENERATION */
void GenSaltAsync(uv_work_t* req) {

    salt_baton* baton = static_cast<salt_baton*>(req->data);

    std::auto_ptr<uint8_t> seed (new uint8_t[baton->rand_len]);
    switch(GetSeed(seed.get(), baton->rand_len)) {
        case -1:
            baton->error = "Rand operation not supported.";
        case 0:
            baton->error = "Rand operation did not generate a cryptographically sound seed.";
    }

    char salt[_SALT_LEN];
    bcrypt_gensalt(baton->rounds, seed.get(), salt);
    baton->salt = std::string(salt);
}

void GenSaltAsyncAfter(uv_work_t* req) {
    HandleScope scope;

    salt_baton* baton = static_cast<salt_baton*>(req->data);
    delete req;

    Handle<Value> argv[2];

    if (!baton->error.empty()) {
        argv[0] = Exception::Error(String::New(baton->error.c_str()));
        argv[1] = Undefined();
    }
    else {
        argv[0] = Undefined();
        argv[1] = Encode(baton->salt.c_str(), baton->salt.size(), BINARY);
    }

    TryCatch try_catch; // don't quite see the necessity of this

    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught())
        FatalException(try_catch);

    delete baton;
}

Handle<Value> GenerateSalt(const Arguments &args) {
    HandleScope scope;

    const ssize_t rounds = args[0]->Int32Value();
    const int rand_len = args[1]->Int32Value();
    Local<Function> callback = Local<Function>::Cast(args[2]);

    salt_baton* baton = new salt_baton();

    baton->callback = Persistent<Function>::New(callback);
    baton->rand_len = rand_len;
    baton->rounds = rounds;

    uv_work_t* req = new uv_work_t;
    req->data = baton;
    uv_queue_work(uv_default_loop(), req, GenSaltAsync, GenSaltAsyncAfter);

    return Undefined();
}

Handle<Value> GenerateSaltSync(const Arguments& args) {
    HandleScope scope;

    const ssize_t rounds = args[0]->Int32Value();
    const int size = args[1]->Int32Value();

    std::auto_ptr<uint8_t> seed (new uint8_t[size]);
    switch(GetSeed(seed.get(), size)) {
        case -1:
            return ThrowException(Exception::Error(String::New("Rand operation not supported.")));
        case 0:
            return ThrowException(Exception::Error(String::New("Rand operation did not generate a cryptographically sound seed.")));
    }

    char salt[_SALT_LEN];
    bcrypt_gensalt(rounds, seed.get(), salt);

    return scope.Close(Encode(salt, strlen(salt), BINARY));
}

/* ENCRYPT DATA - USED TO BE HASHPW */
void EncryptAsync(uv_work_t* req) {
    encrypt_baton* baton = static_cast<encrypt_baton*>(req->data);

    if (!(ValidateSalt(baton->salt.c_str()))) {
        baton->error = "Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue";
    }

    char bcrypted[_PASSWORD_LEN];
    bcrypt(baton->input.c_str(), baton->salt.c_str(), bcrypted);
    baton->output = std::string(bcrypted);
}

void EncryptAsyncAfter(uv_work_t* req) {
    HandleScope scope;

    encrypt_baton* baton = static_cast<encrypt_baton*>(req->data);
    delete req;

    Handle<Value> argv[2];

    if (!baton->error.empty()) {
        argv[0] = Exception::Error(String::New(baton->error.c_str()));
        argv[1] = Undefined();
    }
    else {
        argv[0] = Undefined();
        argv[1] = Encode(baton->output.c_str(), baton->output.size(), BINARY);
    }

    TryCatch try_catch; // don't quite see the necessity of this

    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught())
        FatalException(try_catch);

    delete baton;
}

Handle<Value> Encrypt(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value data(args[0]->ToString());
    String::Utf8Value salt(args[1]->ToString());
    Local<Function> callback = Local<Function>::Cast(args[2]);

    encrypt_baton* baton = new encrypt_baton();
    baton->callback = Persistent<Function>::New(callback);
    baton->input = std::string(*data);
    baton->salt = std::string(*salt);

    uv_work_t* req = new uv_work_t;
    req->data = baton;
    uv_queue_work(uv_default_loop(), req, EncryptAsync, EncryptAsyncAfter);

    return Undefined();
}

Handle<Value> EncryptSync(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value data(args[0]->ToString());
    String::Utf8Value salt(args[1]->ToString());

    if (!(ValidateSalt(*salt))) {
        return ThrowException(Exception::Error(String::New("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue")));
    }

    char bcrypted[_PASSWORD_LEN];
    bcrypt(*data, *salt, bcrypted);
    return scope.Close(Encode(bcrypted, strlen(bcrypted), BINARY));
}

/* COMPARATOR */
bool CompareStrings(const char* s1, const char* s2) {

    bool eq = true;
    int s1_len = strlen(s1);
    int s2_len = strlen(s2);

    if (s1_len != s2_len) {
        eq = false;
    }

    const int max_len = (s2_len < s1_len) ? s1_len : s2_len;

    // to prevent timing attacks, should check entire string
    // don't exit after found to be false
    for (int i = 0; i < max_len; ++i) {
      if (s1_len >= i && s2_len >= i && s1[i] != s2[i]) {
        eq = false;
      }
    }

    return eq;
}

void CompareAsync(uv_work_t* req) {
    compare_baton* baton = static_cast<compare_baton*>(req->data);

    char bcrypted[_PASSWORD_LEN];
    bcrypt(baton->input.c_str(), baton->encrypted.c_str(), bcrypted);
    baton->result = CompareStrings(bcrypted, baton->encrypted.c_str());
}

void CompareAsyncAfter(uv_work_t* req) {
    HandleScope scope;

    compare_baton* baton = static_cast<compare_baton*>(req->data);
    delete req;

    Handle<Value> argv[2];

    if (!baton->error.empty()) {
        argv[0] = Exception::Error(String::New(baton->error.c_str()));
        argv[1] = Undefined();
    } else {
        argv[0] = Undefined();
        argv[1] = Boolean::New(baton->result);
    }

    TryCatch try_catch; // don't quite see the necessity of this

    baton->callback->Call(Context::GetCurrent()->Global(), 2, argv);

    if (try_catch.HasCaught())
        FatalException(try_catch);

    // done with the baton
    // free the memory and callback
    delete baton;
}

Handle<Value> Compare(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value input(args[0]->ToString());
    String::Utf8Value encrypted(args[1]->ToString());
    Local<Function> callback = Local<Function>::Cast(args[2]);

    compare_baton* baton = new compare_baton();
    baton->callback = Persistent<Function>::New(callback);
    baton->input = std::string(*input);
    baton->encrypted = std::string(*encrypted);

    uv_work_t* req = new uv_work_t;
    req->data = baton;
    uv_queue_work(uv_default_loop(), req, CompareAsync, CompareAsyncAfter);

    return Undefined();
}

Handle<Value> CompareSync(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value pw(args[0]->ToString());
    String::Utf8Value hash(args[1]->ToString());

    char bcrypted[_PASSWORD_LEN];
    bcrypt(*pw, *hash, bcrypted);
    return Boolean::New(CompareStrings(bcrypted, *hash));
}

Handle<Value> GetRounds(const Arguments& args) {
    HandleScope scope;

    String::Utf8Value hash(args[0]->ToString());
    u_int32_t rounds;
    if (!(rounds = bcrypt_get_rounds(*hash))) {
        return ThrowException(Exception::Error(String::New("invalid hash provided")));
    }

    return Integer::New(rounds);
}

} // anonymous namespace

// bind the bcrypt module
extern "C" void init(Handle<Object> target) {
    HandleScope scope;

    crypto_lock_init();
    CRYPTO_set_locking_callback(crypto_lock_cb);
    CRYPTO_set_id_callback(crypto_id_cb);

    NODE_SET_METHOD(target, "gen_salt_sync", GenerateSaltSync);
    NODE_SET_METHOD(target, "encrypt_sync", EncryptSync);
    NODE_SET_METHOD(target, "compare_sync", CompareSync);
    NODE_SET_METHOD(target, "get_rounds", GetRounds);
    NODE_SET_METHOD(target, "gen_salt", GenerateSalt);
    NODE_SET_METHOD(target, "encrypt", Encrypt);
    NODE_SET_METHOD(target, "compare", Compare);
};

<|endoftext|>


<commit_before>
#include <cmath>

#include "ofxPS3EyeGrabber.h"
#include "beamCamera.h"

ofPoint rotate_point(ofPoint point, ofPoint center, float angle)
{
    //convert degrees to radians
    angle = angle * M_PI / 180;

    float s = sin(angle);
    float c = cos(angle);

    // translate point back to origin:
    point.x -= center.x;
    point.y -= center.y;

    // rotate point
    float xnew = point.x * c - point.y * s;
    float ynew = point.x * s + point.y * c;

    // translate point back:
    point.x = xnew + center.x;
    point.y = ynew + center.y;

    return point;
}

BeamDescriptor::BeamDescriptor()
{
    mask.allocate(WIDTH, HEIGHT);
    zero();
}

BeamDescriptor::BeamDescriptor(ofImage& image)
{
    //learn from an existing image (saved beam mask)
    mask.allocate(WIDTH, HEIGHT);
    mask = image;
    learn();
}

BeamDescriptor::~BeamDescriptor()
{
    mask.clear();
}

void BeamDescriptor::zero()
{
    cvZero(mask.getCvImage());
    mask.flagImageChanged();
}

void BeamDescriptor::learn()
{
    ofxCvContourFinder contourFinder;
    contourFinder.findContours(mask,
                               BLOB_AREA_MIN,
                               (WIDTH * HEIGHT), //allow large blobs
                               1, //ofxOpenCv sorts for the largest blob
                               false); //find holes

    if(contourFinder.blobs.size() == 0)
    {
        ofLog() << "No beam mask detected";
        blob = ofxCvBlob(); //null blob
        return;
    }

    blob = contourFinder.blobs[0];

    //compute endpoints of the blob

    const float w = blob.minRect.size.width;
    const float h = blob.minRect.size.height;

    top.x = bottom.x = blob.minRect.center.x;
    top.y = bottom.y = blob.minRect.center.y;

    if(h > w)
    {
        top.y    = blob.minRect.center.y - (h / 2.0);
        bottom.y = blob.minRect.center.y + (h / 2.0);
    }
    else
    {
        top.x    = blob.minRect.center.x + (w / 2.0);
        bottom.x = blob.minRect.center.x - (w / 2.0);
    }

    top = rotate_point(top,
                       ofPoint(blob.minRect.center.x, blob.minRect.center.y),
                       blob.minRect.angle);
    bottom = rotate_point(bottom,
                          ofPoint(blob.minRect.center.x, blob.minRect.center.y),
                          blob.minRect.angle);
}

void BeamDescriptor::add_to_mask(ofxCvGrayscaleImage partial)
{
    cvOr(partial.getCvImage(),
         mask.getCvImage(),
         mask.getCvImage());

    mask.flagImageChanged();
}

BeamCamera::BeamCamera(int deviceID, const string name) : cam_name(name)
{
    grabber.setGrabber(std::make_shared<ofxPS3EyeGrabber>());
    grabber.setDeviceID(deviceID);

    grabber.setPixelFormat(OF_PIXELS_RGB);
    grabber.setDesiredFrameRate(FRAMERATE);
    grabber.setup(WIDTH, HEIGHT);

    //PS3 Eye specific settings
    grabber.getGrabber<ofxPS3EyeGrabber>()->setAutogain(false);
    grabber.getGrabber<ofxPS3EyeGrabber>()->setAutoWhiteBalance(false);

    //allocate our working surfaces
    raw.allocate(WIDTH, HEIGHT);
    grey_bg.allocate(WIDTH, HEIGHT);
    grey_working.allocate(WIDTH, HEIGHT);
    grey_beam_working.allocate(WIDTH, HEIGHT);

    threshold = INIT_THRESHOLD;
    learning = NOT_LEARNING;

    load_data();
}

BeamCamera::~BeamCamera()
{
    //release our surfaces
    raw.clear();
    grey_bg.clear();
    grey_working.clear();
    grey_beam_working.clear();

    for(BeamDescriptor* beam : beams)
    {
        if(beam != NULL)
            delete beam;
    }
}

void BeamCamera::load_data()
{
    ofDirectory dir(cam_name);
    if(!dir.exists())
    {
        dir.create();
        return;
    }

    dir.allowExt(IMAGE_FORMAT);
    dir.listDir();

    for(ofFile file : dir)
    {
        ofImage img;

        if(file.getBaseName() == BACKGROUND_FILE)
        {
            img.load(file);
            grey_bg = img;
        }
        else
        {
            int beam = ofToInt(file.getBaseName());

            if(beam < 0)
                continue;

            img.load(file);
            //make sure our mask array has a spot for this beam
            if(beam >= (int) beams.size())
                beams.resize(beam + 1, NULL);

            beams[beam] = new BeamDescriptor(img);
        }
    }
}

void BeamCamera::update()
{
    grabber.update();

    if(grabber.isFrameNew())
    {
        raw.setFromPixels(grabber.getPixels());

        //perform background subtraction
        grey_working = raw;
        cvSub(grey_working.getCvImage(),
              grey_bg.getCvImage(),
              grey_working.getCvImage());
        grey_working.flagImageChanged();

        //apply our intensity threshold
        grey_working.threshold(threshold);

        if(is_learning() && beams[learning] != NULL)
        {
            beams[learning]->add_to_mask(grey_working);
        }
    }
}

void BeamCamera::draw_raw(int x, int y)
{
    raw.draw(x, y);
}

void BeamCamera::draw_working(int x, int y)
{
    grey_working.draw(x, y);
}

void BeamCamera::draw_masks(int x, int y)
{
    cvZero(grey_beam_working.getCvImage());

    for(BeamDescriptor* beam : beams)
    {
        if(beam != NULL)
        {
            cvOr(beam->mask.getCvImage(),
                 grey_beam_working.getCvImage(),
                 grey_beam_working.getCvImage());
        }
    }

    grey_beam_working.flagImageChanged();
    grey_beam_working.draw(x, y);

    for(BeamDescriptor* beam : beams)
    {
        if(beam != NULL)
        {
            beam->blob.draw();
            ofPushStyle();
            ofSetHexColor(0xFF0000);
            ofDrawCircle(beam->top.x, beam->top.y, 3);
            ofSetHexColor(0x0000FF);
            ofDrawCircle(beam->bottom.x, beam->bottom.y, 3);
            ofPopStyle();
        }
    }
}

int BeamCamera::get_threshold()
{
    return threshold;
}

void BeamCamera::adjust_threshold(int delta)
{
    //clamp to [0, 255]
    int new_thresh = threshold + delta;
    if(new_thresh < 0) new_thresh = 0;
    else if(new_thresh > 255) new_thresh = 255;
    threshold = new_thresh;
}

void BeamCamera::learn_background()
{
    grey_bg = raw;

    //save the background to a file
    ofImage background;
    background.setFromPixels(grey_bg.getPixels());
    background.setImageType(OF_IMAGE_GRAYSCALE);

    stringstream filename;
    filename << cam_name << "/" << BACKGROUND_FILE << "." << IMAGE_FORMAT;
    background.save(filename.str());
}

bool BeamCamera::is_learning()
{
    return learning != NOT_LEARNING;
}

void BeamCamera::start_learning_beam(int beam)
{
    ofLog() << cam_name << " started learning beam " << beam;
    new_beam(beam);
    learning = beam;
}

void BeamCamera::stop_learning_beam()
{
    //compute and save the minimum area rect
    BeamDescriptor* beam = beams[learning];
    beam->learn();

    //save the mask to a file
    ofImage mask;
    mask.setFromPixels(beam->mask.getPixels());
    mask.setImageType(OF_IMAGE_GRAYSCALE);

    stringstream filename;
    filename << cam_name << "/" << learning << "." << IMAGE_FORMAT;
    mask.save(filename.str());

    ofLog() << cam_name << " stopped learning beam " << learning;
    learning = NOT_LEARNING;
}

vector<Hand> BeamCamera::hands_for_beam(int beam)
{
    //return early if there's nothing to process
    if(!mask_exists(beam))
        return vector<Hand>();

    //apply the mask that corresponds to this beam
    cvAnd(grey_working.getCvImage(),
          beams[beam]->mask.getCvImage(),
          grey_beam_working.getCvImage());
    grey_beam_working.flagImageChanged();

    //find our hand blobs
    contourFinder.findContours(grey_beam_working,
                               BLOB_AREA_MIN,
                               BLOB_AREA_MAX,
                               N_BLOBS,
                               false); //find holes

    //contourFinder.blobs is now populated
}

bool BeamCamera::mask_exists(int beam)
{
    return (beam < (int)beams.size()) && (beams[beam] != NULL);
}

void BeamCamera::new_beam(int beam)
{
    //make sure our mask array has a spot for this beam
    if(beam >= (int) beams.size())
        beams.resize(beam + 1, NULL);

    if(mask_exists(beam))
        beams[beam]->zero();
    else
        beams[beam] = new BeamDescriptor();
}
<commit_msg>save radius of beam in pixels<commit_after>
#include <cmath>

#include "ofxPS3EyeGrabber.h"
#include "beamCamera.h"

ofPoint rotate_point(ofPoint point, ofPoint center, float angle)
{
    //convert degrees to radians
    angle = angle * M_PI / 180;

    float s = sin(angle);
    float c = cos(angle);

    // translate point back to origin:
    point.x -= center.x;
    point.y -= center.y;

    // rotate point
    float xnew = point.x * c - point.y * s;
    float ynew = point.x * s + point.y * c;

    // translate point back:
    point.x = xnew + center.x;
    point.y = ynew + center.y;

    return point;
}

BeamDescriptor::BeamDescriptor()
{
    mask.allocate(WIDTH, HEIGHT);
    zero();
}

BeamDescriptor::BeamDescriptor(ofImage& image)
{
    //learn from an existing image (saved beam mask)
    mask.allocate(WIDTH, HEIGHT);
    mask = image;
    learn();
}

BeamDescriptor::~BeamDescriptor()
{
    mask.clear();
}

void BeamDescriptor::zero()
{
    cvZero(mask.getCvImage());
    mask.flagImageChanged();
}

void BeamDescriptor::learn()
{
    ofxCvContourFinder contourFinder;
    contourFinder.findContours(mask,
                               BLOB_AREA_MIN,
                               (WIDTH * HEIGHT), //allow large blobs
                               1, //ofxOpenCv sorts for the largest blob
                               false); //find holes

    if(contourFinder.blobs.size() == 0)
    {
        ofLog() << "No beam mask detected";
        blob = ofxCvBlob(); //null blob
        return;
    }

    blob = contourFinder.blobs[0];

    //compute endpoints of the blob

    const float w = blob.minRect.size.width;
    const float h = blob.minRect.size.height;

    top.x = bottom.x = blob.minRect.center.x;
    top.y = bottom.y = blob.minRect.center.y;

    if(h > w)
    {
        top.y    = blob.minRect.center.y - (h / 2.0);
        bottom.y = blob.minRect.center.y + (h / 2.0);
        radius = w / 2.0;
    }
    else
    {
        top.x    = blob.minRect.center.x + (w / 2.0);
        bottom.x = blob.minRect.center.x - (w / 2.0);
        radius = h / 2.0;
    }

    top = rotate_point(top,
                       ofPoint(blob.minRect.center.x, blob.minRect.center.y),
                       blob.minRect.angle);
    bottom = rotate_point(bottom,
                          ofPoint(blob.minRect.center.x, blob.minRect.center.y),
                          blob.minRect.angle);
}

void BeamDescriptor::add_to_mask(ofxCvGrayscaleImage partial)
{
    cvOr(partial.getCvImage(),
         mask.getCvImage(),
         mask.getCvImage());

    mask.flagImageChanged();
}

BeamCamera::BeamCamera(int deviceID, const string name) : cam_name(name)
{
    grabber.setGrabber(std::make_shared<ofxPS3EyeGrabber>());
    grabber.setDeviceID(deviceID);

    grabber.setPixelFormat(OF_PIXELS_RGB);
    grabber.setDesiredFrameRate(FRAMERATE);
    grabber.setup(WIDTH, HEIGHT);

    //PS3 Eye specific settings
    grabber.getGrabber<ofxPS3EyeGrabber>()->setAutogain(false);
    grabber.getGrabber<ofxPS3EyeGrabber>()->setAutoWhiteBalance(false);

    //allocate our working surfaces
    raw.allocate(WIDTH, HEIGHT);
    grey_bg.allocate(WIDTH, HEIGHT);
    grey_working.allocate(WIDTH, HEIGHT);
    grey_beam_working.allocate(WIDTH, HEIGHT);

    threshold = INIT_THRESHOLD;
    learning = NOT_LEARNING;

    load_data();
}

BeamCamera::~BeamCamera()
{
    //release our surfaces
    raw.clear();
    grey_bg.clear();
    grey_working.clear();
    grey_beam_working.clear();

    for(BeamDescriptor* beam : beams)
    {
        if(beam != NULL)
            delete beam;
    }
}

void BeamCamera::load_data()
{
    ofDirectory dir(cam_name);
    if(!dir.exists())
    {
        dir.create();
        return;
    }

    dir.allowExt(IMAGE_FORMAT);
    dir.listDir();

    for(ofFile file : dir)
    {
        ofImage img;

        if(file.getBaseName() == BACKGROUND_FILE)
        {
            img.load(file);
            grey_bg = img;
        }
        else
        {
            int beam = ofToInt(file.getBaseName());

            if(beam < 0)
                continue;

            img.load(file);
            //make sure our mask array has a spot for this beam
            if(beam >= (int) beams.size())
                beams.resize(beam + 1, NULL);

            beams[beam] = new BeamDescriptor(img);
        }
    }
}

void BeamCamera::update()
{
    grabber.update();

    if(grabber.isFrameNew())
    {
        raw.setFromPixels(grabber.getPixels());

        //perform background subtraction
        grey_working = raw;
        cvSub(grey_working.getCvImage(),
              grey_bg.getCvImage(),
              grey_working.getCvImage());
        grey_working.flagImageChanged();

        //apply our intensity threshold
        grey_working.threshold(threshold);

        if(is_learning() && beams[learning] != NULL)
        {
            beams[learning]->add_to_mask(grey_working);
        }
    }
}

void BeamCamera::draw_raw(int x, int y)
{
    raw.draw(x, y);
}

void BeamCamera::draw_working(int x, int y)
{
    grey_working.draw(x, y);
}

void BeamCamera::draw_masks(int x, int y)
{
    cvZero(grey_beam_working.getCvImage());

    for(BeamDescriptor* beam : beams)
    {
        if(beam != NULL)
        {
            cvOr(beam->mask.getCvImage(),
                 grey_beam_working.getCvImage(),
                 grey_beam_working.getCvImage());
        }
    }

    grey_beam_working.flagImageChanged();
    grey_beam_working.draw(x, y);

    for(BeamDescriptor* beam : beams)
    {
        if(beam != NULL)
        {
            beam->blob.draw();
            ofPushStyle();
            ofSetHexColor(0xFF0000);
            ofDrawCircle(beam->top.x, beam->top.y, 3);
            ofSetHexColor(0x0000FF);
            ofDrawCircle(beam->bottom.x, beam->bottom.y, 3);
            ofPopStyle();
        }
    }
}

int BeamCamera::get_threshold()
{
    return threshold;
}

void BeamCamera::adjust_threshold(int delta)
{
    //clamp to [0, 255]
    int new_thresh = threshold + delta;
    if(new_thresh < 0) new_thresh = 0;
    else if(new_thresh > 255) new_thresh = 255;
    threshold = new_thresh;
}

void BeamCamera::learn_background()
{
    grey_bg = raw;

    //save the background to a file
    ofImage background;
    background.setFromPixels(grey_bg.getPixels());
    background.setImageType(OF_IMAGE_GRAYSCALE);

    stringstream filename;
    filename << cam_name << "/" << BACKGROUND_FILE << "." << IMAGE_FORMAT;
    background.save(filename.str());
}

bool BeamCamera::is_learning()
{
    return learning != NOT_LEARNING;
}

void BeamCamera::start_learning_beam(int beam)
{
    ofLog() << cam_name << " started learning beam " << beam;
    new_beam(beam);
    learning = beam;
}

void BeamCamera::stop_learning_beam()
{
    //compute and save the minimum area rect
    BeamDescriptor* beam = beams[learning];
    beam->learn();

    //save the mask to a file
    ofImage mask;
    mask.setFromPixels(beam->mask.getPixels());
    mask.setImageType(OF_IMAGE_GRAYSCALE);

    stringstream filename;
    filename << cam_name << "/" << learning << "." << IMAGE_FORMAT;
    mask.save(filename.str());

    ofLog() << cam_name << " stopped learning beam " << learning;
    learning = NOT_LEARNING;
}

vector<Hand> BeamCamera::hands_for_beam(int beam)
{
    //return early if there's nothing to process
    if(!mask_exists(beam))
        return vector<Hand>();

    //apply the mask that corresponds to this beam
    cvAnd(grey_working.getCvImage(),
          beams[beam]->mask.getCvImage(),
          grey_beam_working.getCvImage());
    grey_beam_working.flagImageChanged();

    //find our hand blobs
    contourFinder.findContours(grey_beam_working,
                               BLOB_AREA_MIN,
                               BLOB_AREA_MAX,
                               N_BLOBS,
                               false); //find holes

    //contourFinder.blobs is now populated
}

bool BeamCamera::mask_exists(int beam)
{
    return (beam < (int)beams.size()) && (beams[beam] != NULL);
}

void BeamCamera::new_beam(int beam)
{
    //make sure our mask array has a spot for this beam
    if(beam >= (int) beams.size())
        beams.resize(beam + 1, NULL);

    if(mask_exists(beam))
        beams[beam]->zero();
    else
        beams[beam] = new BeamDescriptor();
}
<|endoftext|>


<commit_before>/******************************************************************************
*	  Birthstone is a programming language and interpreter language written    *
*   by Robb Tolliver for his Senior Project at BYU-Idaho during the Fall      *
*   Semester of 2010.                                                         *
*                                                                             *
*   Copyright (C) 2010 by Robert Tolliver                                     *
*   Robb.Tolli@gmail.com                                                      *
*                                                                             *
*   Birthstone is free software: you can redistribute it and/or modify        *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation, either version 3 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   Birthstone is distributed in the hope that it will be useful,             *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*   GNU General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with Birthstone.  If not, see <http://www.gnu.org/licenses/>.       *
*                                                                             *
******************************************************************************/
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "parser.h"
using namespace std;

int main(int argc, char **argv)
{
	string filename;
	bool interactive = true;
	if (argc > 1)
	{
		ifstream input(argv[1]);
		if (input.good())
			Parser(input).run();
		else
		{
			cerr << "error: could not read input file. " << endl;
		}
		input.close();
	}
	else // interactive mode
	{
		string str;
		stringstream input;
		Parser parser(input);
		cout << "birthstone interactive shell" << endl;
		do
		{
			cout << "bs> ";
			getline(cin, str);
			input.clear();
			input.seekg(0, ios_base::beg);
			input.str(str);

			parser.newInput(input);
			parser.run();
		} while (true/* TODO:  stop when quit or exit is entered*/);
	}

	return 0;
}
<commit_msg>minor change in output<commit_after>/******************************************************************************
*	  Birthstone is a programming language and interpreter language written    *
*   by Robb Tolliver for his Senior Project at BYU-Idaho during the Fall      *
*   Semester of 2010.                                                         *
*                                                                             *
*   Copyright (C) 2010 by Robert Tolliver                                     *
*   Robb.Tolli@gmail.com                                                      *
*                                                                             *
*   Birthstone is free software: you can redistribute it and/or modify        *
*   it under the terms of the GNU General Public License as published by      *
*   the Free Software Foundation, either version 3 of the License, or         *
*   (at your option) any later version.                                       *
*                                                                             *
*   Birthstone is distributed in the hope that it will be useful,             *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*   GNU General Public License for more details.                              *
*                                                                             *
*   You should have received a copy of the GNU General Public License         *
*   along with Birthstone.  If not, see <http://www.gnu.org/licenses/>.       *
*                                                                             *
******************************************************************************/
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include "parser.h"
using namespace std;

int main(int argc, char **argv)
{
	string filename;
	bool interactive = true;
	if (argc > 1)
	{
		ifstream input(argv[1]);
		if (input.good())
			Parser(input).run();
		else
		{
			cerr << "error: could not read input file. " << endl;
		}
		input.close();
	}
	else // interactive mode
	{
		string str;
		stringstream input;
		Parser parser(input);
		cout << "birthstone interactive interpreter" << endl;
		do
		{
			cout << "bs> ";
			getline(cin, str);
			input.clear();
			input.seekg(0, ios_base::beg);
			input.str(str);

			parser.newInput(input);
			parser.run();
		} while (true/* TODO:  stop when quit or exit is entered*/);
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <chrono>
#include <iostream>

#include "image.h"
using namespace AhoViewer::Booru;

#include "browser.h"

Image::Image(const std::string &path, const std::string &url,
             const std::string &thumbPath, const std::string &thumbUrl,
             const std::string &postUrl,
             std::set<std::string> tags, const Page &page)
  : AhoViewer::Image(path),
    m_Url(url),
    m_ThumbnailUrl(thumbUrl),
    m_PostUrl(postUrl),
    m_Tags(tags),
    m_Page(page),
    m_Curler(m_Url),
    m_ThumbnailCurler(m_ThumbnailUrl),
    m_PixbufError(false)
{
    m_ThumbnailPath = thumbPath;

    if (!m_isWebM)
        m_Curler.signal_write().connect(sigc::mem_fun(*this, &Image::on_write));

    if (m_isWebM && !Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
        m_Loading = true;

    m_Curler.set_referer(m_PostUrl);
    m_Curler.signal_progress().connect(sigc::mem_fun(*this, &Image::on_progress));
    m_Curler.signal_finished().connect(sigc::mem_fun(*this, &Image::on_finished));
}

Image::~Image()
{
    cancel_download();
}

std::string Image::get_filename() const
{
    return Glib::build_filename(m_Page.get_site()->get_name(), Glib::path_get_basename(m_Path));
}

const Glib::RefPtr<Gdk::Pixbuf>& Image::get_thumbnail()
{
    if (!m_ThumbnailPixbuf)
    {
        m_ThumbnailLock.writer_lock();
        if (m_ThumbnailCurler.perform())
        {
            m_ThumbnailCurler.save_file(m_ThumbnailPath);

            try
            {
                m_ThumbnailPixbuf = create_pixbuf_at_size(m_ThumbnailPath, 128, 128);
            }
            catch (const Gdk::PixbufError &ex)
            {
                std::cerr << ex.what() << std::endl;
                m_ThumbnailPixbuf = get_missing_pixbuf();
            }
        }
        else
        {
            std::cerr << "Error while downloading thumbnail " << m_ThumbnailUrl
                      << " " << std::endl << "  " << m_ThumbnailCurler.get_error() << std::endl;
            m_ThumbnailPixbuf = get_missing_pixbuf();
        }
        m_ThumbnailLock.writer_unlock();
    }

    return m_ThumbnailPixbuf;
}

void Image::load_pixbuf()
{
    if (!m_Pixbuf && !m_PixbufError)
    {
        if (Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
        {
            AhoViewer::Image::load_pixbuf();
        }
        else if (!start_download() && !m_isWebM && m_Loader->get_animation())
        {
            m_Pixbuf = m_Loader->get_animation();
        }
    }
}

void Image::reset_pixbuf()
{
    if (m_Loading)
        cancel_download();

    AhoViewer::Image::reset_pixbuf();
}

void Image::save(const std::string &path)
{
    if (!Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
    {
        start_download();

        Glib::Threads::Mutex::Lock lock(m_DownloadMutex);
        while (!m_Curler.is_cancelled() && !Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
            m_DownloadCond.wait(m_DownloadMutex);
    }

    if (m_Curler.is_cancelled())
        return;

    Glib::RefPtr<Gio::File> src = Gio::File::create_for_path(m_Path),
                            dst = Gio::File::create_for_path(path);
    src->copy(dst, Gio::FILE_COPY_OVERWRITE);
}

void Image::cancel_download()
{
    Glib::Threads::Mutex::Lock lock(m_DownloadMutex);
    m_Curler.cancel();
    m_Curler.clear();

    if (m_Loader)
    {
        try { m_Loader->close(); }
        catch (...) { }
        m_Loader.reset();
    }

    m_DownloadCond.signal();
}

/**
 * Returns true if the download was started
 **/
bool Image::start_download()
{
    if (!m_Curler.is_active())
    {
        m_Page.get_image_fetcher().add_handle(&m_Curler);
        m_Loading = true;

        if (!m_isWebM)
        {
            m_Loader = Gdk::PixbufLoader::create();
            m_Loader->signal_area_prepared().connect(sigc::mem_fun(*this, &Image::on_area_prepared));
            m_Loader->signal_area_updated().connect(sigc::mem_fun(*this, &Image::on_area_updated));
        }

        return true;
    }

    return false;
}

void Image::on_write(const unsigned char *d, size_t l)
{
    try
    {
        Glib::Threads::Mutex::Lock lock(m_DownloadMutex);
        m_Loader->write(d, l);
    }
    catch (const Gdk::PixbufError &ex)
    {
        std::cerr << ex.what() << std::endl;
        cancel_download();
        m_PixbufError = true;
    }
}

void Image::on_progress()
{
    double c, t;
    m_Curler.get_progress(c, t);
    m_SignalProgress(c, t);
}

void Image::on_finished()
{
    Glib::Threads::Mutex::Lock lock(m_DownloadMutex);

    m_Curler.save_file(m_Path);
    m_Curler.clear();

    if (m_Loader)
    {
        m_Loader->close();
        m_Loader.reset();
    }

    m_Loading = false;

    m_SignalPixbufChanged();
    m_DownloadCond.signal();
}

void Image::on_area_prepared()
{
    m_ThumbnailLock.reader_lock();
    if (m_ThumbnailPixbuf && m_ThumbnailPixbuf != get_missing_pixbuf())
    {
        Glib::RefPtr<Gdk::Pixbuf> pixbuf = m_Loader->get_pixbuf();
        m_ThumbnailPixbuf->composite(pixbuf, 0, 0, pixbuf->get_width(), pixbuf->get_height(), 0, 0,
                                     static_cast<double>(pixbuf->get_width()) / m_ThumbnailPixbuf->get_width(),
                                     static_cast<double>(pixbuf->get_height()) / m_ThumbnailPixbuf->get_height(),
                                     Gdk::INTERP_BILINEAR, 255);
    }
    m_ThumbnailLock.reader_unlock();

    m_Pixbuf = m_Loader->get_animation();

    if (!m_Curler.is_cancelled())
        m_SignalPixbufChanged();
}

void Image::on_area_updated(int, int, int, int)
{
    using namespace std::chrono;
    if (!m_Curler.is_cancelled() && steady_clock::now() >= m_LastDraw + milliseconds(100))
    {
        m_SignalPixbufChanged();
        m_LastDraw = steady_clock::now();
    }
}
<commit_msg>booru/image: nullcheck loader and move pixbuf assignment inside cancel check<commit_after>#include <chrono>
#include <iostream>

#include "image.h"
using namespace AhoViewer::Booru;

#include "browser.h"

Image::Image(const std::string &path, const std::string &url,
             const std::string &thumbPath, const std::string &thumbUrl,
             const std::string &postUrl,
             std::set<std::string> tags, const Page &page)
  : AhoViewer::Image(path),
    m_Url(url),
    m_ThumbnailUrl(thumbUrl),
    m_PostUrl(postUrl),
    m_Tags(tags),
    m_Page(page),
    m_Curler(m_Url),
    m_ThumbnailCurler(m_ThumbnailUrl),
    m_PixbufError(false)
{
    m_ThumbnailPath = thumbPath;

    if (!m_isWebM)
        m_Curler.signal_write().connect(sigc::mem_fun(*this, &Image::on_write));

    if (m_isWebM && !Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
        m_Loading = true;

    m_Curler.set_referer(m_PostUrl);
    m_Curler.signal_progress().connect(sigc::mem_fun(*this, &Image::on_progress));
    m_Curler.signal_finished().connect(sigc::mem_fun(*this, &Image::on_finished));
}

Image::~Image()
{
    cancel_download();
}

std::string Image::get_filename() const
{
    return Glib::build_filename(m_Page.get_site()->get_name(), Glib::path_get_basename(m_Path));
}

const Glib::RefPtr<Gdk::Pixbuf>& Image::get_thumbnail()
{
    if (!m_ThumbnailPixbuf)
    {
        m_ThumbnailLock.writer_lock();
        if (m_ThumbnailCurler.perform())
        {
            m_ThumbnailCurler.save_file(m_ThumbnailPath);

            try
            {
                m_ThumbnailPixbuf = create_pixbuf_at_size(m_ThumbnailPath, 128, 128);
            }
            catch (const Gdk::PixbufError &ex)
            {
                std::cerr << ex.what() << std::endl;
                m_ThumbnailPixbuf = get_missing_pixbuf();
            }
        }
        else
        {
            std::cerr << "Error while downloading thumbnail " << m_ThumbnailUrl
                      << " " << std::endl << "  " << m_ThumbnailCurler.get_error() << std::endl;
            m_ThumbnailPixbuf = get_missing_pixbuf();
        }
        m_ThumbnailLock.writer_unlock();
    }

    return m_ThumbnailPixbuf;
}

void Image::load_pixbuf()
{
    if (!m_Pixbuf && !m_PixbufError)
    {
        if (Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
        {
            AhoViewer::Image::load_pixbuf();
        }
        else if (!start_download() && !m_isWebM && m_Loader && m_Loader->get_animation())
        {
            m_Pixbuf = m_Loader->get_animation();
        }
    }
}

void Image::reset_pixbuf()
{
    if (m_Loading)
        cancel_download();

    AhoViewer::Image::reset_pixbuf();
}

void Image::save(const std::string &path)
{
    if (!Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
    {
        start_download();

        Glib::Threads::Mutex::Lock lock(m_DownloadMutex);
        while (!m_Curler.is_cancelled() && !Glib::file_test(m_Path, Glib::FILE_TEST_EXISTS))
            m_DownloadCond.wait(m_DownloadMutex);
    }

    if (m_Curler.is_cancelled())
        return;

    Glib::RefPtr<Gio::File> src = Gio::File::create_for_path(m_Path),
                            dst = Gio::File::create_for_path(path);
    src->copy(dst, Gio::FILE_COPY_OVERWRITE);
}

void Image::cancel_download()
{
    Glib::Threads::Mutex::Lock lock(m_DownloadMutex);
    m_Curler.cancel();
    m_Curler.clear();

    if (m_Loader)
    {
        try { m_Loader->close(); }
        catch (...) { }
        m_Loader.reset();
    }

    m_DownloadCond.signal();
}

/**
 * Returns true if the download was started
 **/
bool Image::start_download()
{
    if (!m_Curler.is_active())
    {
        m_Page.get_image_fetcher().add_handle(&m_Curler);
        m_Loading = true;

        if (!m_isWebM)
        {
            m_Loader = Gdk::PixbufLoader::create();
            m_Loader->signal_area_prepared().connect(sigc::mem_fun(*this, &Image::on_area_prepared));
            m_Loader->signal_area_updated().connect(sigc::mem_fun(*this, &Image::on_area_updated));
        }

        return true;
    }

    return false;
}

void Image::on_write(const unsigned char *d, size_t l)
{
    try
    {
        Glib::Threads::Mutex::Lock lock(m_DownloadMutex);
        m_Loader->write(d, l);
    }
    catch (const Gdk::PixbufError &ex)
    {
        std::cerr << ex.what() << std::endl;
        cancel_download();
        m_PixbufError = true;
    }
}

void Image::on_progress()
{
    double c, t;
    m_Curler.get_progress(c, t);
    m_SignalProgress(c, t);
}

void Image::on_finished()
{
    Glib::Threads::Mutex::Lock lock(m_DownloadMutex);

    m_Curler.save_file(m_Path);
    m_Curler.clear();

    if (m_Loader)
    {
        m_Loader->close();
        m_Loader.reset();
    }

    m_Loading = false;

    m_SignalPixbufChanged();
    m_DownloadCond.signal();
}

void Image::on_area_prepared()
{
    m_ThumbnailLock.reader_lock();
    if (m_ThumbnailPixbuf && m_ThumbnailPixbuf != get_missing_pixbuf())
    {
        Glib::RefPtr<Gdk::Pixbuf> pixbuf = m_Loader->get_pixbuf();
        m_ThumbnailPixbuf->composite(pixbuf, 0, 0, pixbuf->get_width(), pixbuf->get_height(), 0, 0,
                                     static_cast<double>(pixbuf->get_width()) / m_ThumbnailPixbuf->get_width(),
                                     static_cast<double>(pixbuf->get_height()) / m_ThumbnailPixbuf->get_height(),
                                     Gdk::INTERP_BILINEAR, 255);
    }
    m_ThumbnailLock.reader_unlock();

    if (!m_Curler.is_cancelled())
    {
        m_Pixbuf = m_Loader->get_animation();
        m_SignalPixbufChanged();
    }
}

void Image::on_area_updated(int, int, int, int)
{
    using namespace std::chrono;
    if (!m_Curler.is_cancelled() && steady_clock::now() >= m_LastDraw + milliseconds(100))
    {
        m_SignalPixbufChanged();
        m_LastDraw = steady_clock::now();
    }
}
<|endoftext|>


<commit_before>

#include "Buffer.h"
namespace OpenClouds
{
	void Buffer::Seek(BufferSeek seek, const int offset)
	{
		switch (seek)
		{
		case BufferSeek::Start:
			index = offset;
			break;
		case BufferSeek::Relative:
			index += offset;
			break;
		case BufferSeek::End:
			index = size + offset; //WARNING: OUT OF BOUND
			break;
		}
	}

	void Buffer::Seek(const int position)
	{
		index = position;
	}

	void Buffer::Clear()
	{
		//memfree(data)
		index = 0;
	}

	int Buffer::GetIndex() const
	{
		return index;
	}

	int Buffer::GetSize() const
	{
		return index;
	}

	void Buffer::WriteInt32(const int32_t value)
	{
		int diff = size - index;

		if (diff >= sizeof(int32_t))
		{
			data[index++] = value;
			data[index++] = (value >> 1);
			data[index++] = (value >> 2);
			data[index++] = (value >> 3);
		}
		else
		{
			//resize the data buffer
		}
	}

}<commit_msg> Implemented methods in Buffer.cpp, Added a new Buffer::Seek overload<commit_after>

#include "Buffer.h"
namespace OpenClouds
{
	void Buffer::Seek(BufferSeek seek, const int offset)
	{
		switch (seek)
		{
		case BufferSeek::Start:
			index = offset;
			break;
		case BufferSeek::Relative:
			index += offset;
			break;
		case BufferSeek::End:
			index = size + offset; //WARNING: OUT OF BOUND
			break;
		}
	}

	void Buffer::Seek(const int position)
	{
		index = position;
	}

	void Buffer::Clear()
	{
		//memfree(data)
		index = 0;
	}

	int Buffer::GetIndex() const
	{
		return index;
	}

	int Buffer::GetSize() const
	{
		return index;
	}

	void Buffer::WriteInt32(const int32_t value)
	{
		int diff = size - (index + 1);

		if (diff >= sizeof(int32_t))
		{
			data[index++] = value;
			data[index++] = (value >> 1);
			data[index++] = (value >> 2);
			data[index++] = (value >> 3);
		}
		else
		{
			//resize the data buffer
		}
	}

}<|endoftext|>


<commit_before><commit_msg>Boost removed<commit_after><|endoftext|>


<commit_before>
#pragma once

#include <istream>
#include <boost/spirit/include/support_utree.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#include <boost/spirit/home/support/info.hpp>
#include <boost/spirit/include/support_line_pos_iterator.hpp>

#include <boost/foreach.hpp>

namespace metaSMT
{
  namespace smt2
  {
    namespace spirit   = boost::spirit;
    namespace qi       = boost::spirit::qi;
    namespace phoenix  = boost::phoenix;
    namespace standard = boost::spirit::standard;
    namespace ascii    = boost::spirit::ascii;

    using boost::spirit::utree;
    using boost::spirit::utree_type;
    using boost::spirit::info;

    namespace detail
    {
      bool is_list_node ( utree const& u )
      {
        return u.which() == utree_type::list_type;
      }

    }

    template<typename Out>
      struct print_info
      {
        typedef boost::spirit::utf8_string string;

        print_info ( Out& out ) : out ( out ), first( true ) {}

        void element ( string const& tag, string const& value, int ) const
        {
          if (!first)
          {
            out << ' ';
            first = false;
          }

          if ( value == "" )
            out << tag;
          else
            out << "\"" << value << '"';
        }

        Out& out;
        mutable bool first;

      };

    struct expected_component : std::exception
    {
      std::string msg;

      expected_component ( std::string const& source, std::size_t line, info const& w)
      {
        using boost::spirit::basic_info_walker;

        std::ostringstream oss;
        oss << "(exception \"" << source << "\" ";

        if ( line == -1 )
          oss << -1;
        else
          oss << line;

        oss << " '(expected_component (";

        print_info < std::ostringstream > pr ( oss );
        basic_info_walker < print_info < std::ostringstream > > walker ( pr, w.tag, 0 );

        boost::apply_visitor ( walker, w.value );

        oss << ")))";

        msg = oss.str();
      }

      virtual ~expected_component() throw() {}

      virtual char const* what() const throw()
      {
        return msg.c_str();
      }
    };

    template<typename Iterator>
      struct error_handler
      {
        template<typename, typename, typename, typename >
          struct result
          {
            typedef void type;
          };

        error_handler ( ) {}

        void operator() (Iterator first, Iterator last, Iterator err_pos, info const& what ) const
        {
          using boost::spirit::get_line;
          Iterator eol = err_pos;
          std::size_t line = get_line (err_pos);
        }
      };

    template<typename Iterator>
      struct whitespace : qi::grammar < Iterator >
    {
      qi::rule<Iterator> start;

      whitespace() : whitespace::base_type ( start )
      {
        using standard::space;
        using standard::char_;
        using qi::eol;

        start = space | ( ';' >> *(char_ - eol) >> eol );
      }

    };

    template<typename Iterator, typename Evaluator, typename ErrorHandler = error_handler<Iterator> >
    struct parser : qi::grammar < Iterator, utree::list_type(), whitespace<Iterator> >
    {
      qi::rule<Iterator, utree::list_type(), whitespace < Iterator > > start;
      qi::rule<Iterator, utree(), whitespace < Iterator > > numeral, sexpr;
      qi::rule<Iterator, boost::spirit::utf8_symbol_type(), whitespace < Iterator > > command_name;
      qi::rule<Iterator, boost::spirit::utf8_string_type(), whitespace < Iterator > > symbol;
      qi::rule<Iterator, utree::list_type(), whitespace < Iterator> > command;
      qi::rule<Iterator > end_of_word;

      phoenix::function<ErrorHandler> const error;
      phoenix::function<Evaluator> const evaluate;

      parser ( Evaluator& evaluator ) : parser::base_type ( start ), evaluate ( evaluator ), error(ErrorHandler()), evaluator ( evaluator )
      {
        using standard::char_;
        using qi::unused_type;
        using qi::lexeme;
        using qi::hex;
        using qi::int_;
        using qi::oct;
        using qi::no_case;
        using qi::real_parser;
        using qi::uint_parser;
        using qi::bool_parser;
        using qi::on_error;
        using qi::fail;
        using qi::int_;
        using qi::lit;
        using qi::_val;
        using qi::_1;
        using qi::_2;
        using qi::_3;
        using qi::_4;
        using ascii::digit;
        using ascii::graph;
        using ascii::alpha;
        using qi::debug;

        start %= *( command ); // [ evaluate ( _val ) ] );

        command %= '(' >> command_name >> *sexpr >> ')';

        sexpr %= '(' >> *sexpr >> ')' | symbol | numeral;

        symbol %= lexeme [ +(qi::char_ -end_of_word ) ];

        numeral %= qi::uint_;

        command_name %= lexeme [ +(char_ - end_of_word ) ];

        end_of_word %= qi::space | char_(")");

        start.name ( "start" );
        command.name ( "command" ) ;
        sexpr.name ("s-expr" );
        symbol.name ( "symbol" );
        numeral.name ( "numeral" );
        command_name.name ( "command_name" );

#if 0
        debug ( start);
        debug ( command );
        debug ( sexpr );
        debug ( symbol );
        debug ( numeral );
        debug ( command_name );
#endif
      }

      Evaluator& evaluator;
    };

    template<typename Evaluator>
      class SMT2Parser
      {
        public:
          SMT2Parser ( Evaluator& evaluator )
          : evaluator ( evaluator )
        {
        }

          bool parse ( std::istream& instream, boost::spirit::utree::list_type& ast )
          {
            if ( !instream.good() )
            {
              return false;
            }

            instream.unsetf ( std::ios::skipws );

            spirit::istream_iterator begin(instream);
            spirit::istream_iterator end;

            parser<spirit::istream_iterator, Evaluator> p ( evaluator );
            whitespace<spirit::istream_iterator> ws;

            bool r = phrase_parse ( begin, end, p, ws, ast );

            if ( !r )
            {
              std::cout << "Not r " << std::endl;
            }

            if ( begin != end )
            {
              std::cout << "begin != end" << std::endl;
            }

            if ( r && begin == end )
            {
              return true;
            }
            else
            {
              std::cerr << "Parsing failed." << std::endl;
              std::cout << "Stop at:" << std::string ( begin, end ) << std::endl;
              return false;
            }

            return r;

          }

        private:
          Evaluator&                       evaluator;
      };
  }
}
<commit_msg>removed incomplete error handling from SMT2Parser<commit_after>#pragma once
#include <boost/spirit/include/support_utree.hpp>
#include <boost/spirit/include/qi.hpp>
#include <istream>

namespace metaSMT {
  namespace smt2 {
    namespace spirit   = boost::spirit;
    namespace qi       = boost::spirit::qi;
    namespace phoenix  = boost::phoenix;
    namespace standard = boost::spirit::standard;
    namespace ascii    = boost::spirit::ascii;

    namespace detail {
      template<typename Iterator>
      struct whitespace : qi::grammar< Iterator >  {
        whitespace()
          : whitespace::base_type(start) {
          using standard::space;
          using standard::char_;
          using qi::eol;

          start = space | ( ';' >> *(char_ - eol) >> eol );
        }

        qi::rule<Iterator> start;
      }; // whitespace

      template < typename Iterator, typename Evaluator >
      struct parser : qi::grammar< Iterator, spirit::utree::list_type(), whitespace<Iterator> > {
        parser( Evaluator &eval )
          : parser::base_type(start)
          , evaluate(eval)
          , evaluator(eval) {

          start %= *( command );

          command %= '(' >> command_name >> *sexpr >> ')';

          sexpr %= '(' >> *sexpr >> ')' | symbol | numeral;

          symbol %= qi::lexeme [ +(qi::char_ -end_of_word ) ];

          numeral %= qi::uint_;

          command_name %= qi::lexeme [ +(qi::char_ - end_of_word ) ];

          end_of_word %= qi::space | qi::char_(")");

          start.name( "start" );
          command.name( "command" ) ;
          sexpr.name( "s-expr" );
          symbol.name( "symbol" );
          numeral.name( "numeral" );
          command_name.name( "command_name" );

#if 0
          qi::debug ( start);
          qi::debug ( command );
          qi::debug ( sexpr );
          qi::debug ( symbol );
          qi::debug ( numeral );
          qi::debug ( command_name );
#endif
        }

        qi::rule<Iterator, spirit::utree::list_type(), whitespace< Iterator > > start;
        qi::rule<Iterator, spirit::utree(), whitespace< Iterator > > numeral, sexpr;
        qi::rule<Iterator, spirit::utf8_symbol_type(), whitespace< Iterator > > command_name;
        qi::rule<Iterator, spirit::utf8_string_type(), whitespace< Iterator > > symbol;
        qi::rule<Iterator, spirit::utree::list_type(), whitespace< Iterator> > command;
        qi::rule<Iterator > end_of_word;

        phoenix::function<Evaluator> const evaluate;
        Evaluator& evaluator;
      }; // parser
    } // detail

    template < typename Evaluator >
    class SMT2Parser {
    public:
      SMT2Parser( Evaluator &evaluator )
        : evaluator(evaluator)
      {}

      bool parse( std::istream &instream, spirit::utree::list_type &ast ) {
        if ( !instream.good() ) {
          return false;
        }

        instream.unsetf ( std::ios::skipws );

        spirit::istream_iterator begin(instream);
        spirit::istream_iterator end;

        detail::parser<spirit::istream_iterator, Evaluator> p( evaluator );
        detail::whitespace<spirit::istream_iterator> ws;
        bool r = phrase_parse( begin, end, p, ws, ast );
        if ( r && begin == end ) {
          return true;
        }
        else {
          std::cerr << "ERROR: Parsing failed!" << std::endl;
          std::cerr << "Stop at:" << std::string(begin, end) << std::endl;
          return false;
        }
      }

    private:
      Evaluator &evaluator;
    }; // SMT2Parser

  } // smt2
} // metaSMT
<|endoftext|>