<commit_before>#include "Server.hpp"

#ifdef __cplusplus
    #include <cstdlib>
#else
    #include <stdlib.h>
#endif

#include <iostream>
#include <cstdlib>  // for random
#include <cmath>    // for sin,cos in the server
#include <list>

#include "../functions.h"
#include "../Mech.h"
#include "../Projectile.h"
#include "../MovingObject.hpp"
#include "../types.h"
#include "../net/NetMessage.h"

namespace ap {
namespace server {
using namespace std;

Server::Server(uint32 port) :
  mScores(new ap::ScoreListing()),
  mPort(port)
{
    std::cout << "[SERVER] Created a server."<< std::endl;
}

void Server::start() {
    float dt; // delta-t between main loop iterations
    std::cout << "[SERVER] Started the server."<<std::endl;
    netdata = new net::NetData(net::NetData::SERVER, mPort);

    if( !netdata ) {
        std::cout << "[SERVER] Error initializing NetData, exiting!" << std::endl;
        return;
    }

    std::cout << "[SERVER] Serving "<< ap::net::netobjectprototypes().size()<<" types of objects."<<std::endl;

    netdata->insertObject(mScores);
    newticks = nextupdate = getTicks();

    while (1) {             // Server main loop
        netdata->receiveChanges();
        oldticks = newticks; newticks = getTicks();
        dt = float(newticks - oldticks)*0.001; // dt is in seconds

        updateObjects(dt, netdata);
        fireWeapons(newticks, netdata);
        detectCollisions(netdata);

        if (newticks >= nextupdate) {
            int changes = netdata->sendChanges();
            nextupdate = newticks + (1000/NetFPS); // 40 ms between updates, that's 25 network fps.
            cout << "\rData rate: "<<changes<<"      ";
            cout.flush();
        }                               // Seems to me that up to 100 is still okay!
        // TODO: Ensure that usleep is available on Mac/Windows as well!
        ap::mSleep(1);       // sleep even a little bit so that dt is never 0

        processEvents(netdata);
        if (!pendingClients.empty()) processPendingClients(netdata);
    } // Main loop
} // void Server::start()

void Server::processEvents(ap::net::NetData *pNetData) {
    ap::net::NetEvent event;
    while (pNetData->pollEvent(event))
    {
      switch (event.type)
      {
        case ap::net::NetData::EVENT_CONNECT:
        {
            cout << "[SERVER] Received a connection from "
                << uint2ipv4(pNetData->getUser(event.uid)->peer->address.host)
                <<", uid " << event.uid;
            pendingClients.insert(event.uid);   // Remember him until later!
                                                // If we add now, his NetUser is still uninitialized.
//            createNewConnection(event.uid, pNetData);
//            NetMessage connectMessage("!!! "+pNetData->getUser(event.uid)->nick+" has joined the game !!!");
//            pNetData->sendMessage(connectMessage);
            break;
        }
        case ap::net::NetData::EVENT_DISCONNECT:
        {
            cout << "[SERVER] Client "<<event.uid<<" disconnected."<<endl;
            while (Mech *pM = pNetData->eachObject<Mech *>(ap::OBJECT_TYPE_MECH)) {
                if (pM->uid == event.uid) pNetData->delObject(pM->id);
            }
            mScores->removeScore(event.uid);
            pNetData->alertObject(mScores->id);       // Refresh the score display to players
            NetMessage disconnectMessage("!!! "+pNetData->getPastUser(event.uid)->nick+" has disconnected !!!");
            pNetData->sendMessage(disconnectMessage);
            break;
        }
        default:
            break;
        }
    }
} // void Server::processEvents(netdata*)

void Server::processPendingClients(ap::net::NetData *pNetData) {
    std::set<uint32>::iterator i = pendingClients.begin();

    while (i != pendingClients.end()) {
        if (pNetData->getUser(*i)->initialized) {
            createNewConnection(*i, pNetData);
            NetMessage connectMessage("!!! "+pNetData->getUser(*i)->nick+" has joined the game !!!");
            pNetData->sendMessage(connectMessage);
            pendingClients.erase(i++);
        } else i++;
    }
}

void Server::updateObjects(float dt, ap::net::NetData* pNetData) const {

    while (NetObject *nop = pNetData->eachObject()) {
        if (nop->advance(dt) == -1) pNetData->delObject(nop->id);
    }

    // Copy colors from NetUser data to Mechs they own
    // TODO: think of some way of doing this only when necessary!
    while (ap::Mech *pMech = pNetData->eachObject<ap::Mech*>(ap::OBJECT_TYPE_MECH)) {
        if (pNetData->getUser(pMech->uid)) {
            pMech->color = pNetData->getUser(pMech->uid)->color;
            pNetData->alertObject(pMech->id);
        }

    }
} // void Server::updateObjects

void Server::fireWeapons(uint64 tstamp, ap::net::NetData *pNetData) {
    while (ap::Mech *mech = pNetData->eachObject<ap::Mech *>(ap::OBJECT_TYPE_MECH))
        if (mech->fireGun(tstamp)) weaponFired(pNetData, mech);
}

  void Server::weaponFired(ap::net::NetData *pNetData, ap::MovingObject *source) {
    Ogre::Vector3 facing = source->getFacing();

    int newid = pNetData->insertObject(new ap::Projectile(facing * 150.0f)); //150 is velocity
    ap::Projectile *bullet = pNetData->getObject<ap::Projectile *>(newid);
    bullet->setWorldBoundaries(1500.0f,0.0f,0.0f,1500.0f);
    bullet->setMaxSpeed(625.0f);
    bullet->setPosition(source->getPosition() + facing*70.0f + Ogre::Vector3(0.0f, 80.0f, 0.0f));
    bullet->setFacing(facing);
    bullet->uid = source->uid;
}

void Server::detectCollisions(ap::net::NetData *pNetData) const {

    while (ap::Mech *mech = pNetData->eachObject<ap::Mech *>(ap::OBJECT_TYPE_MECH))
      {
        while (ap::Projectile *proj = pNetData->eachObject<ap::Projectile *>(ap::OBJECT_TYPE_PROJECTILE))
	  {
            if (proj->testCollision(*mech)) {
                relocateSpawnedMech(mech);

                // update scores.
                ap::ScoreTuple projOwner;
                projOwner.uid = proj->uid;
                projOwner.kills = 1;
                projOwner.deaths = 0;
                projOwner.score = 1;
                ap::ScoreTuple mechOwner;
                mechOwner.uid = mech->uid;
                mechOwner.kills = 0;
                mechOwner.deaths = 1;
                mechOwner.score = -1;
                mScores->addScore(projOwner, false);
                mScores->addScore(mechOwner, false);
                mScores->setChanged();

                mScores->print();

                pNetData->delObject(proj->id);
                pNetData->alertObject(mScores->id);       // Refresh the score display to players
            }
	  }
      }
}

void Server::relocateSpawnedMech(ap::Mech *mech) const
{
    Ogre::Vector3 newPosition = Ogre::Vector3(rand()%1500, 0, rand()%1500);
    mech->setPosition(newPosition);
    mech->setVelocity(Ogre::Vector3::ZERO);
}

void Server::createNewConnection(ap::uint32 userId, ap::net::NetData *pNetData)
{
  ap::Mech *newAvatar = new ap::Mech();
  int newid = pNetData->insertObject(newAvatar);

  newAvatar->setWorldBoundaries(1500.0f,0.0f,0.0f,1500.0f);
  newAvatar->setMaxSpeed(35.0f);
  newAvatar->setFriction(8.0f);
  newAvatar->uid = userId;
  newAvatar->color = pNetData->getUser(userId)->color;
  relocateSpawnedMech(newAvatar);

  pNetData->getUser(userId)->setControlPtr(newAvatar->getControlPtr());

  // Add scores:
  ap::ScoreTuple newPlayer;
  newPlayer.uid = userId;
  newPlayer.nick = pNetData->getUser(userId)->nick;
  newPlayer.kills = 0;
  newPlayer.deaths = 0;
  newPlayer.score = 0;
  mScores->addScore(newPlayer, true);
  mScores->setChanged();
  pNetData->alertObject(mScores->id);       // Refresh the score display to players

  pNetData->sendChanges();
  pNetData->setAvatarID(userId, newid);
}

} // namespace server
} // namespace ap
<commit_msg>Fixed server's processPendingClients to not crash if a client disconnects while pending.<commit_after>#include "Server.hpp"

#ifdef __cplusplus
    #include <cstdlib>
#else
    #include <stdlib.h>
#endif

#include <iostream>
#include <cstdlib>  // for random
#include <cmath>    // for sin,cos in the server
#include <list>

#include "../functions.h"
#include "../Mech.h"
#include "../Projectile.h"
#include "../MovingObject.hpp"
#include "../types.h"
#include "../net/NetMessage.h"

namespace ap {
namespace server {
using namespace std;

Server::Server(uint32 port) :
  mScores(new ap::ScoreListing()),
  mPort(port)
{
    std::cout << "[SERVER] Created a server."<< std::endl;
}

void Server::start() {
    float dt; // delta-t between main loop iterations
    std::cout << "[SERVER] Started the server."<<std::endl;
    netdata = new net::NetData(net::NetData::SERVER, mPort);

    if( !netdata ) {
        std::cout << "[SERVER] Error initializing NetData, exiting!" << std::endl;
        return;
    }

    std::cout << "[SERVER] Serving "<< ap::net::netobjectprototypes().size()<<" types of objects."<<std::endl;

    netdata->insertObject(mScores);
    newticks = nextupdate = getTicks();

    while (1) {             // Server main loop
        netdata->receiveChanges();
        oldticks = newticks; newticks = getTicks();
        dt = float(newticks - oldticks)*0.001; // dt is in seconds

        updateObjects(dt, netdata);
        fireWeapons(newticks, netdata);
        detectCollisions(netdata);

        if (newticks >= nextupdate) {
            int changes = netdata->sendChanges();
            nextupdate = newticks + (1000/NetFPS); // 40 ms between updates, that's 25 network fps.
            cout << "\rData rate: "<<changes<<"      ";
            cout.flush();
        }                               // Seems to me that up to 100 is still okay!
        // TODO: Ensure that usleep is available on Mac/Windows as well!
        ap::mSleep(1);       // sleep even a little bit so that dt is never 0

        processEvents(netdata);
        if (!pendingClients.empty()) processPendingClients(netdata);
    } // Main loop
} // void Server::start()

void Server::processEvents(ap::net::NetData *pNetData) {
    ap::net::NetEvent event;
    while (pNetData->pollEvent(event))
    {
      switch (event.type)
      {
        case ap::net::NetData::EVENT_CONNECT:
        {
            cout << "[SERVER] Received a connection from "
                << uint2ipv4(pNetData->getUser(event.uid)->peer->address.host)
                <<", uid " << event.uid;
            pendingClients.insert(event.uid);   // Remember him until later!
                                                // If we add now, his NetUser is still uninitialized.
//            createNewConnection(event.uid, pNetData);
//            NetMessage connectMessage("!!! "+pNetData->getUser(event.uid)->nick+" has joined the game !!!");
//            pNetData->sendMessage(connectMessage);
            break;
        }
        case ap::net::NetData::EVENT_DISCONNECT:
        {
            cout << "[SERVER] Client "<<event.uid<<" disconnected."<<endl;
            while (Mech *pM = pNetData->eachObject<Mech *>(ap::OBJECT_TYPE_MECH)) {
                if (pM->uid == event.uid) pNetData->delObject(pM->id);
            }
            mScores->removeScore(event.uid);
            pNetData->alertObject(mScores->id);       // Refresh the score display to players
            NetMessage disconnectMessage("!!! "+pNetData->getPastUser(event.uid)->nick+" has disconnected !!!");
            pNetData->sendMessage(disconnectMessage);
            break;
        }
        default:
            break;
        }
    }
} // void Server::processEvents(netdata*)

void Server::processPendingClients(ap::net::NetData *pNetData) {
    std::set<uint32>::iterator i = pendingClients.begin();

    while (i != pendingClients.end()) {
        if (!pNetData->getUser(*i)) {
            pendingClients.erase(i++);      // The user disconnected before finishing connection
        } else if (pNetData->getUser(*i)->initialized) {
            createNewConnection(*i, pNetData);
            NetMessage connectMessage("!!! "+pNetData->getUser(*i)->nick+" has joined the game !!!");
            pNetData->sendMessage(connectMessage);
            pendingClients.erase(i++);
        } else i++;
    }
}

void Server::updateObjects(float dt, ap::net::NetData* pNetData) const {

    while (NetObject *nop = pNetData->eachObject()) {
        if (nop->advance(dt) == -1) pNetData->delObject(nop->id);
    }

    // Copy colors from NetUser data to Mechs they own
    // TODO: think of some way of doing this only when necessary!
    while (ap::Mech *pMech = pNetData->eachObject<ap::Mech*>(ap::OBJECT_TYPE_MECH)) {
        if (pNetData->getUser(pMech->uid)) {
            pMech->color = pNetData->getUser(pMech->uid)->color;
            pNetData->alertObject(pMech->id);
        }

    }
} // void Server::updateObjects

void Server::fireWeapons(uint64 tstamp, ap::net::NetData *pNetData) {
    while (ap::Mech *mech = pNetData->eachObject<ap::Mech *>(ap::OBJECT_TYPE_MECH))
        if (mech->fireGun(tstamp)) weaponFired(pNetData, mech);
}

  void Server::weaponFired(ap::net::NetData *pNetData, ap::MovingObject *source) {
    Ogre::Vector3 facing = source->getFacing();

    int newid = pNetData->insertObject(new ap::Projectile(facing * 150.0f)); //150 is velocity
    ap::Projectile *bullet = pNetData->getObject<ap::Projectile *>(newid);
    bullet->setWorldBoundaries(1500.0f,0.0f,0.0f,1500.0f);
    bullet->setMaxSpeed(625.0f);
    bullet->setPosition(source->getPosition() + facing*70.0f + Ogre::Vector3(0.0f, 80.0f, 0.0f));
    bullet->setFacing(facing);
    bullet->uid = source->uid;
}

void Server::detectCollisions(ap::net::NetData *pNetData) const {

    while (ap::Mech *mech = pNetData->eachObject<ap::Mech *>(ap::OBJECT_TYPE_MECH))
      {
        while (ap::Projectile *proj = pNetData->eachObject<ap::Projectile *>(ap::OBJECT_TYPE_PROJECTILE))
	  {
            if (proj->testCollision(*mech)) {
                relocateSpawnedMech(mech);

                // update scores.
                ap::ScoreTuple projOwner;
                projOwner.uid = proj->uid;
                projOwner.kills = 1;
                projOwner.deaths = 0;
                projOwner.score = 1;
                ap::ScoreTuple mechOwner;
                mechOwner.uid = mech->uid;
                mechOwner.kills = 0;
                mechOwner.deaths = 1;
                mechOwner.score = -1;
                mScores->addScore(projOwner, false);
                mScores->addScore(mechOwner, false);
                mScores->setChanged();

                mScores->print();

                pNetData->delObject(proj->id);
                pNetData->alertObject(mScores->id);       // Refresh the score display to players
            }
	  }
      }
}

void Server::relocateSpawnedMech(ap::Mech *mech) const
{
    Ogre::Vector3 newPosition = Ogre::Vector3(rand()%1500, 0, rand()%1500);
    mech->setPosition(newPosition);
    mech->setVelocity(Ogre::Vector3::ZERO);
}

void Server::createNewConnection(ap::uint32 userId, ap::net::NetData *pNetData)
{
  ap::Mech *newAvatar = new ap::Mech();
  int newid = pNetData->insertObject(newAvatar);

  newAvatar->setWorldBoundaries(1500.0f,0.0f,0.0f,1500.0f);
  newAvatar->setMaxSpeed(35.0f);
  newAvatar->setFriction(8.0f);
  newAvatar->uid = userId;
  newAvatar->color = pNetData->getUser(userId)->color;
  relocateSpawnedMech(newAvatar);

  pNetData->getUser(userId)->setControlPtr(newAvatar->getControlPtr());

  // Add scores:
  ap::ScoreTuple newPlayer;
  newPlayer.uid = userId;
  newPlayer.nick = pNetData->getUser(userId)->nick;
  newPlayer.kills = 0;
  newPlayer.deaths = 0;
  newPlayer.score = 0;
  mScores->addScore(newPlayer, true);
  mScores->setChanged();
  pNetData->alertObject(mScores->id);       // Refresh the score display to players

  pNetData->sendChanges();
  pNetData->setAvatarID(userId, newid);
}

} // namespace server
} // namespace ap
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestScenePicker.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//
// Test class vtkScenePicker.
// Move your mouse around the scene and the underlying actor should be
// printed on standard output.
//

#include "vtkSphereSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkCommand.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"
#include "vtkScenePicker.h"
#include "vtkVolume16Reader.h"
#include "vtkProperty.h"
#include "vtkPolyDataNormals.h"
#include "vtkContourFilter.h"
#include <vtkstd/map>
#include <vtkstd/string>

//-----------------------------------------------------------------------------
// Create a few actors first
vtkActor *CreateActor1( int argc, char *argv[], vtkRenderer * aRenderer )
{
  char* fname2 = vtkTestUtilities::ExpandDataFileName(
      argc, argv, "Data/headsq/quarter");
  vtkVolume16Reader *v16 = vtkVolume16Reader::New();
    v16->SetDataDimensions (64,64);
    v16->SetImageRange (1,93);
    v16->SetDataByteOrderToLittleEndian();
    v16->SetFilePrefix (fname2);
    v16->SetDataSpacing (3.2, 3.2, 1.5);

  // An isosurface, or contour value of 500 is known to correspond to the
  // skin of the patient. Once generated, a vtkPolyDataNormals filter is
  // is used to create normals for smooth surface shading during rendering.
  vtkContourFilter *skinExtractor = vtkContourFilter::New();
    skinExtractor->SetInputConnection(v16->GetOutputPort());
    skinExtractor->SetValue(0, 500);
  vtkPolyDataNormals *skinNormals = vtkPolyDataNormals::New();
    skinNormals->SetInputConnection(skinExtractor->GetOutputPort());
    skinNormals->SetFeatureAngle(60.0);
  vtkPolyDataMapper *skinMapper = vtkPolyDataMapper::New();
    skinMapper->SetInputConnection(skinNormals->GetOutputPort());
    skinMapper->ScalarVisibilityOff();
  vtkActor *skin = vtkActor::New();
    skin->SetMapper(skinMapper);
    skin->GetProperty()->SetColor(0.95,0.75,0.75);

  aRenderer->AddActor(skin);

  v16->Delete();
  skinExtractor->Delete();
  skinNormals->Delete();
  skinMapper->Delete();
  skin->Delete();
  return skin;
}

//-----------------------------------------------------------------------------
// Create a few actors first
vtkActor * CreateActor2( int vtkNotUsed(argc), char **vtkNotUsed(argv), vtkRenderer * ren )
{
  vtkSphereSource *ss = vtkSphereSource::New();
  ss->SetThetaResolution(30);
  ss->SetPhiResolution(30);
  ss->SetRadius(150.0);
  vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
  mapper->SetInput(ss->GetOutput());
  vtkActor *actor = vtkActor::New();
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(0.0,1.0,0.0);
  ren->AddActor(actor);
  ss->Delete();
  mapper->Delete();
  actor->Delete();
  return actor;
}

//-----------------------------------------------------------------------------
// Command to write out picked actors during mouse over.
class TestScenePickerCommand : public vtkCommand
{
public:
  vtkScenePicker * m_Picker;
  static TestScenePickerCommand *New()
    {
    return new TestScenePickerCommand;
    }

  virtual void Execute(vtkObject *caller, unsigned long vtkNotUsed(eventId), void* vtkNotUsed(callData))
    {
    vtkRenderWindowInteractor * iren = reinterpret_cast<
      vtkRenderWindowInteractor *>(caller);
    int e[2];
    iren->GetEventPosition(e);
    cout << "DisplayPosition : (" << e[0] << "," << e[1] << ")"
         << " Prop: "     << m_ActorDescription[m_Picker->GetViewProp(e)].c_str();
         << " CellId: "   << m_Picker->GetCellId(e)
         << " VertexId: " << m_Picker->GetVertexId(e)
         << endl;
    }

  void SetActorDescription( vtkProp *a, vtkstd::string s )
    {
    this->m_ActorDescription[a] = s;
    }
  vtkstd::map< vtkProp *, vtkstd::string > m_ActorDescription;

protected:
  TestScenePickerCommand() { this->SetActorDescription((vtkActor*)NULL, "None"); }
  virtual ~TestScenePickerCommand() {}
};

//-----------------------------------------------------------------------------
int TestScenePicker(int argc, char* argv[])
{
  vtkRenderer *ren = vtkRenderer::New();
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();

  renWin->AddRenderer(ren);
  iren->SetRenderWindow(renWin);
  ren->SetBackground(0.0, 0.0, 0.0);
  renWin->SetSize(300, 300);

  // Here comes the scene picker stuff. [ Just 2 lines ]
  vtkScenePicker * picker = vtkScenePicker::New();
  picker->SetRenderer(ren);

  // Write some stuff for interactive stuff.
  TestScenePickerCommand * command =
    TestScenePickerCommand::New();
  command->m_Picker = picker;
  command->SetActorDescription( CreateActor1( argc, argv, ren ), "Head"   );
  command->SetActorDescription( CreateActor2( argc, argv, ren ), "Sphere" );
  iren->AddObserver(vtkCommand::MouseMoveEvent, command);

  renWin->Render();
  iren->Initialize();

  // Check if scene picking works.
  int retVal = EXIT_SUCCESS;
  int e[2] = {175, 215};
  if (command->m_ActorDescription[picker->GetViewProp(e)] != "Head" ||
      picker->GetCellId(e) != 50992)
    {
    retVal = EXIT_FAILURE;
    }

  for ( int i = 0; i < argc; ++i )
    {
    if ( ! strcmp( argv[i], "-I" ) )
      {
      iren->Start();
      }
    }

  // Cleanups
  command->Delete();
  picker->Delete();
  ren->Delete();
  renWin->Delete();
  iren->Delete();

  return retVal;
}
<commit_msg>COMP: fix typo in my last commit<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestScenePicker.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
//
// Test class vtkScenePicker.
// Move your mouse around the scene and the underlying actor should be
// printed on standard output.
//

#include "vtkSphereSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkCommand.h"
#include "vtkTestUtilities.h"
#include "vtkRegressionTestImage.h"
#include "vtkScenePicker.h"
#include "vtkVolume16Reader.h"
#include "vtkProperty.h"
#include "vtkPolyDataNormals.h"
#include "vtkContourFilter.h"
#include <vtkstd/map>
#include <vtkstd/string>

//-----------------------------------------------------------------------------
// Create a few actors first
vtkActor *CreateActor1( int argc, char *argv[], vtkRenderer * aRenderer )
{
  char* fname2 = vtkTestUtilities::ExpandDataFileName(
      argc, argv, "Data/headsq/quarter");
  vtkVolume16Reader *v16 = vtkVolume16Reader::New();
    v16->SetDataDimensions (64,64);
    v16->SetImageRange (1,93);
    v16->SetDataByteOrderToLittleEndian();
    v16->SetFilePrefix (fname2);
    v16->SetDataSpacing (3.2, 3.2, 1.5);

  // An isosurface, or contour value of 500 is known to correspond to the
  // skin of the patient. Once generated, a vtkPolyDataNormals filter is
  // is used to create normals for smooth surface shading during rendering.
  vtkContourFilter *skinExtractor = vtkContourFilter::New();
    skinExtractor->SetInputConnection(v16->GetOutputPort());
    skinExtractor->SetValue(0, 500);
  vtkPolyDataNormals *skinNormals = vtkPolyDataNormals::New();
    skinNormals->SetInputConnection(skinExtractor->GetOutputPort());
    skinNormals->SetFeatureAngle(60.0);
  vtkPolyDataMapper *skinMapper = vtkPolyDataMapper::New();
    skinMapper->SetInputConnection(skinNormals->GetOutputPort());
    skinMapper->ScalarVisibilityOff();
  vtkActor *skin = vtkActor::New();
    skin->SetMapper(skinMapper);
    skin->GetProperty()->SetColor(0.95,0.75,0.75);

  aRenderer->AddActor(skin);

  v16->Delete();
  skinExtractor->Delete();
  skinNormals->Delete();
  skinMapper->Delete();
  skin->Delete();
  return skin;
}

//-----------------------------------------------------------------------------
// Create a few actors first
vtkActor * CreateActor2( int vtkNotUsed(argc), char **vtkNotUsed(argv), vtkRenderer * ren )
{
  vtkSphereSource *ss = vtkSphereSource::New();
  ss->SetThetaResolution(30);
  ss->SetPhiResolution(30);
  ss->SetRadius(150.0);
  vtkPolyDataMapper *mapper = vtkPolyDataMapper::New();
  mapper->SetInput(ss->GetOutput());
  vtkActor *actor = vtkActor::New();
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(0.0,1.0,0.0);
  ren->AddActor(actor);
  ss->Delete();
  mapper->Delete();
  actor->Delete();
  return actor;
}

//-----------------------------------------------------------------------------
// Command to write out picked actors during mouse over.
class TestScenePickerCommand : public vtkCommand
{
public:
  vtkScenePicker * m_Picker;
  static TestScenePickerCommand *New()
    {
    return new TestScenePickerCommand;
    }

  virtual void Execute(vtkObject *caller, unsigned long vtkNotUsed(eventId), void* vtkNotUsed(callData))
    {
    vtkRenderWindowInteractor * iren = reinterpret_cast<
      vtkRenderWindowInteractor *>(caller);
    int e[2];
    iren->GetEventPosition(e);
    cout << "DisplayPosition : (" << e[0] << "," << e[1] << ")"
         << " Prop: "     << m_ActorDescription[m_Picker->GetViewProp(e)].c_str()
         << " CellId: "   << m_Picker->GetCellId(e)
         << " VertexId: " << m_Picker->GetVertexId(e)
         << endl;
    }

  void SetActorDescription( vtkProp *a, vtkstd::string s )
    {
    this->m_ActorDescription[a] = s;
    }
  vtkstd::map< vtkProp *, vtkstd::string > m_ActorDescription;

protected:
  TestScenePickerCommand() { this->SetActorDescription((vtkActor*)NULL, "None"); }
  virtual ~TestScenePickerCommand() {}
};

//-----------------------------------------------------------------------------
int TestScenePicker(int argc, char* argv[])
{
  vtkRenderer *ren = vtkRenderer::New();
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();

  renWin->AddRenderer(ren);
  iren->SetRenderWindow(renWin);
  ren->SetBackground(0.0, 0.0, 0.0);
  renWin->SetSize(300, 300);

  // Here comes the scene picker stuff. [ Just 2 lines ]
  vtkScenePicker * picker = vtkScenePicker::New();
  picker->SetRenderer(ren);

  // Write some stuff for interactive stuff.
  TestScenePickerCommand * command =
    TestScenePickerCommand::New();
  command->m_Picker = picker;
  command->SetActorDescription( CreateActor1( argc, argv, ren ), "Head"   );
  command->SetActorDescription( CreateActor2( argc, argv, ren ), "Sphere" );
  iren->AddObserver(vtkCommand::MouseMoveEvent, command);

  renWin->Render();
  iren->Initialize();

  // Check if scene picking works.
  int retVal = EXIT_SUCCESS;
  int e[2] = {175, 215};
  if (command->m_ActorDescription[picker->GetViewProp(e)] != "Head" ||
      picker->GetCellId(e) != 50992)
    {
    retVal = EXIT_FAILURE;
    }

  for ( int i = 0; i < argc; ++i )
    {
    if ( ! strcmp( argv[i], "-I" ) )
      {
      iren->Start();
      }
    }

  // Cleanups
  command->Delete();
  picker->Delete();
  ren->Delete();
  renWin->Delete();
  iren->Delete();

  return retVal;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "BBE/SimpleFile.h"
#include <fstream>
#include <iostream>
#include <stdlib.h>

bbe::List<char> bbe::simpleFile::readBinaryFile(const bbe::String & filepath)
{
	//UNTESTED
	std::cout << filepath.getLength() << std::endl;
	std::cout << filepath.getRaw() << std::endl;
	for(std::size_t i = 0; i<filepath.getLength(); i++){
		std::cout << filepath.getRaw()[i] << std::endl;
	}

	std::cout << "Reading File: " << filepath << std::endl;
	std::ifstream file(filepath.getRaw(), std::ios::binary | std::ios::ate);

	if (file)
	{
		size_t fileSize = (size_t)file.tellg();
		bbe::List<char> fileBuffer;
		fileBuffer.resizeCapacityAndLength(fileSize);
		file.seekg(0);
		file.read(fileBuffer.getRaw(), fileSize);
		file.close();
		return fileBuffer;
	}
	else
	{
		throw std::runtime_error("Failed to open file!");
	}
}

void bbe::simpleFile::writeFloatArrToFile(const bbe::String & filePath, float * arr, size_t size)
{
	std::ofstream file(filePath.getRaw());
	for (std::size_t i = 0; i < size; i++)
	{
		file << arr[i] << "\n";
	}
	file.close();
}
<commit_msg>Stable again! Reverted simpleFile to use old String class.<commit_after>#include "stdafx.h"
#include "BBE/SimpleFile.h"
#include <fstream>
#include <iostream>
#include <stdlib.h>

bbe::List<char> bbe::simpleFile::readBinaryFile(const bbe::String & filepath)
{
	//UNTESTED
	std::cout << filepath.getLength() << std::endl;
	std::cout << filepath.getRaw() << std::endl;
	for(std::size_t i = 0; i<filepath.getLength(); i++){
		std::cout << filepath.getRaw()[i] << std::endl;
	}

	wchar_t path_w[1024];
	char path[1024];
	memset(path_w, 0, 1024*sizeof(wchar_t));

	std::cout << "OLA!" << std::endl;
	if(filepath.getLength() >= sizeof(path) - 1)
	{
		throw std::runtime_error("Path too long!");
	}
	for(std::size_t i = 0; i<filepath.getLength(); i++)
	{
		std::cout << "OLA!" << std::endl;
		path_w[i] = filepath.getRaw()[i];
	}

	std::cout << "OLA!" << std::endl;
	std::size_t length = wcstombs(path, path_w, sizeof(path));
	if(length >= sizeof(path) - 1)
	{
		throw std::runtime_error("Path too long!");
	}
	std::cout << "Reading File: " << path << std::endl;
	std::ifstream file(path, std::ios::binary | std::ios::ate);

	if (file)
	{
		size_t fileSize = (size_t)file.tellg();
		bbe::List<char> fileBuffer;
		fileBuffer.resizeCapacityAndLength(fileSize);
		file.seekg(0);
		file.read(fileBuffer.getRaw(), fileSize);
		file.close();
		return fileBuffer;
	}
	else
	{
		throw std::runtime_error("Failed to open file!");
	}
}

void bbe::simpleFile::writeFloatArrToFile(const bbe::String & filePath, float * arr, size_t size)
{
	char path[1024];
	std::size_t length = wcstombs(path, filePath.getRaw(), sizeof(path));
	if(length >= sizeof(path) - 1)
	{
		throw std::runtime_error("Path too long!");
	}
	std::ofstream file(path);
	for (std::size_t i = 0; i < size; i++)
	{
		file << arr[i] << "\n";
	}
	file.close();
}
<|endoftext|>


<commit_before>/*
 open source routing machine
 Copyright (C) Dennis Luxen, others 2010

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU AFFERO General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 any later version.

 This program 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 Affero General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "DescriptionFactory.h"

DescriptionFactory::DescriptionFactory() { }

DescriptionFactory::~DescriptionFactory() { }

double DescriptionFactory::GetAzimuth(const _Coordinate& A, const _Coordinate& B) const {
    double lonDiff = (A.lon-B.lon)/100000.;
    double angle = atan2(sin(lonDiff)*cos(B.lat/100000.),
            cos(A.lat/100000.)*sin(B.lat/100000.)-sin(A.lat/100000.)*cos(B.lat/100000.)*cos(lonDiff));
    angle*=180/M_PI;
    while(angle < 0)
        angle += 360;

    return angle;
}

void DescriptionFactory::SetStartSegment(const PhantomNode & _startPhantom) {
    startPhantom = _startPhantom;
    AppendSegment(_startPhantom.location, _PathData(0, _startPhantom.nodeBasedEdgeNameID, 10, _startPhantom.weight1));
}

void DescriptionFactory::SetEndSegment(const PhantomNode & _targetPhantom) {
    targetPhantom = _targetPhantom;
    pathDescription.push_back(SegmentInformation(_targetPhantom.location, _targetPhantom.nodeBasedEdgeNameID, 0, _targetPhantom.weight1, 0, true) );
}

void DescriptionFactory::AppendSegment(const _Coordinate & coordinate, const _PathData & data ) {
    pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) );
}

void DescriptionFactory::AppendEncodedPolylineString(std::string & output, bool isEncoded) {
    if(isEncoded)
        pc.printEncodedString(pathDescription, output);
    else
        pc.printUnencodedString(pathDescription, output);
}

void DescriptionFactory::AppendEncodedPolylineString(std::string &output) {
    pc.printEncodedString(pathDescription, output);
}

void DescriptionFactory::AppendUnencodedPolylineString(std::string &output) {
    pc.printUnencodedString(pathDescription, output);
}

void DescriptionFactory::Run(const unsigned zoomLevel, const unsigned duration) {

    if(0 == pathDescription.size())
        return;

    unsigned entireLength = 0;
    /** starts at index 1 */
    pathDescription[0].length = 0;
    for(unsigned i = 1; i < pathDescription.size(); ++i) {
        pathDescription[i].length = ApproximateDistance(pathDescription[i-1].location, pathDescription[i].location);
    }

    unsigned lengthOfSegment = 0;
    unsigned durationOfSegment = 0;
    unsigned indexOfSegmentBegin = 0;

    for(unsigned i = 1; i < pathDescription.size(); ++i) {
        entireLength += pathDescription[i].length;
        lengthOfSegment += pathDescription[i].length;
        durationOfSegment += pathDescription[i].duration;
        pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
        pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
        if(pathDescription[i].turnInstruction != 0) {
            //INFO("Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID);
            assert(pathDescription[i].necessary);
            lengthOfSegment = 0;
            durationOfSegment = 0;
            indexOfSegmentBegin = i;
        }
    }

    //Post-processing to remove empty or nearly empty path segments
    if(0. == startPhantom.ratio || 0 == pathDescription[0].length) {
        if(pathDescription.size() > 2)
            pathDescription.erase(pathDescription.begin());
        pathDescription[0].turnInstruction = TurnInstructions.HeadOn;
        pathDescription[0].necessary = true;
        startPhantom.nodeBasedEdgeNameID = pathDescription[0].nameID;
    } else {
        pathDescription[0].duration *= startPhantom.ratio;
    }
    if(1. == targetPhantom.ratio || 0 == pathDescription.back().length) {
        if(pathDescription.size() > 2)
            pathDescription.pop_back();
        pathDescription.back().necessary = true;
        pathDescription.back().turnInstruction = TurnInstructions.NoTurn;
        targetPhantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID;
//        INFO("Deleting last turn instruction");
    } else {
        pathDescription[indexOfSegmentBegin].duration *= (1.-targetPhantom.ratio);
    }

    //Generalize poly line
    dp.Run(pathDescription, zoomLevel);

    //fix what needs to be fixed else
    for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
        if(pathDescription[i].necessary) {
            int angle = 100*GetAzimuth(pathDescription[i].location, pathDescription[i+1].location);
            pathDescription[i].bearing = angle/100.;
        }
    }

    BuildRouteSummary(entireLength, duration);
    return;
}

void DescriptionFactory::BuildRouteSummary(const unsigned distance, const unsigned time) {
    summary.startName = startPhantom.nodeBasedEdgeNameID;
    summary.destName = targetPhantom.nodeBasedEdgeNameID;
    summary.BuildDurationAndLengthStrings(distance, time);
}
<commit_msg>Fixes test cucumber --tags @basic:63 and issue #105<commit_after>/*
 open source routing machine
 Copyright (C) Dennis Luxen, others 2010

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU AFFERO General Public License as published by
 the Free Software Foundation; either version 3 of the License, or
 any later version.

 This program 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 Affero General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "DescriptionFactory.h"

DescriptionFactory::DescriptionFactory() { }

DescriptionFactory::~DescriptionFactory() { }

double DescriptionFactory::GetAzimuth(const _Coordinate& A, const _Coordinate& B) const {
    double lonDiff = (A.lon-B.lon)/100000.;
    double angle = atan2(sin(lonDiff)*cos(B.lat/100000.),
            cos(A.lat/100000.)*sin(B.lat/100000.)-sin(A.lat/100000.)*cos(B.lat/100000.)*cos(lonDiff));
    angle*=180/M_PI;
    while(angle < 0)
        angle += 360;

    return angle;
}

void DescriptionFactory::SetStartSegment(const PhantomNode & _startPhantom) {
    startPhantom = _startPhantom;
    AppendSegment(_startPhantom.location, _PathData(0, _startPhantom.nodeBasedEdgeNameID, 10, _startPhantom.weight1));
}

void DescriptionFactory::SetEndSegment(const PhantomNode & _targetPhantom) {
    targetPhantom = _targetPhantom;
    pathDescription.push_back(SegmentInformation(_targetPhantom.location, _targetPhantom.nodeBasedEdgeNameID, 0, _targetPhantom.weight1, 0, true) );
}

void DescriptionFactory::AppendSegment(const _Coordinate & coordinate, const _PathData & data ) {
    pathDescription.push_back(SegmentInformation(coordinate, data.nameID, 0, data.durationOfSegment, data.turnInstruction) );
}

void DescriptionFactory::AppendEncodedPolylineString(std::string & output, bool isEncoded) {
    if(isEncoded)
        pc.printEncodedString(pathDescription, output);
    else
        pc.printUnencodedString(pathDescription, output);
}

void DescriptionFactory::AppendEncodedPolylineString(std::string &output) {
    pc.printEncodedString(pathDescription, output);
}

void DescriptionFactory::AppendUnencodedPolylineString(std::string &output) {
    pc.printUnencodedString(pathDescription, output);
}

void DescriptionFactory::Run(const unsigned zoomLevel, const unsigned duration) {

    if(0 == pathDescription.size())
        return;

    unsigned entireLength = 0;
    /** starts at index 1 */
    pathDescription[0].length = 0;
    for(unsigned i = 1; i < pathDescription.size(); ++i) {
        pathDescription[i].length = ApproximateDistance(pathDescription[i-1].location, pathDescription[i].location);
    }

    unsigned lengthOfSegment = 0;
    unsigned durationOfSegment = 0;
    unsigned indexOfSegmentBegin = 0;

    for(unsigned i = 1; i < pathDescription.size(); ++i) {
        entireLength += pathDescription[i].length;
        lengthOfSegment += pathDescription[i].length;
        durationOfSegment += pathDescription[i].duration;
        pathDescription[indexOfSegmentBegin].length = lengthOfSegment;
        pathDescription[indexOfSegmentBegin].duration = durationOfSegment;
        if(pathDescription[i].turnInstruction != 0) {
            //INFO("Turn after " << lengthOfSegment << "m into way with name id " << segment.nameID);
            assert(pathDescription[i].necessary);
            lengthOfSegment = 0;
            durationOfSegment = 0;
            indexOfSegmentBegin = i;
        }
    }
//    INFO("#segs: " << pathDescription.size());

    //Post-processing to remove empty or nearly empty path segments
    if(0 == pathDescription.back().length) {
//        INFO("#segs: " << pathDescription.size() << ", last ratio: " << targetPhantom.ratio << ", length: " << pathDescription.back().length);
        if(pathDescription.size() > 2){
            pathDescription.pop_back();
            pathDescription.back().necessary = true;
            pathDescription.back().turnInstruction = TurnInstructions.NoTurn;
            targetPhantom.nodeBasedEdgeNameID = (pathDescription.end()-2)->nameID;
//            INFO("Deleting last turn instruction");
        }
    } else {
        pathDescription[indexOfSegmentBegin].duration *= (1.-targetPhantom.ratio);
    }
    if(0 == pathDescription[0].length) {
        if(pathDescription.size() > 2) {
            pathDescription.erase(pathDescription.begin());
            pathDescription[0].turnInstruction = TurnInstructions.HeadOn;
            pathDescription[0].necessary = true;
            startPhantom.nodeBasedEdgeNameID = pathDescription[0].nameID;
//            INFO("Deleting first turn instruction, ratio: " << startPhantom.ratio << ", length: " << pathDescription[0].length);
        }
    } else {
        pathDescription[0].duration *= startPhantom.ratio;
    }

    //Generalize poly line
    dp.Run(pathDescription, zoomLevel);

    //fix what needs to be fixed else
    for(unsigned i = 0; i < pathDescription.size()-1 && pathDescription.size() >= 2; ++i){
        if(pathDescription[i].necessary) {
            int angle = 100*GetAzimuth(pathDescription[i].location, pathDescription[i+1].location);
            pathDescription[i].bearing = angle/100.;
        }
    }

    BuildRouteSummary(entireLength, duration);
    return;
}

void DescriptionFactory::BuildRouteSummary(const unsigned distance, const unsigned time) {
    summary.startName = startPhantom.nodeBasedEdgeNameID;
    summary.destName = targetPhantom.nodeBasedEdgeNameID;
    summary.BuildDurationAndLengthStrings(distance, time);
}
<|endoftext|>


<commit_before>//
// TextureUnitManager.cpp
//
// Originally written by RJ.
//
// Copyright (c) 2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "textureunitmanager.h"

//
// RJ's warning: NONE OF THIS IS THREAD SAFE!!!
//

vtTextureUnitManager::vtTextureUnitManager(void)
{
	m_bInitialised = false;
	m_pAllocationArray = NULL;
}

vtTextureUnitManager::~vtTextureUnitManager(void)
{
	if (NULL != m_pAllocationArray)
		delete m_pAllocationArray;
}

void vtTextureUnitManager::Initialise()
{
#if VTLIB_OSG
	osg::ref_ptr<osg::Texture::Extensions> pTextureExtensions = osg::Texture::getExtensions(0, true);
	m_iNumTextureUnits = pTextureExtensions->numTextureUnits();
#else
	// Assume four.
	m_iNumTextureUnits = 4;
#endif
	m_pAllocationArray = new bool[m_iNumTextureUnits];
	for (int i = 0; i < m_iNumTextureUnits; i++)
		m_pAllocationArray[i] = false;
	m_bInitialised = true;
}

int vtTextureUnitManager::ReserveTextureUnit()
{
	int iUnit = -1;
	if (!m_bInitialised)
		Initialise();
	for (int i = 0; i < m_iNumTextureUnits; i++)
	{
		if (m_pAllocationArray[i] == false)
		{
			m_pAllocationArray[i] = true;
			iUnit = i;
			break;
		}
	}
	return iUnit;
}

void vtTextureUnitManager::FreeTextureUnit(int iUnit)
{
	if (!m_bInitialised || (iUnit >= m_iNumTextureUnits))
		return;
	m_pAllocationArray[iUnit] = false;
}

<commit_msg>fixed case on include<commit_after>//
// TextureUnitManager.cpp
//
// Originally written by RJ.
//
// Copyright (c) 2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "TextureUnitManager.h"

//
// RJ's warning: NONE OF THIS IS THREAD SAFE!!!
//

vtTextureUnitManager::vtTextureUnitManager(void)
{
	m_bInitialised = false;
	m_pAllocationArray = NULL;
}

vtTextureUnitManager::~vtTextureUnitManager(void)
{
	if (NULL != m_pAllocationArray)
		delete m_pAllocationArray;
}

void vtTextureUnitManager::Initialise()
{
#if VTLIB_OSG
	osg::ref_ptr<osg::Texture::Extensions> pTextureExtensions = osg::Texture::getExtensions(0, true);
	m_iNumTextureUnits = pTextureExtensions->numTextureUnits();
#else
	// Assume four.
	m_iNumTextureUnits = 4;
#endif
	m_pAllocationArray = new bool[m_iNumTextureUnits];
	for (int i = 0; i < m_iNumTextureUnits; i++)
		m_pAllocationArray[i] = false;
	m_bInitialised = true;
}

int vtTextureUnitManager::ReserveTextureUnit()
{
	int iUnit = -1;
	if (!m_bInitialised)
		Initialise();
	for (int i = 0; i < m_iNumTextureUnits; i++)
	{
		if (m_pAllocationArray[i] == false)
		{
			m_pAllocationArray[i] = true;
			iUnit = i;
			break;
		}
	}
	return iUnit;
}

void vtTextureUnitManager::FreeTextureUnit(int iUnit)
{
	if (!m_bInitialised || (iUnit >= m_iNumTextureUnits))
		return;
	m_pAllocationArray[iUnit] = false;
}

<|endoftext|>


<commit_before>#include <string>
#include "sm-log-impl.h"

using namespace RCU;

namespace {
    /* No point allocating these individually or repeatedly---they're
       thread-private with a reasonably small maximum size (~10kB).

       WARNING: this assumes that transactions are pinned to their
       worker thread at least until pre-commit. If we ever implement
       DORA we'll have to be more clever, because transactions would
       change threads frequently, but for now it works great.
     */
    static __thread log_request tls_log_requests[sm_log_recover_mgr::MAX_BLOCK_RECORDS];

    /* Same goes for the sm_tx_log_impl object we give the caller, for that matter */
    static __thread char LOG_ALIGN tls_log_space[sizeof(sm_tx_log_impl)];
    static __thread bool tls_log_space_used = false;

    static sm_tx_log_impl*
    get_log_impl(sm_tx_log *x)
    {
        DIE_IF(x != (void*) tls_log_space,
               "sm_tx_log object can only be safely used by the thread that created it");
        DIE_IF(not tls_log_space_used, "Attempt to access unallocated memory");
        return get_impl(x);
    }
}

void

sm_tx_log::log_insert_index(FID f, OID o, fat_ptr ptr, int abits, fat_ptr *pdest) {
    get_log_impl(this)->add_payload_request(LOG_INSERT_INDEX, f, o, ptr, abits, pdest);
}

void
sm_tx_log::log_insert(FID f, OID o, fat_ptr ptr, int abits, fat_ptr *pdest) {
    get_log_impl(this)->add_payload_request(LOG_INSERT, f, o, ptr, abits, pdest);
}

void
sm_tx_log::log_update(FID f, OID o, fat_ptr ptr, int abits, fat_ptr *pdest) {
    get_log_impl(this)->add_payload_request(LOG_UPDATE, f, o, ptr, abits, pdest);
}

void
sm_tx_log::log_fid(FID f, const std::string &name)
{
    auto size = align_up(name.length()) + 1;
    auto size_code = encode_size_aligned(size);
    char *buf = (char *)malloc(size);
    memset(buf, '\0', size);
    memcpy(buf, (char *)name.c_str(), size-1);
    ASSERT(buf[size-1] == '\0');
    // only use the logrec's fid field, payload is name
    get_log_impl(this)->add_payload_request(LOG_FID, f, 0,
                            fat_ptr::make(buf, size_code),
                            DEFAULT_ALIGNMENT_BITS, NULL);
}

static
void
format_extra_ptr(log_request &req)
{
    auto p = req.extra_ptr = req.payload_ptr;
    req.payload_ptr = fat_ptr::make(&req.extra_ptr, p.size_code());
    req.payload_size = align_up(sizeof(req.extra_ptr));
}

static
log_request
make_log_request(log_record_type type, FID f, OID o, fat_ptr ptr, int abits) {
    log_request req;
    req.type = type;
    req.fid = f;
    req.oid = o;
    req.pdest = NULL;
    req.size_align_bits = abits;
    req.payload_ptr = ptr;
    req.payload_size = decode_size_aligned(ptr.size_code(), abits);
    return req;
}

void
sm_tx_log::log_relocate(FID f, OID o, fat_ptr ptr, int abits) {
    log_request req = make_log_request(LOG_RELOCATE, f, o, ptr, abits);
    format_extra_ptr(req);
    get_log_impl(this)->add_request(req);
}

void
sm_tx_log::log_delete(FID f, OID o) {
    log_request req = make_log_request(LOG_DELETE, f, o, NULL_PTR, 0);
    get_log_impl(this)->add_request(req);
}

LSN
sm_tx_log::get_clsn() {
    /* The caller already has a published CLSN, so if this tx still
       appears to not have a commit block it cannot possibly have an
       earlier CLSN. INVALID_LSN is an appropriate
       response. Otherwise, we have to race to finish installing a
       commit block.

       WARNING: Both this object and the commit block it points to
       might have been freed by the time a thread calls this function,
       so the caller must use an appropriate RCU transaction to avoid
       use-after-free bugs.
     */
    auto *impl = get_log_impl(this);
    if (auto *a = volatile_read(impl->_commit_block)) {
        a = impl->_install_commit_block(a);
        return a->block->next_lsn();
    }

    return INVALID_LSN;
}

LSN
sm_tx_log::pre_commit() {
    auto *impl = get_log_impl(this);
    if (not impl->_commit_block)
        impl->enter_precommit();
    return impl->_commit_block->block->next_lsn();
}

LSN
sm_tx_log::commit(LSN *pdest) {
    // make sure we acquired a commit block
    LSN clsn = pre_commit();

    auto *impl = get_log_impl(this);
    // now copy log record data
    impl->_populate_block(impl->_commit_block->block);

    if (pdest)
        *pdest = impl->_commit_block->block->lsn;

    impl->_log->_lm.release(impl->_commit_block);
    tls_log_space_used = false;
    return clsn;
}

void
sm_tx_log::discard() {
    auto *impl = get_log_impl(this);
    if (impl->_commit_block)
        impl->_log->_lm.discard(impl->_commit_block);
    tls_log_space_used = false;
}

void *
sm_tx_log_impl::alloc_storage() {
    DIE_IF(tls_log_space_used, "Only one transaction per worker thread is allowed");
    tls_log_space_used = true;
    return tls_log_space;
}

void
sm_tx_log_impl::add_payload_request(log_record_type type, FID f, OID o,
                                    fat_ptr p, int abits, fat_ptr *pdest)
{

    log_request req = make_log_request(type, f, o, p, abits);

    // 4GB+ for a single object is just too big. Punt.
    size_t psize = req.payload_size;
    THROW_IF(psize > UINT32_MAX, illegal_argument,
             "Log record payload must be less than 4GB (%zd requested, %zd bytes over limit)",
             psize, psize - UINT32_MAX);

    /* If the record's payload is too large (e.g. 8 of them would
       overflow the block), then embed the payload directly in the log
       (disguised as a skip record) and link the request to it.
     */
    if (sm_log_recover_mgr::MAX_BLOCK_SIZE < log_block::wrapped_size(8, 8*psize)) {
        log_allocation *a = _log->_lm.allocate(0, psize);
        DEFER_UNLESS(it_worked, _log->_lm.discard(a));

        log_block *b = a->block;
        ASSERT(b->nrec == 0);
        ASSERT(b->lsn != INVALID_LSN);
        ASSERT(b->records->type == LOG_SKIP);

        b->records->type = LOG_FAT_SKIP;
        b->records->size_code = p.size_code();
        b->records->size_align_bits = abits;

        uint32_t csum = b->body_checksum();
        b->checksum = adler32_memcpy(b->payload_begin(), p, psize, csum);

        // update the request to point to the external record
        req.type = (log_record_type) (req.type | LOG_FLAG_IS_EXT);
        p = req.payload_ptr = _log->lsn2ptr(b->payload_lsn(0), false);
        format_extra_ptr(req);
        if (pdest) {
            *pdest = p;
            pdest = NULL;
        }

        it_worked = true;
        _log->_lm.release(a);
    }

    // add to list
    req.pdest = pdest;
    add_request(req);
}

void sm_tx_log_impl::add_request(log_request const &req) {
    ASSERT (not _commit_block);
    auto new_nreq = _nreq+1;
    bool too_many = (new_nreq > sm_log_recover_mgr::MAX_BLOCK_RECORDS);
    auto new_payload_bytes = _payload_bytes + align_up(req.payload_size);
    ASSERT(is_aligned(new_payload_bytes));

    auto bsize = log_block::wrapped_size(new_nreq, new_payload_bytes);
    bool too_big = bsize > sm_log_recover_mgr::MAX_BLOCK_SIZE;
    if (too_many or too_big) {
        spill_overflow();
        return add_request(req);
    }

    tls_log_requests[_nreq] = req;
    _nreq = new_nreq;
    _payload_bytes = new_payload_bytes;
}

void
sm_tx_log_impl::_populate_block(log_block *b)
{
    size_t i = 0;
    uint32_t payload_end = 0;
    uint32_t csum_payload = ADLER32_CSUM_INIT;

    // link to previous overflow?
    if (_prev_overflow != INVALID_LSN) {
        log_record *r = &b->records[i++];
        r->type = LOG_OVERFLOW;
        r->size_code = INVALID_SIZE_CODE;
        r->size_align_bits = 0;
        r->payload_end = 0;
        r->next_lsn = _prev_overflow;
    }

    // process normal log records
    while (i < _nreq) {
        log_request *it = &tls_log_requests[i];
        DEFER(++i);

        log_record *r = &b->records[i];
        r->type = it->type;
        r->fid = it->fid;
        r->oid = it->oid;
        if (it->type & LOG_FLAG_HAS_PAYLOAD) {
            // fill out payload-related bits before calling payload_lsn()
            r->size_code = it->payload_ptr.size_code();
            r->size_align_bits = it->size_align_bits;

            // copy and checksum the payload
            if (it->pdest) {
                bool is_ext = it->type & LOG_FLAG_IS_EXT;
                *it->pdest = _log->lsn2ptr(b->payload_lsn(i), is_ext);
            }

            char *dest = b->payload_begin() + payload_end;
            csum_payload = adler32_memcpy(dest, it->payload_ptr, it->payload_size, csum_payload);
            payload_end += it->payload_size;
        }
        else {
            r->size_code = INVALID_SIZE_CODE;
            r->size_align_bits = -1;
        }
        r->payload_end = payload_end;
    }
    ASSERT (i == b->nrec);
    ASSERT (b->payload_end() == b->payload_begin() + payload_end);

    // finalize the checksum
    uint32_t csum = b->body_checksum();
    b->checksum = adler32_merge(csum, csum_payload, payload_end);
}

/* Transactions assign this value to their commit block as a signal of
   their intent to enter pre-commit. It should never be accessed or
   freed.
 */
static constexpr
log_allocation * const ENTERING_PRECOMMIT = (log_allocation*) 0x1;

/* Sometimes the log block overflows before a transaction completes
   and we have to spill and overflow block to the log.
 */
void sm_tx_log_impl::spill_overflow() {
    size_t inner_nreq = _nreq;
    size_t outer_nreq = 0;
    size_t pbytes = log_block::size(inner_nreq, _payload_bytes);

    log_allocation *a = _log->_lm.allocate(outer_nreq, pbytes);
    DEFER_UNLESS(it_worked, _log->_lm.discard(a));

    log_block *b = a->block;
    ASSERT(b->nrec == outer_nreq);
    ASSERT(b->lsn != INVALID_LSN);

    b->records->type = LOG_FAT_SKIP;

    auto *inner = (log_block*) b->payload(0);
    inner->nrec = inner_nreq;
    inner->lsn = b->payload_lsn(0);
    fill_skip_record(&inner->records[inner_nreq], INVALID_LSN, _payload_bytes, false);
    _populate_block(inner);

    uint32_t csum = b->body_checksum();
    b->checksum = adler32_merge(csum, inner->checksum, pbytes);
    _nreq = 1; // for the overflow LSN
    _prev_overflow = inner->lsn;
    _payload_bytes = 0;

    it_worked = true;
    _log->_lm.release(a);
}

/* This function is called by threads racing to install a commit
   block. The transaction calls it as part of the pre-commit protocol,
   and other threads call it to learn whether this transaction's CLSN
   precedes theirs or not (and if so, its value). It should never be
   called with a NULL _commit_block: the owner thread should signal
   ENTERING_PRECOMMIT, and other threads should only call this if they
   see a non-NULL value (which might be the signal, or might be an
   already-installed commit block).
 */
log_allocation *sm_tx_log_impl::_install_commit_block(log_allocation *a) {
    ASSERT(a);
    if (a == ENTERING_PRECOMMIT) {
        a = _log->_lm.allocate(_nreq, _payload_bytes);
        auto *tmp = __sync_val_compare_and_swap(&_commit_block, ENTERING_PRECOMMIT, a);
        if (tmp != ENTERING_PRECOMMIT) {
            _log->_lm.discard(a);
            a = tmp;
        }

        ASSERT(a != ENTERING_PRECOMMIT);
        ASSERT(a->block->nrec == _nreq);
        ASSERT(a->block->lsn != INVALID_LSN);
    }

    return a;
}

void sm_tx_log_impl::enter_precommit() {
    _commit_block = ENTERING_PRECOMMIT;
    auto *a = _install_commit_block(ENTERING_PRECOMMIT);
    DEFER_UNLESS(it_worked, _log->_lm.discard(a));

    // tzwang: avoid copying data here, commit() will do it
    //_populate_block(a->block);

    // leave these in place for late-comers to the race
    //_nreq = 0;
    //_prev_overflow = INVALID_LSN;
    //_payload_bytes = 0;

    it_worked = true;

    // do this late to give races plenty of time to show up
    ASSERT(_commit_block == a);
}
<commit_msg>Fix potential buf overflow in sm-tx-log.<commit_after>#include <string>
#include "sm-log-impl.h"

using namespace RCU;

namespace {
    /* No point allocating these individually or repeatedly---they're
       thread-private with a reasonably small maximum size (~10kB).

       WARNING: this assumes that transactions are pinned to their
       worker thread at least until pre-commit. If we ever implement
       DORA we'll have to be more clever, because transactions would
       change threads frequently, but for now it works great.
     */
    static __thread log_request tls_log_requests[sm_log_recover_mgr::MAX_BLOCK_RECORDS];

    /* Same goes for the sm_tx_log_impl object we give the caller, for that matter */
    static __thread char LOG_ALIGN tls_log_space[sizeof(sm_tx_log_impl)];
    static __thread bool tls_log_space_used = false;

    static sm_tx_log_impl*
    get_log_impl(sm_tx_log *x)
    {
        DIE_IF(x != (void*) tls_log_space,
               "sm_tx_log object can only be safely used by the thread that created it");
        DIE_IF(not tls_log_space_used, "Attempt to access unallocated memory");
        return get_impl(x);
    }
}

void

sm_tx_log::log_insert_index(FID f, OID o, fat_ptr ptr, int abits, fat_ptr *pdest) {
    get_log_impl(this)->add_payload_request(LOG_INSERT_INDEX, f, o, ptr, abits, pdest);
}

void
sm_tx_log::log_insert(FID f, OID o, fat_ptr ptr, int abits, fat_ptr *pdest) {
    get_log_impl(this)->add_payload_request(LOG_INSERT, f, o, ptr, abits, pdest);
}

void
sm_tx_log::log_update(FID f, OID o, fat_ptr ptr, int abits, fat_ptr *pdest) {
    get_log_impl(this)->add_payload_request(LOG_UPDATE, f, o, ptr, abits, pdest);
}

void
sm_tx_log::log_fid(FID f, const std::string &name)
{
    auto size = align_up(name.length() + 1);
    auto size_code = encode_size_aligned(size);
    char *buf = (char *)malloc(size);
    memset(buf, '\0', size);
    memcpy(buf, (char *)name.c_str(), name.length());
    ASSERT(buf[name.length()] == '\0');
    // only use the logrec's fid field, payload is name
    get_log_impl(this)->add_payload_request(LOG_FID, f, 0,
                            fat_ptr::make(buf, size_code),
                            DEFAULT_ALIGNMENT_BITS, NULL);
}

static
void
format_extra_ptr(log_request &req)
{
    auto p = req.extra_ptr = req.payload_ptr;
    req.payload_ptr = fat_ptr::make(&req.extra_ptr, p.size_code());
    req.payload_size = align_up(sizeof(req.extra_ptr));
}

static
log_request
make_log_request(log_record_type type, FID f, OID o, fat_ptr ptr, int abits) {
    log_request req;
    req.type = type;
    req.fid = f;
    req.oid = o;
    req.pdest = NULL;
    req.size_align_bits = abits;
    req.payload_ptr = ptr;
    req.payload_size = decode_size_aligned(ptr.size_code(), abits);
    return req;
}

void
sm_tx_log::log_relocate(FID f, OID o, fat_ptr ptr, int abits) {
    log_request req = make_log_request(LOG_RELOCATE, f, o, ptr, abits);
    format_extra_ptr(req);
    get_log_impl(this)->add_request(req);
}

void
sm_tx_log::log_delete(FID f, OID o) {
    log_request req = make_log_request(LOG_DELETE, f, o, NULL_PTR, 0);
    get_log_impl(this)->add_request(req);
}

LSN
sm_tx_log::get_clsn() {
    /* The caller already has a published CLSN, so if this tx still
       appears to not have a commit block it cannot possibly have an
       earlier CLSN. INVALID_LSN is an appropriate
       response. Otherwise, we have to race to finish installing a
       commit block.

       WARNING: Both this object and the commit block it points to
       might have been freed by the time a thread calls this function,
       so the caller must use an appropriate RCU transaction to avoid
       use-after-free bugs.
     */
    auto *impl = get_log_impl(this);
    if (auto *a = volatile_read(impl->_commit_block)) {
        a = impl->_install_commit_block(a);
        return a->block->next_lsn();
    }

    return INVALID_LSN;
}

LSN
sm_tx_log::pre_commit() {
    auto *impl = get_log_impl(this);
    if (not impl->_commit_block)
        impl->enter_precommit();
    return impl->_commit_block->block->next_lsn();
}

LSN
sm_tx_log::commit(LSN *pdest) {
    // make sure we acquired a commit block
    LSN clsn = pre_commit();

    auto *impl = get_log_impl(this);
    // now copy log record data
    impl->_populate_block(impl->_commit_block->block);

    if (pdest)
        *pdest = impl->_commit_block->block->lsn;

    impl->_log->_lm.release(impl->_commit_block);
    tls_log_space_used = false;
    return clsn;
}

void
sm_tx_log::discard() {
    auto *impl = get_log_impl(this);
    if (impl->_commit_block)
        impl->_log->_lm.discard(impl->_commit_block);
    tls_log_space_used = false;
}

void *
sm_tx_log_impl::alloc_storage() {
    DIE_IF(tls_log_space_used, "Only one transaction per worker thread is allowed");
    tls_log_space_used = true;
    return tls_log_space;
}

void
sm_tx_log_impl::add_payload_request(log_record_type type, FID f, OID o,
                                    fat_ptr p, int abits, fat_ptr *pdest)
{

    log_request req = make_log_request(type, f, o, p, abits);

    // 4GB+ for a single object is just too big. Punt.
    size_t psize = req.payload_size;
    THROW_IF(psize > UINT32_MAX, illegal_argument,
             "Log record payload must be less than 4GB (%zd requested, %zd bytes over limit)",
             psize, psize - UINT32_MAX);

    /* If the record's payload is too large (e.g. 8 of them would
       overflow the block), then embed the payload directly in the log
       (disguised as a skip record) and link the request to it.
     */
    if (sm_log_recover_mgr::MAX_BLOCK_SIZE < log_block::wrapped_size(8, 8*psize)) {
        log_allocation *a = _log->_lm.allocate(0, psize);
        DEFER_UNLESS(it_worked, _log->_lm.discard(a));

        log_block *b = a->block;
        ASSERT(b->nrec == 0);
        ASSERT(b->lsn != INVALID_LSN);
        ASSERT(b->records->type == LOG_SKIP);

        b->records->type = LOG_FAT_SKIP;
        b->records->size_code = p.size_code();
        b->records->size_align_bits = abits;

        uint32_t csum = b->body_checksum();
        b->checksum = adler32_memcpy(b->payload_begin(), p, psize, csum);

        // update the request to point to the external record
        req.type = (log_record_type) (req.type | LOG_FLAG_IS_EXT);
        p = req.payload_ptr = _log->lsn2ptr(b->payload_lsn(0), false);
        format_extra_ptr(req);
        if (pdest) {
            *pdest = p;
            pdest = NULL;
        }

        it_worked = true;
        _log->_lm.release(a);
    }

    // add to list
    req.pdest = pdest;
    add_request(req);
}

void sm_tx_log_impl::add_request(log_request const &req) {
    ASSERT (not _commit_block);
    auto new_nreq = _nreq+1;
    bool too_many = (new_nreq > sm_log_recover_mgr::MAX_BLOCK_RECORDS);
    auto new_payload_bytes = _payload_bytes + align_up(req.payload_size);
    ASSERT(is_aligned(new_payload_bytes));

    auto bsize = log_block::wrapped_size(new_nreq, new_payload_bytes);
    bool too_big = bsize > sm_log_recover_mgr::MAX_BLOCK_SIZE;
    if (too_many or too_big) {
        spill_overflow();
        return add_request(req);
    }

    tls_log_requests[_nreq] = req;
    _nreq = new_nreq;
    _payload_bytes = new_payload_bytes;
}

void
sm_tx_log_impl::_populate_block(log_block *b)
{
    size_t i = 0;
    uint32_t payload_end = 0;
    uint32_t csum_payload = ADLER32_CSUM_INIT;

    // link to previous overflow?
    if (_prev_overflow != INVALID_LSN) {
        log_record *r = &b->records[i++];
        r->type = LOG_OVERFLOW;
        r->size_code = INVALID_SIZE_CODE;
        r->size_align_bits = 0;
        r->payload_end = 0;
        r->next_lsn = _prev_overflow;
    }

    // process normal log records
    while (i < _nreq) {
        log_request *it = &tls_log_requests[i];
        DEFER(++i);

        log_record *r = &b->records[i];
        r->type = it->type;
        r->fid = it->fid;
        r->oid = it->oid;
        if (it->type & LOG_FLAG_HAS_PAYLOAD) {
            // fill out payload-related bits before calling payload_lsn()
            r->size_code = it->payload_ptr.size_code();
            r->size_align_bits = it->size_align_bits;

            // copy and checksum the payload
            if (it->pdest) {
                bool is_ext = it->type & LOG_FLAG_IS_EXT;
                *it->pdest = _log->lsn2ptr(b->payload_lsn(i), is_ext);
            }

            char *dest = b->payload_begin() + payload_end;
            csum_payload = adler32_memcpy(dest, it->payload_ptr, it->payload_size, csum_payload);
            payload_end += it->payload_size;
        }
        else {
            r->size_code = INVALID_SIZE_CODE;
            r->size_align_bits = -1;
        }
        r->payload_end = payload_end;
    }
    ASSERT (i == b->nrec);
    ASSERT (b->payload_end() == b->payload_begin() + payload_end);

    // finalize the checksum
    uint32_t csum = b->body_checksum();
    b->checksum = adler32_merge(csum, csum_payload, payload_end);
}

/* Transactions assign this value to their commit block as a signal of
   their intent to enter pre-commit. It should never be accessed or
   freed.
 */
static constexpr
log_allocation * const ENTERING_PRECOMMIT = (log_allocation*) 0x1;

/* Sometimes the log block overflows before a transaction completes
   and we have to spill and overflow block to the log.
 */
void sm_tx_log_impl::spill_overflow() {
    size_t inner_nreq = _nreq;
    size_t outer_nreq = 0;
    size_t pbytes = log_block::size(inner_nreq, _payload_bytes);

    log_allocation *a = _log->_lm.allocate(outer_nreq, pbytes);
    DEFER_UNLESS(it_worked, _log->_lm.discard(a));

    log_block *b = a->block;
    ASSERT(b->nrec == outer_nreq);
    ASSERT(b->lsn != INVALID_LSN);

    b->records->type = LOG_FAT_SKIP;

    auto *inner = (log_block*) b->payload(0);
    inner->nrec = inner_nreq;
    inner->lsn = b->payload_lsn(0);
    fill_skip_record(&inner->records[inner_nreq], INVALID_LSN, _payload_bytes, false);
    _populate_block(inner);

    uint32_t csum = b->body_checksum();
    b->checksum = adler32_merge(csum, inner->checksum, pbytes);
    _nreq = 1; // for the overflow LSN
    _prev_overflow = inner->lsn;
    _payload_bytes = 0;

    it_worked = true;
    _log->_lm.release(a);
}

/* This function is called by threads racing to install a commit
   block. The transaction calls it as part of the pre-commit protocol,
   and other threads call it to learn whether this transaction's CLSN
   precedes theirs or not (and if so, its value). It should never be
   called with a NULL _commit_block: the owner thread should signal
   ENTERING_PRECOMMIT, and other threads should only call this if they
   see a non-NULL value (which might be the signal, or might be an
   already-installed commit block).
 */
log_allocation *sm_tx_log_impl::_install_commit_block(log_allocation *a) {
    ASSERT(a);
    if (a == ENTERING_PRECOMMIT) {
        a = _log->_lm.allocate(_nreq, _payload_bytes);
        auto *tmp = __sync_val_compare_and_swap(&_commit_block, ENTERING_PRECOMMIT, a);
        if (tmp != ENTERING_PRECOMMIT) {
            _log->_lm.discard(a);
            a = tmp;
        }

        ASSERT(a != ENTERING_PRECOMMIT);
        ASSERT(a->block->nrec == _nreq);
        ASSERT(a->block->lsn != INVALID_LSN);
    }

    return a;
}

void sm_tx_log_impl::enter_precommit() {
    _commit_block = ENTERING_PRECOMMIT;
    auto *a = _install_commit_block(ENTERING_PRECOMMIT);
    DEFER_UNLESS(it_worked, _log->_lm.discard(a));

    // tzwang: avoid copying data here, commit() will do it
    //_populate_block(a->block);

    // leave these in place for late-comers to the race
    //_nreq = 0;
    //_prev_overflow = INVALID_LSN;
    //_payload_bytes = 0;

    it_worked = true;

    // do this late to give races plenty of time to show up
    ASSERT(_commit_block == a);
}
<|endoftext|>


<commit_before>/*
 * DynBetweenness.cpp
 *
 *  Created on: 29.07.2014
 *      Author: ebergamini
 */
#include <stack>
#include <queue>
#include <memory>

#include "../auxiliary/PrioQueue.h"
#include "DynBetweenness.h"
#include "../auxiliary/PrioQueue.h"
#include "../auxiliary/Log.h"
#include "../graph/SSSP.h"
#include "../graph/Dijkstra.h"
#include "../graph/BFS.h"

namespace NetworKit {
DynBetweenness::DynBetweenness(const Graph& G, bool storePredecessors) : Centrality(G, normalized),
maxDistance(G.upperNodeIdBound()),
npaths(G.upperNodeIdBound(), std::vector<count>(G.upperNodeIdBound())),
distances(G.upperNodeIdBound(), std::vector<edgeweight>(G.upperNodeIdBound())),
dependencies(G.upperNodeIdBound(),std::vector<double>(G.upperNodeIdBound(), 0.0)),
storePreds(storePredecessors) {

}

inline bool logically_equal(double a, double b, double error_factor=1.0)
{
  return a==b || std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*error_factor;
}

void DynBetweenness::run() {
    count z = G.upperNodeIdBound();
    scoreData.clear();
    scoreData.resize(z);
    npaths.clear();
    nPaths.resize(z);
    distances.clear();
    distance.resize(z);
    dependencies.clear();
    dependencies.resize(z);
    if (storePreds) {
        predecessors.clear();
        predecessors.resize(G.upperNodeIdBound());
        G.forNodes([&](node v){
            predecessors[v].resize(G.upperNodeIdBound());
        });
    }

    auto computeDependencies = [&](node s) {
        // run SSSP algorithm and keep track of everything
        std::unique_ptr<SSSP> sssp;
        if (G.isWeighted()) {
            sssp.reset(new Dijkstra(G, s, true, true));
        } else {
            sssp.reset(new BFS(G, s, true, true));
        }

        sssp->run();

        G.forNodes([&](node t){
            distances[s][t] = sssp->distance(t);
            npaths[s][t] = sssp->numberOfPaths(t);
            if (storePreds) {
                predecessors[s][t] = sssp->getPredecessors(t);
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::stack<node> stack = sssp->getStack();
        // set maxDistance to the distance of the furthest vertex
        maxDistance[s] = distances[s][stack.top()];
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp->getPredecessors(t)) {
                dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }
    };

    G.forNodes(computeDependencies);
}

void DynBetweenness::updateUnweighted(GraphEvent e) {
    G.forNodes([&] (node s){
        node u_l, u_h;
        if (distances[s][e.u] > distances[s][e.v]){
            u_l = e.u;
            u_h = e.v;
        } else {
            u_l = e.v;
            u_h = e.u;
        }
        edgeweight difference = distances[s][u_l] - distances[s][u_h];
        if (difference > 0) {
            std::vector<count> new_npaths(G.upperNodeIdBound());
            std::vector<edgeweight> new_dist(G.upperNodeIdBound());
            G.forNodes([&] (node v){
                new_npaths[v] = npaths[s][v];
                new_dist[v] = distances[s][v];
            });
            std::vector<double> new_dep(G.upperNodeIdBound(), 0.0);
            std::vector<int> touched(G.upperNodeIdBound(), 0);
            std::vector<std::queue<node>> l_queues(maxDistance[s]+1);
            std::queue<node> queue_BFS;
            queue_BFS.push(u_l);
            // one-level update
            if (difference == 1) {
                l_queues[distances[s][u_l]].push(u_l);
                if (storePreds)
                    predecessors[s][u_l].push_back(u_h);
                new_npaths[u_l] += npaths[s][u_h];
                touched[u_l] = -1;
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ", v);
                    queue_BFS.pop();
                    G.forNeighborsOf(v, [&](node w) {
                        if (new_dist[w] == new_dist[v]+1) {
                            if (touched[w] == 0) {
                                touched[w] = -1;
                                queue_BFS.push(w);
                                l_queues[new_dist[w]].push(w);
                            }
                            new_npaths[w] = new_npaths[w] - npaths[s][v] + new_npaths[v];
                        }
                    });
                }
            } else if (difference > 1) {
                new_dist[u_l] = distances[s][u_h] + 1;
                l_queues[new_dist[u_l]].push(u_l);
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ",v);
                    if (storePreds) {
                        predecessors[s][v].clear();
                    }
                    queue_BFS.pop();
                    touched[v] = -1;
                    new_npaths[v] = 0;
                    G.forNeighborsOf(v, [&] (node w){
                            if (new_dist[w] + 1 == new_dist[v]) {
                                new_npaths[v] += new_npaths[w];
                                if (storePreds) {
                                    predecessors[s][v].push_back(w);
                                }
                            }
                            if (new_dist[w] >= new_dist[v] && touched[w] == 0) {
                                if (new_dist[w] > new_dist[v])
                                    new_dist[w] = new_dist[v]+1;
                                touched[w] = -1;
                                l_queues[new_dist[w]].push(w);
                                queue_BFS.push(w);
                            }
                    });
                }
            }
            // dependencies accumulation
            DEBUG("Dependency accumulation");
            count level = maxDistance[s];
            while(level > 0) {
                while(!l_queues[level].empty()) {
                    node w = l_queues[level].front();
                    DEBUG("Node ",w);
                    l_queues[level].pop();
                    auto updateDependency = [&](node w, node v) {
                        if (new_dist[v] < new_dist[w]) {
                            if (touched[v] == 0) {
                                touched[v] = 1;
                                new_dep[v] = dependencies[s][v];
                                l_queues[level-1].push(v);
                            }
                            double new_contrib = double(new_npaths[v])/new_npaths[w]*(1+new_dep[w]);
                            new_dep[v] += new_contrib;
                            double old_contrib = double(npaths[s][v])/npaths[s][w]*(1+dependencies[s][w]);
                            if (touched[v] == 1 && (v != u_h or w!= u_l))
                                new_dep[v] -= old_contrib;
                            DEBUG("Parent ", v);
                        }
                    };
                    if (storePreds) {
                        for (node v : predecessors[s][w]) {
                            updateDependency(w, v);
                        }
                    }
                    else {
                        G.forNeighborsOf(w, [&](node v){
                            updateDependency(w, v);
                        });
                    }
                    if (w != s) {
                        scoreData[w] = scoreData[w] + new_dep[w] - dependencies[s][w];
                    }
                }
                level = level - 1;
            }
            // data structures update
            G.forNodes([&] (node r){
                distances[s][r] = new_dist[r];
                npaths[s][r] = new_npaths[r];
                if (touched[r] != 0)
                    dependencies[s][r] = new_dep[r];
            });
        }
/*

        BFS sssp(G, s, true, true);
        sssp.run();
        G.forNodes([&](node t){
            if(distances[s][t] != sssp.distance(t) || npaths[s][t] != sssp.numberOfPaths(t)) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DISTANCE: "<<distances[s][t]<<"  REAL DISTANCE: "<<sssp.distance(t)<<std::endl;
                std::cout<<"COMPUTED NUMBER OF PATHS: "<<npaths[s][t]<<"  REAL NUMBER OF PATHS: "<<sssp.numberOfPaths(t)<<std::endl;
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::vector<double> dep(G.upperNodeIdBound());
        std::stack<node> stack = sssp.getStack();
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp.getPredecessors(t)) {
                dep[p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dep[t]);
            }
        }

        G.forNodes([&](node t){
            if((dependencies[s][t]-dep[t]>0.000001 || dependencies[s][t]-dep[t]<-0.000001) && s!=t) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DEPENDENCY: "<<dependencies[s][t]<<"  REAL DEPENDENCY: "<<dep[t]<<std::endl;
            }
        });

*/

    });
}

void DynBetweenness::updateWeighted(GraphEvent e) {
    G.forNodes([&] (node s){
        scoreData[s] = 0.0;
    });
    G.forNodes([&] (node s){
        // update of distances and number of shortest paths
        Aux::PrioQueue<double, node> S(G.upperNodeIdBound());
        G.forNodes([&] (node t){
            auto updatePaths = [&](node u, node v, edgeweight w) {
                if (distances[s][t] == distances[s][u] + w + distances[v][t]){
                    npaths[s][t] = npaths[s][t] + npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v){
                            DEBUG("Adding predecessors from v to t to predecessors from s to t");
                            //predecessors[s][t].insert( predecessors[s][t].end(), predecessors[v][t].begin(), predecessors[v][t].end());
                            for (node pv : predecessors[v][t]) {
                                bool wasAlreadyPred = false;
                                for (node ps : predecessors[s][t]) {
                                    if (ps == pv)
                                        wasAlreadyPred = true;
                                }
                                if (!wasAlreadyPred)
                                    predecessors[s][t].push_back(pv);
                            }
                            DEBUG("Finished adding");
                        }
                        else {
                            DEBUG("Adding u to the predecessors of v");
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished adding");
                        }
                    }
                }
                if (distances[s][t] > distances[s][u] + w + distances[v][t]){
                    distances[s][t] = distances[s][u] + w + distances[v][t];
                    npaths[s][t] = npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v) {
                            DEBUG("Replacing predecessors from v to t with predecessors from s to t");
                            predecessors[s][t] = predecessors[v][t];
                            DEBUG("Finished replacing");
                        }
                        else {
                            DEBUG("Replacing old predecessors of v with u");
                            predecessors[s][t].clear();
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished replacing");
                        }
                    }
                }
            };
            if (s != t) {
                updatePaths(e.u, e.v, e.w);
                updatePaths(e.v, e.u, e.w);
                S.insert(-1*distances[s][t], t);
                dependencies[s][t] = 0.0;
            }
        });
        // dependency accumulation
        while (S.size() != 0) {
            // extract the node with the maximum distance
            node t = S.extractMin().second;
            if (storePreds) {
                DEBUG("Computing dependencies");
                for (node p : predecessors[s][t]) {
                    dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                }
            }
            else {
                G.forNeighborsOf(t, [&] (node p){
                    if (logically_equal(distances[s][t], distances[s][p] + G.weight(p, t))) {
                        dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                    }
                });
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }

    });

}

void DynBetweenness::update(GraphEvent e) {
    if (G.isWeighted())
        updateWeighted(e);
    else
        updateUnweighted(e);
}

} /* namespace NetworKit */
<commit_msg>inserted cleaning of structures at the beginning of the run method in dynbetweenness<commit_after>/*
 * DynBetweenness.cpp
 *
 *  Created on: 29.07.2014
 *      Author: ebergamini
 */
#include <stack>
#include <queue>
#include <memory>

#include "../auxiliary/PrioQueue.h"
#include "DynBetweenness.h"
#include "../auxiliary/PrioQueue.h"
#include "../auxiliary/Log.h"
#include "../graph/SSSP.h"
#include "../graph/Dijkstra.h"
#include "../graph/BFS.h"

namespace NetworKit {
DynBetweenness::DynBetweenness(const Graph& G, bool storePredecessors) : Centrality(G, normalized),
maxDistance(G.upperNodeIdBound()),
npaths(G.upperNodeIdBound(), std::vector<count>(G.upperNodeIdBound())),
distances(G.upperNodeIdBound(), std::vector<edgeweight>(G.upperNodeIdBound())),
dependencies(G.upperNodeIdBound(),std::vector<double>(G.upperNodeIdBound(), 0.0)),
storePreds(storePredecessors) {

}

inline bool logically_equal(double a, double b, double error_factor=1.0)
{
  return a==b || std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*error_factor;
}

void DynBetweenness::run() {
    count z = G.upperNodeIdBound();
    scoreData.clear();
    scoreData.resize(z);
    npaths.clear();
    npaths.resize(z);
    distances.clear();
    distances.resize(z);
    dependencies.clear();
    dependencies.resize(z);
    if (storePreds) {
        predecessors.clear();
        predecessors.resize(G.upperNodeIdBound());
        G.forNodes([&](node v){
            predecessors[v].resize(G.upperNodeIdBound());
        });
    }

    auto computeDependencies = [&](node s) {
        // run SSSP algorithm and keep track of everything
        std::unique_ptr<SSSP> sssp;
        if (G.isWeighted()) {
            sssp.reset(new Dijkstra(G, s, true, true));
        } else {
            sssp.reset(new BFS(G, s, true, true));
        }

        sssp->run();

        G.forNodes([&](node t){
            distances[s][t] = sssp->distance(t);
            npaths[s][t] = sssp->numberOfPaths(t);
            if (storePreds) {
                predecessors[s][t] = sssp->getPredecessors(t);
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::stack<node> stack = sssp->getStack();
        // set maxDistance to the distance of the furthest vertex
        maxDistance[s] = distances[s][stack.top()];
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp->getPredecessors(t)) {
                dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }
    };

    G.forNodes(computeDependencies);
}

void DynBetweenness::updateUnweighted(GraphEvent e) {
    G.forNodes([&] (node s){
        node u_l, u_h;
        if (distances[s][e.u] > distances[s][e.v]){
            u_l = e.u;
            u_h = e.v;
        } else {
            u_l = e.v;
            u_h = e.u;
        }
        edgeweight difference = distances[s][u_l] - distances[s][u_h];
        if (difference > 0) {
            std::vector<count> new_npaths(G.upperNodeIdBound());
            std::vector<edgeweight> new_dist(G.upperNodeIdBound());
            G.forNodes([&] (node v){
                new_npaths[v] = npaths[s][v];
                new_dist[v] = distances[s][v];
            });
            std::vector<double> new_dep(G.upperNodeIdBound(), 0.0);
            std::vector<int> touched(G.upperNodeIdBound(), 0);
            std::vector<std::queue<node>> l_queues(maxDistance[s]+1);
            std::queue<node> queue_BFS;
            queue_BFS.push(u_l);
            // one-level update
            if (difference == 1) {
                l_queues[distances[s][u_l]].push(u_l);
                if (storePreds)
                    predecessors[s][u_l].push_back(u_h);
                new_npaths[u_l] += npaths[s][u_h];
                touched[u_l] = -1;
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ", v);
                    queue_BFS.pop();
                    G.forNeighborsOf(v, [&](node w) {
                        if (new_dist[w] == new_dist[v]+1) {
                            if (touched[w] == 0) {
                                touched[w] = -1;
                                queue_BFS.push(w);
                                l_queues[new_dist[w]].push(w);
                            }
                            new_npaths[w] = new_npaths[w] - npaths[s][v] + new_npaths[v];
                        }
                    });
                }
            } else if (difference > 1) {
                new_dist[u_l] = distances[s][u_h] + 1;
                l_queues[new_dist[u_l]].push(u_l);
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ",v);
                    if (storePreds) {
                        predecessors[s][v].clear();
                    }
                    queue_BFS.pop();
                    touched[v] = -1;
                    new_npaths[v] = 0;
                    G.forNeighborsOf(v, [&] (node w){
                            if (new_dist[w] + 1 == new_dist[v]) {
                                new_npaths[v] += new_npaths[w];
                                if (storePreds) {
                                    predecessors[s][v].push_back(w);
                                }
                            }
                            if (new_dist[w] >= new_dist[v] && touched[w] == 0) {
                                if (new_dist[w] > new_dist[v])
                                    new_dist[w] = new_dist[v]+1;
                                touched[w] = -1;
                                l_queues[new_dist[w]].push(w);
                                queue_BFS.push(w);
                            }
                    });
                }
            }
            // dependencies accumulation
            DEBUG("Dependency accumulation");
            count level = maxDistance[s];
            while(level > 0) {
                while(!l_queues[level].empty()) {
                    node w = l_queues[level].front();
                    DEBUG("Node ",w);
                    l_queues[level].pop();
                    auto updateDependency = [&](node w, node v) {
                        if (new_dist[v] < new_dist[w]) {
                            if (touched[v] == 0) {
                                touched[v] = 1;
                                new_dep[v] = dependencies[s][v];
                                l_queues[level-1].push(v);
                            }
                            double new_contrib = double(new_npaths[v])/new_npaths[w]*(1+new_dep[w]);
                            new_dep[v] += new_contrib;
                            double old_contrib = double(npaths[s][v])/npaths[s][w]*(1+dependencies[s][w]);
                            if (touched[v] == 1 && (v != u_h or w!= u_l))
                                new_dep[v] -= old_contrib;
                            DEBUG("Parent ", v);
                        }
                    };
                    if (storePreds) {
                        for (node v : predecessors[s][w]) {
                            updateDependency(w, v);
                        }
                    }
                    else {
                        G.forNeighborsOf(w, [&](node v){
                            updateDependency(w, v);
                        });
                    }
                    if (w != s) {
                        scoreData[w] = scoreData[w] + new_dep[w] - dependencies[s][w];
                    }
                }
                level = level - 1;
            }
            // data structures update
            G.forNodes([&] (node r){
                distances[s][r] = new_dist[r];
                npaths[s][r] = new_npaths[r];
                if (touched[r] != 0)
                    dependencies[s][r] = new_dep[r];
            });
        }
/*

        BFS sssp(G, s, true, true);
        sssp.run();
        G.forNodes([&](node t){
            if(distances[s][t] != sssp.distance(t) || npaths[s][t] != sssp.numberOfPaths(t)) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DISTANCE: "<<distances[s][t]<<"  REAL DISTANCE: "<<sssp.distance(t)<<std::endl;
                std::cout<<"COMPUTED NUMBER OF PATHS: "<<npaths[s][t]<<"  REAL NUMBER OF PATHS: "<<sssp.numberOfPaths(t)<<std::endl;
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::vector<double> dep(G.upperNodeIdBound());
        std::stack<node> stack = sssp.getStack();
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp.getPredecessors(t)) {
                dep[p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dep[t]);
            }
        }

        G.forNodes([&](node t){
            if((dependencies[s][t]-dep[t]>0.000001 || dependencies[s][t]-dep[t]<-0.000001) && s!=t) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DEPENDENCY: "<<dependencies[s][t]<<"  REAL DEPENDENCY: "<<dep[t]<<std::endl;
            }
        });

*/

    });
}

void DynBetweenness::updateWeighted(GraphEvent e) {
    G.forNodes([&] (node s){
        scoreData[s] = 0.0;
    });
    G.forNodes([&] (node s){
        // update of distances and number of shortest paths
        Aux::PrioQueue<double, node> S(G.upperNodeIdBound());
        G.forNodes([&] (node t){
            auto updatePaths = [&](node u, node v, edgeweight w) {
                if (distances[s][t] == distances[s][u] + w + distances[v][t]){
                    npaths[s][t] = npaths[s][t] + npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v){
                            DEBUG("Adding predecessors from v to t to predecessors from s to t");
                            //predecessors[s][t].insert( predecessors[s][t].end(), predecessors[v][t].begin(), predecessors[v][t].end());
                            for (node pv : predecessors[v][t]) {
                                bool wasAlreadyPred = false;
                                for (node ps : predecessors[s][t]) {
                                    if (ps == pv)
                                        wasAlreadyPred = true;
                                }
                                if (!wasAlreadyPred)
                                    predecessors[s][t].push_back(pv);
                            }
                            DEBUG("Finished adding");
                        }
                        else {
                            DEBUG("Adding u to the predecessors of v");
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished adding");
                        }
                    }
                }
                if (distances[s][t] > distances[s][u] + w + distances[v][t]){
                    distances[s][t] = distances[s][u] + w + distances[v][t];
                    npaths[s][t] = npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v) {
                            DEBUG("Replacing predecessors from v to t with predecessors from s to t");
                            predecessors[s][t] = predecessors[v][t];
                            DEBUG("Finished replacing");
                        }
                        else {
                            DEBUG("Replacing old predecessors of v with u");
                            predecessors[s][t].clear();
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished replacing");
                        }
                    }
                }
            };
            if (s != t) {
                updatePaths(e.u, e.v, e.w);
                updatePaths(e.v, e.u, e.w);
                S.insert(-1*distances[s][t], t);
                dependencies[s][t] = 0.0;
            }
        });
        // dependency accumulation
        while (S.size() != 0) {
            // extract the node with the maximum distance
            node t = S.extractMin().second;
            if (storePreds) {
                DEBUG("Computing dependencies");
                for (node p : predecessors[s][t]) {
                    dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                }
            }
            else {
                G.forNeighborsOf(t, [&] (node p){
                    if (logically_equal(distances[s][t], distances[s][p] + G.weight(p, t))) {
                        dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                    }
                });
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }

    });

}

void DynBetweenness::update(GraphEvent e) {
    if (G.isWeighted())
        updateWeighted(e);
    else
        updateUnweighted(e);
}

} /* namespace NetworKit */
<|endoftext|>