<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* no header other than VotingArbiter.h should be included here */

#ifdef _WIN32
#  pragma warning( 4:4786)
#  define snprintf _snprintf
#endif

#include "VotingArbiter.h"

/* private */

/* protected */

void VotingArbiter::updatePollers(void)
{
  while (!_pollers.empty()) {
    poller_t& p = _pollers.front();
    if ((TimeKeeper::getCurrent() - p.lastRequest) > _voteRepeatTime) {
      // remove pollers that expired their repoll timeout
      _pollers.pop_front();
    } else {
      break;
    }
  }
  return;
}

bool VotingArbiter::isPollerWaiting(std::string name) const
{
  for (unsigned int i = 0; i < _pollers.size(); i++) {
    if (_pollers[i].name == name) {
      return true;
    }
  }
  return false;
}

/* public */

bool VotingArbiter::forgetPoll(void)
{
  if (_votingBooth != NULL) {
    delete _votingBooth;
    _votingBooth = NULL;
  }
  _startTime = TimeKeeper::getNullTime();
  _pollee = "nobody";
  _polleeIP = "";
  _action = "";
  _pollRequestor = "nobody";

  /* poof */
  _suffraged.clear();

  return true;
}

bool VotingArbiter::poll(std::string player, std::string playerRequesting, std::string action, std::string playerIP)
{
  poller_t p;
  std::string message;
  bool tooSoon;

  // you have to forget the current poll before another can be spawned
  if (this->isPollOpen()) {
    return false;
  }

  // update the poller list (people on the pollers list cannot initiate a poll
  updatePollers();

  // see if the poller is in the list
  tooSoon = isPollerWaiting(playerRequesting);
  if (tooSoon) {
    return false;
  }

  // add this poller to the end list
  p.name = playerRequesting;
  p.lastRequest = TimeKeeper::getCurrent();
  _pollers.push_back(p);

  // create the booth to record votes
  message = player + " " + action;

  if (_votingBooth != NULL) {
    delete _votingBooth;
  }
  _votingBooth = YesNoVotingBooth(message);
  _pollee = player;
  _polleeIP = playerIP;
  _action = action;
  _pollRequestor = playerRequesting;

  // set timers
  _startTime = TimeKeeper::getCurrent();

  return true;
}

bool VotingArbiter::pollToKick(std::string player, std::string playerRequesting)
{
  return (this->poll(player, playerRequesting, "kick"));
}

bool VotingArbiter::pollToBan(std::string player, std::string playerRequesting, std::string playerIP)
{
  return (this->poll(player, playerRequesting, "ban", playerIP));
}

bool VotingArbiter::closePoll(void)
{
  if (this->isPollClosed()) {
    return true;
  }
  // set starting time to exactly current time minus necessary vote time
  _startTime = TimeKeeper::getCurrent();
  _startTime += -(_voteTime);

  return true;
}

bool VotingArbiter::setAvailableVoters(unsigned short int count)
{
  _maxVotes = count;
  return true;
}

bool VotingArbiter::grantSuffrage(std::string player)
{
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      return true;
    }
  }
  _suffraged.push_front(player);
  return true;
}

bool VotingArbiter::hasSuffrage(std::string player) const
{
  // is there a poll to vote on?
  if (!this->isPollOpen()) {
    return false;
  }

  // was this player granted the right to vote?
  bool foundPlayer = false;
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      foundPlayer = true;
      break;
    }
  }
  if (!foundPlayer) {
    return false;
  }

  // has this player already voted?
  if (_votingBooth->hasVoted(player)) {
    return false;
  }

  // are there too many votes somehow (sanity)
  if (_votingBooth->getTotalVotes() >= _maxVotes) {
    return false;
  }

  return true;
}

bool VotingArbiter::voteYes(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, 1));
}

bool VotingArbiter::voteNo(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, 0));
}

unsigned long int VotingArbiter::getYesCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount(1);
}

unsigned long int VotingArbiter::getNoCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount(0);
}

unsigned long int VotingArbiter::getAbstentionCount(void) const
{
  // cannot abstain if there is no poll
  if (!this->knowsPoll()) {
    return 0;
  }
  int count = _suffraged.size() - this->getYesCount() - this->getNoCount();
  if (count <= 0) {
    return 0;
  }
  return count;
}

bool VotingArbiter::isPollSuccessful(void) const
{
  if (!this->knowsPoll()) {
    return false;
  }
  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // ensure minimum votage (and sanity zero-div check)
  if ((yesVotes + noVotes < _votesRequired) || (yesVotes + noVotes == 0)) {
    return false;
  }

  //  std::cout << "Percentage successful is " << ((double)votes * (double)100.0 / (double)_maxVotes) << " with " << votes << " votes and " << _maxVotes << "max votes required" << std::endl;

  // were there enough votes?
  if (( (double)100.0 * (double)yesVotes / total) >= (double)_votePercentage) {
    return true;
  }

  return false;
}

bool VotingArbiter::isPollSureToFail(void) const
{
  if (!this->knowsPoll()) {
    return true; // hrm, maybe false
  }

  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // there is a poll, but nobody is allowed to vote
  if (total <= 0.1) {
    return true;
  }

  // were there enough no votes to ensure failure?
  if (( (double)100.0 * (double)noVotes / total) >= (double)100.0 - (double)_votePercentage) {
    return true;
  }

  return false;
}

unsigned long int VotingArbiter::timeRemaining(void) const
{
  if (_votingBooth == NULL) {
    return 0;
  }

  // if the poll is successful early, terminate the clock
  if (this->isPollSuccessful()) {
    return 0;
  }

  float remaining = _voteTime - (TimeKeeper::getCurrent() - _startTime);
  if (remaining < 0.0f) {
    return 0;
  }
  return (unsigned int)remaining;
}

bool VotingArbiter::retractVote(std::string player)
{
  if (_votingBooth == NULL) {
    return false;
  }
  return _votingBooth->retractVote(player);
}

// ex: shiftwidth=2 tabstop=8
<commit_msg>updated arbiter to new booth interface; votes are no longer integer indices, they are strings<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* no header other than VotingArbiter.h should be included here */

#ifdef _WIN32
#  pragma warning( 4:4786)
#  define snprintf _snprintf
#endif

#include "VotingArbiter.h"

/* private */

/* protected */

void VotingArbiter::updatePollers(void)
{
  while (!_pollers.empty()) {
    poller_t& p = _pollers.front();
    if ((TimeKeeper::getCurrent() - p.lastRequest) > _voteRepeatTime) {
      // remove pollers that expired their repoll timeout
      _pollers.pop_front();
    } else {
      break;
    }
  }
  return;
}

bool VotingArbiter::isPollerWaiting(std::string name) const
{
  for (unsigned int i = 0; i < _pollers.size(); i++) {
    if (_pollers[i].name == name) {
      return true;
    }
  }
  return false;
}

/* public */

bool VotingArbiter::forgetPoll(void)
{
  if (_votingBooth != NULL) {
    delete _votingBooth;
    _votingBooth = NULL;
  }
  _startTime = TimeKeeper::getNullTime();
  _pollee = "nobody";
  _polleeIP = "";
  _action = "";
  _pollRequestor = "nobody";

  /* poof */
  _suffraged.clear();

  return true;
}

bool VotingArbiter::poll(std::string player, std::string playerRequesting, std::string action, std::string playerIP)
{
  poller_t p;
  std::string message;
  bool tooSoon;

  // you have to forget the current poll before another can be spawned
  if (this->isPollOpen()) {
    return false;
  }

  // update the poller list (people on the pollers list cannot initiate a poll
  updatePollers();

  // see if the poller is in the list
  tooSoon = isPollerWaiting(playerRequesting);
  if (tooSoon) {
    return false;
  }

  // add this poller to the end list
  p.name = playerRequesting;
  p.lastRequest = TimeKeeper::getCurrent();
  _pollers.push_back(p);

  // create the booth to record votes
  message = player + " " + action;

  if (_votingBooth != NULL) {
    delete _votingBooth;
  }
  _votingBooth = YesNoVotingBooth(message);
  _pollee = player;
  _polleeIP = playerIP;
  _action = action;
  _pollRequestor = playerRequesting;

  // set timers
  _startTime = TimeKeeper::getCurrent();

  return true;
}

bool VotingArbiter::pollToKick(std::string player, std::string playerRequesting)
{
  return (this->poll(player, playerRequesting, "kick"));
}

bool VotingArbiter::pollToBan(std::string player, std::string playerRequesting, std::string playerIP)
{
  return (this->poll(player, playerRequesting, "ban", playerIP));
}

bool VotingArbiter::closePoll(void)
{
  if (this->isPollClosed()) {
    return true;
  }
  // set starting time to exactly current time minus necessary vote time
  _startTime = TimeKeeper::getCurrent();
  _startTime += -(_voteTime);

  return true;
}

bool VotingArbiter::setAvailableVoters(unsigned short int count)
{
  _maxVotes = count;
  return true;
}

bool VotingArbiter::grantSuffrage(std::string player)
{
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      return true;
    }
  }
  _suffraged.push_front(player);
  return true;
}

bool VotingArbiter::hasSuffrage(std::string player) const
{
  // is there a poll to vote on?
  if (!this->isPollOpen()) {
    return false;
  }

  // was this player granted the right to vote?
  bool foundPlayer = false;
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      foundPlayer = true;
      break;
    }
  }
  if (!foundPlayer) {
    return false;
  }

  // has this player already voted?
  if (_votingBooth->hasVoted(player)) {
    return false;
  }

  // are there too many votes somehow (sanity)
  if (_votingBooth->getTotalVotes() >= _maxVotes) {
    return false;
  }

  return true;
}

bool VotingArbiter::voteYes(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, "1"));
}

bool VotingArbiter::voteNo(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, "0"));
}

unsigned long int VotingArbiter::getYesCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount("1");
}

unsigned long int VotingArbiter::getNoCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount("0");
}

unsigned long int VotingArbiter::getAbstentionCount(void) const
{
  // cannot abstain if there is no poll
  if (!this->knowsPoll()) {
    return 0;
  }
  int count = _suffraged.size() - this->getYesCount() - this->getNoCount();
  if (count <= 0) {
    return 0;
  }
  return count;
}

bool VotingArbiter::isPollSuccessful(void) const
{
  if (!this->knowsPoll()) {
    return false;
  }
  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // ensure minimum votage (and sanity zero-div check)
  if ((yesVotes + noVotes < _votesRequired) || (yesVotes + noVotes == 0)) {
    return false;
  }

  //  std::cout << "Percentage successful is " << ((double)votes * (double)100.0 / (double)_maxVotes) << " with " << votes << " votes and " << _maxVotes << "max votes required" << std::endl;

  // were there enough votes?
  if (( (double)100.0 * (double)yesVotes / total) >= (double)_votePercentage) {
    return true;
  }

  return false;
}

bool VotingArbiter::isPollSureToFail(void) const
{
  if (!this->knowsPoll()) {
    return true; // hrm, maybe false
  }

  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // there is a poll, but nobody is allowed to vote
  if (total <= 0.1) {
    return true;
  }

  // were there enough no votes to ensure failure?
  if (( (double)100.0 * (double)noVotes / total) >= (double)100.0 - (double)_votePercentage) {
    return true;
  }

  return false;
}

unsigned long int VotingArbiter::timeRemaining(void) const
{
  if (_votingBooth == NULL) {
    return 0;
  }

  // if the poll is successful early, terminate the clock
  if (this->isPollSuccessful()) {
    return 0;
  }

  float remaining = _voteTime - (TimeKeeper::getCurrent() - _startTime);
  if (remaining < 0.0f) {
    return 0;
  }
  return (unsigned int)remaining;
}

bool VotingArbiter::retractVote(std::string player)
{
  if (_votingBooth == NULL) {
    return false;
  }
  return _votingBooth->retractVote(player);
}

// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* no header other than VotingArbiter.h should be included here */

#ifdef _WIN32
#  pragma warning( 4:4786)
#  define snprintf _snprintf
#endif

#include "VotingArbiter.h"

/* private */

/* protected */

void VotingArbiter::updatePollers(void)
{
  while (!_pollers.empty()) {
    poller_t& p = _pollers.front();
    if ((TimeKeeper::getCurrent() - p.lastRequest) > _voteRepeatTime) {
      // remove pollers that expired their repoll timeout
      _pollers.pop_front();
    } else {
      break;
    }
  }
  return;
}

bool VotingArbiter::isPollerWaiting(std::string name) const
{
  for (unsigned int i = 0; i < _pollers.size(); i++) {
    if (_pollers[i].name == name) {
      return true;
    }
  }
  return false;
}

/* public */

bool VotingArbiter::forgetPoll(void)
{
  if (_votingBooth != NULL) {
    delete _votingBooth;
    _votingBooth = NULL;
  }
  _startTime = TimeKeeper::getNullTime();
  _pollee = "nobody";
  _polleeIP = "";
  _action = "";
  _pollRequestor = "nobody";

  /* poof */
  _suffraged.clear();

  return true;
}

bool VotingArbiter::poll(std::string player, std::string playerRequesting, std::string action, std::string playerIP)
{
  poller_t p;
  std::string message;
  bool tooSoon;

  // you have to forget the current poll before another can be spawned
  if (this->isPollOpen()) {
    return false;
  }

  // update the poller list (people on the pollers list cannot initiate a poll
  updatePollers();

  // see if the poller is in the list
  tooSoon = isPollerWaiting(playerRequesting);
  if (tooSoon) {
    return false;
  }

  // add this poller to the end list
  p.name = playerRequesting;
  p.lastRequest = TimeKeeper::getCurrent();
  _pollers.push_back(p);

  // create the booth to record votes
  message = player + " " + action;

  if (_votingBooth != NULL) {
    delete _votingBooth;
  }
  _votingBooth = YesNoVotingBooth(message);
  _pollee = player;
  _polleeIP = playerIP;
  _action = action;
  _pollRequestor = playerRequesting;

  // set timers
  _startTime = TimeKeeper::getCurrent();

  return true;
}

bool VotingArbiter::pollToKick(std::string player, std::string playerRequesting)
{
  return (this->poll(player, playerRequesting, "kick"));
}

bool VotingArbiter::pollToBan(std::string player, std::string playerRequesting, std::string playerIP)
{
  return (this->poll(player, playerRequesting, "ban", playerIP));
}

bool VotingArbiter::closePoll(void)
{
  if (this->isPollClosed()) {
    return true;
  }
  // set starting time to exactly current time minus necessary vote time
  _startTime = TimeKeeper::getCurrent();
  _startTime += -(_voteTime);

  return true;
}

bool VotingArbiter::setAvailableVoters(unsigned short int count)
{
  _maxVotes = count;
  return true;
}

bool VotingArbiter::grantSuffrage(std::string player)
{
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      return true;
    }
  }
  _suffraged.push_front(player);
  return true;
}

bool VotingArbiter::hasSuffrage(std::string player) const
{
  // is there a poll to vote on?
  if (!this->isPollOpen()) {
    return false;
  }

  // was this player granted the right to vote?
  bool foundPlayer = false;
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      foundPlayer = true;
      break;
    }
  }
  if (!foundPlayer) {
    return false;
  }

  // has this player already voted?
  if (_votingBooth->hasVoted(player)) {
    return false;
  }

  // are there too many votes somehow (sanity)
  if (_votingBooth->getTotalVotes() >= _maxVotes) {
    return false;
  }

  return true;
}

bool VotingArbiter::voteYes(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, "yes"));
}

bool VotingArbiter::voteNo(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, "no"));
}

unsigned long int VotingArbiter::getYesCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount("yes");
}

unsigned long int VotingArbiter::getNoCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount("no");
}

unsigned long int VotingArbiter::getAbstentionCount(void) const
{
  // cannot abstain if there is no poll
  if (!this->knowsPoll()) {
    return 0;
  }
  int count = _suffraged.size() - this->getYesCount() - this->getNoCount();
  if (count <= 0) {
    return 0;
  }
  return count;
}

bool VotingArbiter::isPollSuccessful(void) const
{
  if (!this->knowsPoll()) {
    return false;
  }
  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // ensure minimum votage (and sanity zero-div check)
  if ((yesVotes + noVotes < _votesRequired) || (yesVotes + noVotes == 0)) {
    return false;
  }

  //  std::cout << "Percentage successful is " << ((double)votes * (double)100.0 / (double)_maxVotes) << " with " << votes << " votes and " << _maxVotes << "max votes required" << std::endl;

  // were there enough votes?
  if (( (double)100.0 * (double)yesVotes / total) >= (double)_votePercentage) {
    return true;
  }

  return false;
}

bool VotingArbiter::isPollSureToFail(void) const
{
  if (!this->knowsPoll()) {
    return true; // hrm, maybe false
  }

  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // there is a poll, but nobody is allowed to vote
  if (total <= 0.1) {
    return true;
  }

  // were there enough no votes to ensure failure?
  if (( (double)100.0 * (double)noVotes / total) >= (double)100.0 - (double)_votePercentage) {
    return true;
  }

  return false;
}

unsigned short int VotingArbiter::timeRemaining(void) const
{
  if (_votingBooth == NULL) {
    return 0;
  }

  // if the poll is successful early, terminate the clock
  if (this->isPollSuccessful()) {
    return 0;
  }

  float remaining = _voteTime - (TimeKeeper::getCurrent() - _startTime);
  if (remaining < 0.0f) {
    return 0;
  }
  return (unsigned short int)remaining;
}

bool VotingArbiter::retractVote(std::string player)
{
  if (_votingBooth == NULL) {
    return false;
  }
  return _votingBooth->retractVote(player);
}

// Local variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>typecasting<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* no header other than VotingArbiter.h should be included here */

#ifdef _WIN32
#  pragma warning( 4:4786)
#  define snprintf _snprintf
#endif

#include "VotingArbiter.h"

/* private */

/* protected */

void VotingArbiter::updatePollers(void)
{
  while (!_pollers.empty()) {
    poller_t& p = _pollers.front();
    if ((TimeKeeper::getCurrent() - p.lastRequest) > _voteRepeatTime) {
      // remove pollers that expired their repoll timeout
      _pollers.pop_front();
    } else {
      break;
    }
  }
  return;
}

bool VotingArbiter::isPollerWaiting(std::string name) const
{
  for (unsigned int i = 0; i < _pollers.size(); i++) {
    if (_pollers[i].name == name) {
      return true;
    }
  }
  return false;
}

/* public */

bool VotingArbiter::forgetPoll(void)
{
  if (_votingBooth != NULL) {
    delete _votingBooth;
    _votingBooth = NULL;
  }
  _startTime = TimeKeeper::getNullTime();
  _pollee = "nobody";
  _polleeIP = "";
  _action = "";
  _pollRequestor = "nobody";

  /* poof */
  _suffraged.clear();

  return true;
}

bool VotingArbiter::poll(std::string player, std::string playerRequesting, std::string action, std::string playerIP)
{
  poller_t p;
  std::string message;
  bool tooSoon;

  // you have to forget the current poll before another can be spawned
  if (this->isPollOpen()) {
    return false;
  }

  // update the poller list (people on the pollers list cannot initiate a poll
  updatePollers();

  // see if the poller is in the list
  tooSoon = isPollerWaiting(playerRequesting);
  if (tooSoon) {
    return false;
  }

  // add this poller to the end list
  p.name = playerRequesting;
  p.lastRequest = TimeKeeper::getCurrent();
  _pollers.push_back(p);

  // create the booth to record votes
  message = player + " " + action;

  if (_votingBooth != NULL) {
    delete _votingBooth;
  }
  _votingBooth = YesNoVotingBooth(message);
  _pollee = player;
  _polleeIP = playerIP;
  _action = action;
  _pollRequestor = playerRequesting;

  // set timers
  _startTime = TimeKeeper::getCurrent();

  return true;
}

bool VotingArbiter::pollToKick(std::string player, std::string playerRequesting)
{
  return (this->poll(player, playerRequesting, "kick"));
}

bool VotingArbiter::pollToBan(std::string player, std::string playerRequesting, std::string playerIP)
{
  return (this->poll(player, playerRequesting, "ban", playerIP));
}

bool VotingArbiter::closePoll(void)
{
  if (this->isPollClosed()) {
    return true;
  }
  // set starting time to exactly current time minus necessary vote time
  _startTime = TimeKeeper::getCurrent();
  _startTime += -(float)(_voteTime);

  return true;
}

bool VotingArbiter::setAvailableVoters(unsigned short int count)
{
  _maxVotes = count;
  return true;
}

bool VotingArbiter::grantSuffrage(std::string player)
{
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      return true;
    }
  }
  _suffraged.push_front(player);
  return true;
}

bool VotingArbiter::hasSuffrage(std::string player) const
{
  // is there a poll to vote on?
  if (!this->isPollOpen()) {
    return false;
  }

  // was this player granted the right to vote?
  bool foundPlayer = false;
  for (unsigned int i = 0; i < _suffraged.size(); i++) {
    if (_suffraged[i] == player) {
      foundPlayer = true;
      break;
    }
  }
  if (!foundPlayer) {
    return false;
  }

  // has this player already voted?
  if (_votingBooth->hasVoted(player)) {
    return false;
  }

  // are there too many votes somehow (sanity)
  if (_votingBooth->getTotalVotes() >= _maxVotes) {
    return false;
  }

  return true;
}

bool VotingArbiter::voteYes(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, "yes"));
}

bool VotingArbiter::voteNo(std::string player)
{
  if (!this->knowsPoll() || this->isPollClosed()) {
    return false;
  }

  // allowed to vote?
  if (!hasSuffrage(player)) {
    return false;
  }

  return (_votingBooth->vote(player, "no"));
}

unsigned long int VotingArbiter::getYesCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount("yes");
}

unsigned long int VotingArbiter::getNoCount(void) const
{
  if (!this->knowsPoll()) {
    return 0;
  }
  return _votingBooth->getVoteCount("no");
}

unsigned long int VotingArbiter::getAbstentionCount(void) const
{
  // cannot abstain if there is no poll
  if (!this->knowsPoll()) {
    return 0;
  }
  int count = _suffraged.size() - this->getYesCount() - this->getNoCount();
  if (count <= 0) {
    return 0;
  }
  return count;
}

bool VotingArbiter::isPollSuccessful(void) const
{
  if (!this->knowsPoll()) {
    return false;
  }
  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // ensure minimum votage (and sanity zero-div check)
  if ((yesVotes + noVotes < _votesRequired) || (yesVotes + noVotes == 0)) {
    return false;
  }

  //  std::cout << "Percentage successful is " << ((double)votes * (double)100.0 / (double)_maxVotes) << " with " << votes << " votes and " << _maxVotes << "max votes required" << std::endl;

  // were there enough votes?
  if (( (double)100.0 * (double)yesVotes / total) >= (double)_votePercentage) {
    return true;
  }

  return false;
}

bool VotingArbiter::isPollSureToFail(void) const
{
  if (!this->knowsPoll()) {
    return true; // hrm, maybe false
  }

  unsigned long int yesVotes = this->getYesCount();
  unsigned long int noVotes = this->getNoCount();
  unsigned long int abstainVotes = this->getAbstentionCount();
  double total = (double)yesVotes + (double)noVotes + (double)abstainVotes;

  // there is a poll, but nobody is allowed to vote
  if (total <= 0.1) {
    return true;
  }

  // were there enough no votes to ensure failure?
  if (( (double)100.0 * (double)noVotes / total) >= (double)100.0 - (double)_votePercentage) {
    return true;
  }

  return false;
}

unsigned short int VotingArbiter::timeRemaining(void) const
{
  if (_votingBooth == NULL) {
    return 0;
  }

  // if the poll is successful early, terminate the clock
  if (this->isPollSuccessful()) {
    return 0;
  }

  float remaining = _voteTime - (TimeKeeper::getCurrent() - _startTime);
  if (remaining < 0.0f) {
    return 0;
  }
  return (unsigned short int)remaining;
}

bool VotingArbiter::retractVote(std::string player)
{
  if (_votingBooth == NULL) {
    return false;
  }
  return _votingBooth->retractVote(player);
}

// Local variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>


<commit_before>#define WANT_TEST_EXTRAS
#include "tap++.h"
#include <stack>
#include <boost/lexical_cast.hpp>

namespace TAP {
	std::string TODO = "";

	const details::skip_all_type skip_all = details::skip_all_type();
	const details::no_plan_type no_plan = details::no_plan_type();

	namespace {
		unsigned expected = 0;
		unsigned counter = 0;
		unsigned not_oks = 0;

		std::string todo_test() throw() {
			if (TODO == "") {
				return TODO;
			}
			else {
				return " # TODO " + TODO;
			}
		}
		bool is_planned = false;
		bool no_planned = false;
		bool has_output_plan = false;

		void output_plan(unsigned tests, const std::string& extra = "") throw(fatal_exception) {
			if (has_output_plan) {
				throw fatal_exception("Can't plan twice");
			}
			*details::output << "1.." << tests << extra << std::endl;
			has_output_plan = true;
		}
		inline const std::string to_string(unsigned num) throw() {
			return boost::lexical_cast<std::string>(num);
		}

		inline void _done_testing(unsigned tests) throw(fatal_exception) {
			static bool is_done = false;
			if (is_done) {
				fail("done_testing() was already called");
				return;
			}
			is_done = true;

			if (expected && tests != expected) {
				fail(std::string("planned to run ") + to_string(expected) + " tests but done_testing() expects " + to_string(tests));
			}
			else {
				expected = tests;
			}
			is_planned = true;
			if (!has_output_plan) {
				output_plan(tests);
			}
		}

	}
	void plan(unsigned tests) throw(fatal_exception) {
		if (is_planned) {
			bail_out("Can't plan again!");
		}
		is_planned = true;
		output_plan(tests);
		expected = tests;
	}
	void plan(const details::skip_all_type&, const std::string& reason) throw(fatal_exception) {
		output_plan(0, " #skip " + reason);
		exit(0);
	}
	void plan(const details::no_plan_type&) throw() {
		is_planned = true;
		no_planned = true;
	}

	void done_testing() throw(fatal_exception) {
		_done_testing(encountered());
	}

	void done_testing(unsigned tests) throw(fatal_exception) {
		no_planned = false;
		_done_testing(tests);
	}

	unsigned planned() throw() {
		return expected;
	}
	unsigned encountered() throw() {
		return counter;
	}

	int exit_status() throw () {
		bool passing;
		if (!is_planned && encountered()) {
			diag("Tests were run but no plan was declared and done_testing() was not seen.");
		}
		if (no_planned) {
			output_plan(encountered());
			return std::min(254u, not_oks);
		}
		else if (expected == counter) {
			return std::min(254u, not_oks);
		}
		else {
			return 255;
		}
	}
	bool summary() throw() {
		return not_oks;
	}

	void bail_out(const std::string& reason) throw() {
		*details::output << "Bail out!  " << reason << std::endl;
		exit(255); // Does not unwind stack!
	}

	bool ok(bool is_ok, const std::string& message) throw() {
		const char* hot_or_not = is_ok ? "" : "not ";
		*details::output << hot_or_not << "ok " << ++counter<< " - " << message << todo_test()  << std::endl;
		if (!is_ok) {
			++not_oks;
		}
		return is_ok;
	}
	bool not_ok(bool is_not_ok, const std::string& message) throw() {
		return !ok(!is_not_ok, message);
	}

	bool pass(const std::string& message) throw() {
		return ok(true, message);
	}
	bool fail(const std::string& message) throw() {
		return ok(false, message);
	}

	void skip(unsigned num, const std::string& reason) throw ()  {
		for(unsigned i = 0; i < num; ++i) {
			pass(" # skip " + reason);
		}
	}

	void set_output(std::ostream& new_output) throw (fatal_exception) {
		if (is_planned) {
			throw fatal_exception("Can't set output after plan()");
		}
		details::output = &new_output;
	}
	void set_error(std::ostream& new_error) throw(fatal_exception) {
		if (is_planned) {
			throw fatal_exception("Can't set error after plan()");
		}
		details::error = &new_error;
	}
	namespace details {
		std::ostream* output = &std::cout;
		std::ostream* error = &std::cerr;
		static std::stack<unsigned> block_expected;
		void start_block(unsigned expected) throw() {
			block_expected.push(encountered() + expected);
		}
		unsigned stop_block() throw(fatal_exception) {
			unsigned ret = block_expected.top();
			block_expected.pop();
			return ret;
		}

		todo_guard::todo_guard() throw() : value(TODO) {
		}
		todo_guard::~todo_guard() throw() {
			TODO = value;
		}
	}

	void skip(const std::string& reason) throw(details::Skip_exception) {
		throw details::Skip_exception(reason);
	}
	void skip_todo(const std::string& reason) throw(details::Todo_exception) {
		throw details::Todo_exception(reason);
	}

}
<commit_msg>Sanatized #includes<commit_after>#define WANT_TEST_EXTRAS
#include <tap++/tap++.h>
#include <stack>
#include <boost/lexical_cast.hpp>

namespace TAP {
	std::string TODO = "";

	const details::skip_all_type skip_all = details::skip_all_type();
	const details::no_plan_type no_plan = details::no_plan_type();

	namespace {
		unsigned expected = 0;
		unsigned counter = 0;
		unsigned not_oks = 0;

		std::string todo_test() throw() {
			if (TODO == "") {
				return TODO;
			}
			else {
				return " # TODO " + TODO;
			}
		}
		bool is_planned = false;
		bool no_planned = false;
		bool has_output_plan = false;

		void output_plan(unsigned tests, const std::string& extra = "") throw(fatal_exception) {
			if (has_output_plan) {
				throw fatal_exception("Can't plan twice");
			}
			*details::output << "1.." << tests << extra << std::endl;
			has_output_plan = true;
		}
		inline const std::string to_string(unsigned num) throw() {
			return boost::lexical_cast<std::string>(num);
		}

		inline void _done_testing(unsigned tests) throw(fatal_exception) {
			static bool is_done = false;
			if (is_done) {
				fail("done_testing() was already called");
				return;
			}
			is_done = true;

			if (expected && tests != expected) {
				fail(std::string("planned to run ") + to_string(expected) + " tests but done_testing() expects " + to_string(tests));
			}
			else {
				expected = tests;
			}
			is_planned = true;
			if (!has_output_plan) {
				output_plan(tests);
			}
		}

	}
	void plan(unsigned tests) throw(fatal_exception) {
		if (is_planned) {
			bail_out("Can't plan again!");
		}
		is_planned = true;
		output_plan(tests);
		expected = tests;
	}
	void plan(const details::skip_all_type&, const std::string& reason) throw(fatal_exception) {
		output_plan(0, " #skip " + reason);
		exit(0);
	}
	void plan(const details::no_plan_type&) throw() {
		is_planned = true;
		no_planned = true;
	}

	void done_testing() throw(fatal_exception) {
		_done_testing(encountered());
	}

	void done_testing(unsigned tests) throw(fatal_exception) {
		no_planned = false;
		_done_testing(tests);
	}

	unsigned planned() throw() {
		return expected;
	}
	unsigned encountered() throw() {
		return counter;
	}

	int exit_status() throw () {
		bool passing;
		if (!is_planned && encountered()) {
			diag("Tests were run but no plan was declared and done_testing() was not seen.");
		}
		if (no_planned) {
			output_plan(encountered());
			return std::min(254u, not_oks);
		}
		else if (expected == counter) {
			return std::min(254u, not_oks);
		}
		else {
			return 255;
		}
	}
	bool summary() throw() {
		return not_oks;
	}

	void bail_out(const std::string& reason) throw() {
		*details::output << "Bail out!  " << reason << std::endl;
		exit(255); // Does not unwind stack!
	}

	bool ok(bool is_ok, const std::string& message) throw() {
		const char* hot_or_not = is_ok ? "" : "not ";
		*details::output << hot_or_not << "ok " << ++counter<< " - " << message << todo_test()  << std::endl;
		if (!is_ok) {
			++not_oks;
		}
		return is_ok;
	}
	bool not_ok(bool is_not_ok, const std::string& message) throw() {
		return !ok(!is_not_ok, message);
	}

	bool pass(const std::string& message) throw() {
		return ok(true, message);
	}
	bool fail(const std::string& message) throw() {
		return ok(false, message);
	}

	void skip(unsigned num, const std::string& reason) throw ()  {
		for(unsigned i = 0; i < num; ++i) {
			pass(" # skip " + reason);
		}
	}

	void set_output(std::ostream& new_output) throw (fatal_exception) {
		if (is_planned) {
			throw fatal_exception("Can't set output after plan()");
		}
		details::output = &new_output;
	}
	void set_error(std::ostream& new_error) throw(fatal_exception) {
		if (is_planned) {
			throw fatal_exception("Can't set error after plan()");
		}
		details::error = &new_error;
	}
	namespace details {
		std::ostream* output = &std::cout;
		std::ostream* error = &std::cerr;
		static std::stack<unsigned> block_expected;
		void start_block(unsigned expected) throw() {
			block_expected.push(encountered() + expected);
		}
		unsigned stop_block() throw(fatal_exception) {
			unsigned ret = block_expected.top();
			block_expected.pop();
			return ret;
		}

		todo_guard::todo_guard() throw() : value(TODO) {
		}
		todo_guard::~todo_guard() throw() {
			TODO = value;
		}
	}

	void skip(const std::string& reason) throw(details::Skip_exception) {
		throw details::Skip_exception(reason);
	}
	void skip_todo(const std::string& reason) throw(details::Todo_exception) {
		throw details::Todo_exception(reason);
	}

}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "intersection.h"
#include "aabb.h"
#include "plane.h"
#include "sphere.h"
#include "vector3.h"

namespace crown
{
namespace math
{
	/// Returns the distance along ray (from, dir) to intersection point with plane @a p.
	/// -1.0f if no collision.
	float ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p)
	{
		float nd = vector3::dot(dir, p.n);
		float orpn = vector3::dot(from, p.n);
		float dist = -1.0f;

		if (nd < 0.0f)
			dist = (-p.d - orpn) / nd;

		return dist > 0.0f ? dist : -1.0f;
	}

	/// Returns the distance along ray (from, dir) to intersection point with sphere @a s.
	/// -1.0f if no collision.
	float ray_sphere_intersection(const Vector3& from, const Vector3& dir, const Sphere& s)
	{
		Vector3 v = s.c - from;
		float b = vector3::dot(v, dir);
		float det = (s.r * s.r) - vector3::dot(v, v) + (b * b);

		if (det < 0.0 || b < s.r)
		{
			return -1.0f;
		}

		return b - sqrt(det);
	}

	// http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-custom-ray-obb-function/
	float ray_oobb_intersection(const Vector3& from, const Vector3& dir, const OBB& obb)
	{
		using namespace vector3;

		float tmin = 0.0f;
		float tmax = 100000.0f;

		Vector3 obb_pos(obb.tm.t.x, obb.tm.t.y, obb.tm.t.z);
		Vector3 delta = obb_pos - from;

		{
			const Vector3 xaxis(obb.tm.x.x, obb.tm.x.y, obb.tm.x.z);
			float e = dot(xaxis, delta);
			float f = dot(dir, xaxis);

			if (fabs(f) > 0.001f)
			{
				float t1 = (e+obb.aabb.min.x)/f;
				float t2 = (e+obb.aabb.max.x)/f;

				if (t1>t2){
					float w=t1;t1=t2;t2=w;
				}

				if (t2 < tmax)
					tmax = t2;
				if (t1 > tmin)
					tmin = t1;

				if (tmax < tmin)
					return -1.0f;

			}
			else
			{
				if(-e+obb.aabb.min.x > 0.0f || -e+obb.aabb.max.x < 0.0f)
					return -1.0f;
			}
		}

		{
			const Vector3 yaxis(obb.tm.y.x, obb.tm.y.y, obb.tm.y.z);
			float e = dot(yaxis, delta);
			float f = dot(dir, yaxis);

			if (fabs(f) > 0.001f){

				float t1 = (e+obb.aabb.min.y)/f;
				float t2 = (e+obb.aabb.max.y)/f;

				if (t1>t2){float w=t1;t1=t2;t2=w;}

				if (t2 < tmax)
					tmax = t2;
				if (t1 > tmin)
					tmin = t1;

				if (tmin > tmax)
					return -1.0f;
			}
			else
			{
				if(-e+obb.aabb.min.y > 0.0f || -e+obb.aabb.max.y < 0.0f)
					return -1.0f;
			}
		}

		{
			const Vector3 zaxis(obb.tm.z.x, obb.tm.z.y, obb.tm.z.z);
			float e = dot(zaxis, delta);
			float f = dot(dir, zaxis);

			if (fabs(f) > 0.001f){

				float t1 = (e+obb.aabb.min.z)/f;
				float t2 = (e+obb.aabb.max.z)/f;

				if (t1>t2){float w=t1;t1=t2;t2=w;}

				if (t2 < tmax)
					tmax = t2;
				if (t1 > tmin)
					tmin = t1;

				if (tmin > tmax)
					return -1.0f;

			}
			else
			{
				if(-e+obb.aabb.min.z > 0.0f || -e+obb.aabb.max.z < 0.0f)
					return -1.0f;
			}
		}

		return tmin;
	}

	bool plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip)
	{
		const Vector3& n1 = p1.n;
		const Vector3& n2 = p2.n;
		const Vector3& n3 = p3.n;

		float den = -vector3::dot(vector3::cross(n1, n2), n3);

		if (equals(den, (float)0.0))
		{
			return false;
		}

		Vector3 res = p1.d * vector3::cross(n2, n3) + p2.d * vector3::cross(n3, n1) + p3.d * vector3::cross(n1, n2);
		ip = res / den;

		return true;
	}

	bool frustum_sphere_intersection(const Frustum& f, const Sphere& s)
	{
		if (plane::distance_to_point(f.left, s.c) < -s.r ||
			plane::distance_to_point(f.right, s.c) < -s.r)
		{
			return false;
		}

		if (plane::distance_to_point(f.bottom, s.c) < -s.r ||
			plane::distance_to_point(f.top, s.c) < -s.r)
		{
			return false;
		}

		if (plane::distance_to_point(f.near, s.c) < -s.r ||
			plane::distance_to_point(f.far, s.c) < -s.r)
		{
			return false;
		}

		return true;
	}

	bool frustum_box_intersection(const Frustum& f, const AABB& b)
	{
		uint8_t out;

		out = 0;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 0)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 1)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 2)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 3)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 4)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 5)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 6)) < 0.0) out++;
		if (plane::distance_to_point(f.left, aabb::vertex(b, 7)) < 0.0) out++;

		// If all vertices are outside one face, then the box doesn't intersect the frustum
		if (out == 8) return false;

		out = 0;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 0)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 1)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 2)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 3)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 4)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 5)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 6)) < 0.0) out++;
		if (plane::distance_to_point(f.right, aabb::vertex(b, 7)) < 0.0) out++;
		if (out == 8) return false;

		out = 0;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 0)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 1)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 2)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 3)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 4)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 5)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 6)) < 0.0) out++;
		if (plane::distance_to_point(f.bottom, aabb::vertex(b, 7)) < 0.0) out++;
		if (out == 8) return false;

		out = 0;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 0)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 1)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 2)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 3)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 4)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 5)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 6)) < 0.0) out++;
		if (plane::distance_to_point(f.top, aabb::vertex(b, 7)) < 0.0) out++;
		if (out == 8) return false;

		out = 0;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 0)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 1)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 2)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 3)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 4)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 5)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 6)) < 0.0) out++;
		if (plane::distance_to_point(f.near, aabb::vertex(b, 7)) < 0.0) out++;
		if (out == 8) return false;

		out = 0;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 0)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 1)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 2)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 3)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 4)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 5)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 6)) < 0.0) out++;
		if (plane::distance_to_point(f.far, aabb::vertex(b, 7)) < 0.0) out++;
		if (out == 8) return false;

		// If we are here, it is because either the box intersects or it is contained in the frustum
		return true;
	}

} // namespace math
} // namespace crown
<commit_msg>Remove namespace in .cpp as well<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "intersection.h"
#include "aabb.h"
#include "plane.h"
#include "sphere.h"
#include "vector3.h"

namespace crown
{

/// Returns the distance along ray (from, dir) to intersection point with plane @a p.
/// -1.0f if no collision.
float ray_plane_intersection(const Vector3& from, const Vector3& dir, const Plane& p)
{
	float nd = vector3::dot(dir, p.n);
	float orpn = vector3::dot(from, p.n);
	float dist = -1.0f;

	if (nd < 0.0f)
		dist = (-p.d - orpn) / nd;

	return dist > 0.0f ? dist : -1.0f;
}

/// Returns the distance along ray (from, dir) to intersection point with sphere @a s.
/// -1.0f if no collision.
float ray_sphere_intersection(const Vector3& from, const Vector3& dir, const Sphere& s)
{
	Vector3 v = s.c - from;
	float b = vector3::dot(v, dir);
	float det = (s.r * s.r) - vector3::dot(v, v) + (b * b);

	if (det < 0.0 || b < s.r)
	{
		return -1.0f;
	}

	return b - sqrt(det);
}

// http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-custom-ray-obb-function/
float ray_oobb_intersection(const Vector3& from, const Vector3& dir, const OBB& obb)
{
	using namespace vector3;

	float tmin = 0.0f;
	float tmax = 100000.0f;

	Vector3 obb_pos(obb.tm.t.x, obb.tm.t.y, obb.tm.t.z);
	Vector3 delta = obb_pos - from;

	{
		const Vector3 xaxis(obb.tm.x.x, obb.tm.x.y, obb.tm.x.z);
		float e = dot(xaxis, delta);
		float f = dot(dir, xaxis);

		if (fabs(f) > 0.001f)
		{
			float t1 = (e+obb.aabb.min.x)/f;
			float t2 = (e+obb.aabb.max.x)/f;

			if (t1>t2){
				float w=t1;t1=t2;t2=w;
			}

			if (t2 < tmax)
				tmax = t2;
			if (t1 > tmin)
				tmin = t1;

			if (tmax < tmin)
				return -1.0f;

		}
		else
		{
			if(-e+obb.aabb.min.x > 0.0f || -e+obb.aabb.max.x < 0.0f)
				return -1.0f;
		}
	}

	{
		const Vector3 yaxis(obb.tm.y.x, obb.tm.y.y, obb.tm.y.z);
		float e = dot(yaxis, delta);
		float f = dot(dir, yaxis);

		if (fabs(f) > 0.001f){

			float t1 = (e+obb.aabb.min.y)/f;
			float t2 = (e+obb.aabb.max.y)/f;

			if (t1>t2){float w=t1;t1=t2;t2=w;}

			if (t2 < tmax)
				tmax = t2;
			if (t1 > tmin)
				tmin = t1;

			if (tmin > tmax)
				return -1.0f;
		}
		else
		{
			if(-e+obb.aabb.min.y > 0.0f || -e+obb.aabb.max.y < 0.0f)
				return -1.0f;
		}
	}

	{
		const Vector3 zaxis(obb.tm.z.x, obb.tm.z.y, obb.tm.z.z);
		float e = dot(zaxis, delta);
		float f = dot(dir, zaxis);

		if (fabs(f) > 0.001f){

			float t1 = (e+obb.aabb.min.z)/f;
			float t2 = (e+obb.aabb.max.z)/f;

			if (t1>t2){float w=t1;t1=t2;t2=w;}

			if (t2 < tmax)
				tmax = t2;
			if (t1 > tmin)
				tmin = t1;

			if (tmin > tmax)
				return -1.0f;

		}
		else
		{
			if(-e+obb.aabb.min.z > 0.0f || -e+obb.aabb.max.z < 0.0f)
				return -1.0f;
		}
	}

	return tmin;
}

bool plane_3_intersection(const Plane& p1, const Plane& p2, const Plane& p3, Vector3& ip)
{
	const Vector3& n1 = p1.n;
	const Vector3& n2 = p2.n;
	const Vector3& n3 = p3.n;

	float den = -vector3::dot(vector3::cross(n1, n2), n3);

	if (equals(den, (float)0.0))
	{
		return false;
	}

	Vector3 res = p1.d * vector3::cross(n2, n3) + p2.d * vector3::cross(n3, n1) + p3.d * vector3::cross(n1, n2);
	ip = res / den;

	return true;
}

bool frustum_sphere_intersection(const Frustum& f, const Sphere& s)
{
	if (plane::distance_to_point(f.left, s.c) < -s.r ||
		plane::distance_to_point(f.right, s.c) < -s.r)
	{
		return false;
	}

	if (plane::distance_to_point(f.bottom, s.c) < -s.r ||
		plane::distance_to_point(f.top, s.c) < -s.r)
	{
		return false;
	}

	if (plane::distance_to_point(f.near, s.c) < -s.r ||
		plane::distance_to_point(f.far, s.c) < -s.r)
	{
		return false;
	}

	return true;
}

bool frustum_box_intersection(const Frustum& f, const AABB& b)
{
	uint8_t out;

	out = 0;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 0)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 1)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 2)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 3)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 4)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 5)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 6)) < 0.0) out++;
	if (plane::distance_to_point(f.left, aabb::vertex(b, 7)) < 0.0) out++;

	// If all vertices are outside one face, then the box doesn't intersect the frustum
	if (out == 8) return false;

	out = 0;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 0)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 1)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 2)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 3)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 4)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 5)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 6)) < 0.0) out++;
	if (plane::distance_to_point(f.right, aabb::vertex(b, 7)) < 0.0) out++;
	if (out == 8) return false;

	out = 0;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 0)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 1)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 2)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 3)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 4)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 5)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 6)) < 0.0) out++;
	if (plane::distance_to_point(f.bottom, aabb::vertex(b, 7)) < 0.0) out++;
	if (out == 8) return false;

	out = 0;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 0)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 1)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 2)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 3)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 4)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 5)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 6)) < 0.0) out++;
	if (plane::distance_to_point(f.top, aabb::vertex(b, 7)) < 0.0) out++;
	if (out == 8) return false;

	out = 0;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 0)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 1)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 2)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 3)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 4)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 5)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 6)) < 0.0) out++;
	if (plane::distance_to_point(f.near, aabb::vertex(b, 7)) < 0.0) out++;
	if (out == 8) return false;

	out = 0;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 0)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 1)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 2)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 3)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 4)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 5)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 6)) < 0.0) out++;
	if (plane::distance_to_point(f.far, aabb::vertex(b, 7)) < 0.0) out++;
	if (out == 8) return false;

	// If we are here, it is because either the box intersects or it is contained in the frustum
	return true;
}

} // namespace crown
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_pss_init.H $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file p9_pm_pss_init.H
/// @brief Initializes P2S and HWC logic
///
// *HWP HWP Owner: Amit Kumar <akumar3@us.ibm.com>
// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner: Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team: PM
// *HWP Level: 2
// *HWP Consumed by: FSP:HS

///
/// Procedure Summary:
/// --------------------
///    One procedure to initialize both P2S and HWC SPIPSS registers to
///    second Procedure is to access APSS or DPSS through P2S Bridge
///    Third procedure is to access APSS or DPSS through HWC (hardware control)
///
///    High-level procedure flow:
///     ----------------------------------
///      o INIT PROCEDURE(frame_size,cpol,cpha)
///         - set SPIPSS_ADC_CTRL_REG0(24b)
///             hwctrl_frame_size = 16
///         - set SPIPSS_ADC_CTRL_REG1
///             hwctrl_fsm_enable = disable
///             hwctrl_device     = APSS
///             hwctrl_cpol       = 0 (set idle state = deasserted)
///             hwctrl_cpha       = 0 (set 1st edge = capture 2nd edge = change)
///             hwctrl_clock_divider = set to 10Mhz(0x1D)
///             hwctrl_nr_of_frames (4b) = 16 (for auto 2 mode)
///         - set SPIPSS_ADC_CTRL_REG2
///                      hwctrl_interframe_delay = 0x0
///              - clear SPIPSS_ADC_WDATA_REG
///         - set SPIPSS_P2S_CTRL_REG0 (24b)
///             p2s_frame_size  = 16
///         - set SPIPSS_P2S_CTRL_REG1
///             p2s_bridge_enable = disable
///             p2s_device        = DPSS
///             p2s_cpol          = 0
///             p2s_cpha          = 0
///             p2s_clock_divider = set to 10Mhz
///             p2s_nr_of_frames (1b) = 0 (means 1 frame operation)
///         - set SPIPSS_P2S_CTRL_REG2
///                      p2s_interframe_delay = 0x0
///              - clear SPIPSS_P2S_WDATA_REG
/// Procedure Prereq:
///   o System clocks are running
///

#ifndef _P9_PM_PSS_INIT_H_
#define _P9_PM_PSS_INIT_H_

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <fapi2.H>
#include <p9_pm.H>
#include <p9_misc_scom_addresses.H>

typedef fapi2::ReturnCode (*p9_pm_pss_init_FP_t)
(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&,
 const p9pm::PM_FLOW_MODE);

extern "C"
{
//------------------------------------------------------------------------------
// Function prototype
//------------------------------------------------------------------------------
///
/// @brief Calls the underlying routine based on mode parameter to initialize
///        the PSS macro or reset it or configure the required attributes
///
/// @param[in] i_target Chip target
/// @param[in] i_mode   Control mode for the procedure:
///                     PM_INIT, PM_RESET
///
/// @return FAPI2_RC_SUCCESS if success, else error code
///
    fapi2::ReturnCode p9_pm_pss_init(
        const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
        const p9pm::PM_FLOW_MODE i_mode);
}
#endif // _P9_PM_PSS_INIT_H_
<commit_msg>Level 3: For various PM HWP<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_pss_init.H $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file p9_pm_pss_init.H
/// @brief Initializes P2S and HWC logic
///
// *HWP HW Owner        :   Greg Still <stillgs@us.ibm.com>
// *HWP Backup Owner    :   Prasad BG Ranganath <prasadbgr@in.ibm.com>
// *HWP FW Owner        :   Prem S Jha <premjha2@in.ibm.com>
// *HWP Team            :   PM
// *HWP Level           :   3
// *HWP Consumed by     :   HS

///
/// Procedure Summary:
/// --------------------
///    One procedure to initialize both P2S and HWC SPIPSS registers to
///    second Procedure is to access APSS or DPSS through P2S Bridge
///    Third procedure is to access APSS or DPSS through HWC (hardware control)
///
///    High-level procedure flow:
///     ----------------------------------
///      o INIT PROCEDURE(frame_size,cpol,cpha)
///         - set SPIPSS_ADC_CTRL_REG0(24b)
///             hwctrl_frame_size = 16
///         - set SPIPSS_ADC_CTRL_REG1
///             hwctrl_fsm_enable = disable
///             hwctrl_device     = APSS
///             hwctrl_cpol       = 0 (set idle state = deasserted)
///             hwctrl_cpha       = 0 (set 1st edge = capture 2nd edge = change)
///             hwctrl_clock_divider = set to 10Mhz(0x1D)
///             hwctrl_nr_of_frames (4b) = 16 (for auto 2 mode)
///         - set SPIPSS_ADC_CTRL_REG2
///                      hwctrl_interframe_delay = 0x0
///              - clear SPIPSS_ADC_WDATA_REG
///         - set SPIPSS_P2S_CTRL_REG0 (24b)
///             p2s_frame_size  = 16
///         - set SPIPSS_P2S_CTRL_REG1
///             p2s_bridge_enable = disable
///             p2s_device        = DPSS
///             p2s_cpol          = 0
///             p2s_cpha          = 0
///             p2s_clock_divider = set to 10Mhz
///             p2s_nr_of_frames (1b) = 0 (means 1 frame operation)
///         - set SPIPSS_P2S_CTRL_REG2
///                      p2s_interframe_delay = 0x0
///              - clear SPIPSS_P2S_WDATA_REG
/// Procedure Prereq:
///   o System clocks are running
///

#ifndef _P9_PM_PSS_INIT_H_
#define _P9_PM_PSS_INIT_H_

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <fapi2.H>
#include <p9_pm.H>
#include <p9_misc_scom_addresses.H>

typedef fapi2::ReturnCode (*p9_pm_pss_init_FP_t)
(const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&,
 const p9pm::PM_FLOW_MODE);

extern "C"
{
//------------------------------------------------------------------------------
// Function prototype
//------------------------------------------------------------------------------
///
/// @brief Calls the underlying routine based on mode parameter to initialize
///        the PSS macro or reset it or configure the required attributes
///
/// @param[in] i_target Chip target
/// @param[in] i_mode   Control mode for the procedure:
///                     PM_INIT, PM_RESET
///
/// @return FAPI2_RC_SUCCESS if success, else error code
///
    fapi2::ReturnCode p9_pm_pss_init(
        const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
        const p9pm::PM_FLOW_MODE i_mode);
}
#endif // _P9_PM_PSS_INIT_H_
<|endoftext|>


<commit_before>/*
 *   CrissCross
 *   A multi-purpose cross-platform library.
 *
 *   A product of Uplink Laboratories.
 *
 *   (c) 2006-2010 Steven Noonan.
 *   Licensed under the New BSD License.
 *
 */

#ifndef __included_cc_darray_h
#error "This file shouldn't be compiled directly."
#endif

#include <crisscross/debug.h>

#include <crisscross/darray.h>
#include <crisscross/dstack.h>

namespace CrissCross
{
	namespace Data
	{
		template <class T>
		DArray <T>::DArray()
		{
			m_stepSize = -1;
			m_numUsed = m_arraySize = 0;
			m_shadow = NULL;
			m_array = NULL;
			m_emptyNodes = new DStack<size_t>;
			m_emptyNodes->push((size_t)-1);
		}

		template <class T>
		DArray <T>::DArray(T *_array, size_t _indices)
		{
			m_array = new T[_indices];
			memcpy(m_array, _array, _indices * sizeof(T));

			m_shadow = new char[_indices];
			memset(m_shadow, 0, _indices * sizeof(char));

			m_numUsed = 0;
			for (size_t i = 0; i < _indices; i++) {
				m_shadow[i] = m_array[i] != NULL ? 1 : 0;
				if (m_shadow[i]) {
					m_numUsed++;
				}
			}

			m_arraySize = _indices;
			m_stepSize = -1;
			m_emptyNodes = new DStack<size_t>;

			rebuildStack();
		}

		template <class T>
		DArray <T>::DArray(DArray<T> const &_array)
		{
			m_array = new T[_array.m_arraySize];
			memcpy(m_array, _array.m_array, _array.m_arraySize * sizeof(T));

			m_shadow = new char[_array.m_arraySize];
			memset(m_shadow, 0, _array.m_arraySize * sizeof(char));

			m_numUsed = 0;
			for (size_t i = 0; i < _array.m_arraySize; i++)	{
				m_shadow[i] = m_array[i] != NULL ? 1 : 0;
				if (m_shadow[i]) {
					m_numUsed++;
				}
			}

			m_arraySize = _array.m_arraySize;
			m_stepSize = _array.m_stepSize;
			m_emptyNodes = new DStack<size_t>;

			rebuildStack();
		}

		template <class T>
		DArray <T>::DArray(int _newStepSize)
		{
			if (_newStepSize < 1)
				m_stepSize = -1;
			else
				m_stepSize = _newStepSize;

			m_numUsed = m_arraySize = 0;
			m_shadow = NULL;
			m_array = NULL;
			m_emptyNodes = new DStack<size_t> (_newStepSize + 1);
			m_emptyNodes->push((size_t)-1);
		}

		template <class T>
		DArray <T>::~DArray()
		{
			empty();
			delete m_emptyNodes;
			m_emptyNodes = NULL;
		}

		template <class T>
		void DArray <T>::rebuildStack()
		{
			/*  Reset free list */

			m_emptyNodes->empty();
			m_emptyNodes->push((size_t)-1);

			/* Step through, rebuilding */

			for (size_t i = m_arraySize - 1; (int)i >= 0; i--)
				if (m_shadow[i] == 0)
					m_emptyNodes->push(i);
		}

		template <class T>
		void DArray <T>::recount()
		{
			m_numUsed = 0;
			for (size_t i = 0; i < m_arraySize; i++)
				if (m_shadow[i] == 1)
					m_numUsed++;
		}

		template <class T>
		void DArray <T>::setSize(size_t newsize)
		{
			if (newsize > m_arraySize) {
				size_t oldarraysize = m_arraySize;

				m_arraySize = newsize;
				T *temparray = new T[m_arraySize];
				char *tempshadow = new char[m_arraySize];

				if (m_array && m_shadow) {
					memcpy(&temparray[0], &m_array[0], sizeof(temparray[0]) * oldarraysize);
					memcpy(&tempshadow[0], &m_shadow[0], sizeof(tempshadow[0]) * oldarraysize);
				}

				memset(&temparray[oldarraysize], 0, sizeof(temparray[0]) * (m_arraySize - oldarraysize));
				memset(&tempshadow[oldarraysize], 0, sizeof(tempshadow[0]) * (m_arraySize - oldarraysize));

				for (size_t a = m_arraySize - 1; (int)a >= (int)oldarraysize; a--) {
					m_emptyNodes->push(a);
				}

				delete [] m_array;
				delete [] m_shadow;

				m_array = temparray;
				m_shadow = tempshadow;
			} else if (newsize < m_arraySize) {
				m_arraySize = newsize;
				T *temparray = new T[m_arraySize];
				char *tempshadow = new char[m_arraySize];

				if (m_array && m_shadow) {
					memcpy(&temparray[0], &m_array[0], sizeof(temparray[0]) * m_arraySize);
					memcpy(&tempshadow[0], &m_shadow[0], sizeof(tempshadow[0]) * m_arraySize);
				}

				/* We may have lost more than one node. It's worth rebuilding over. */
				rebuildStack();
				recount();

				delete [] m_array;
				delete [] m_shadow;

				m_array = temparray;
				m_shadow = tempshadow;
			} else if (newsize == m_arraySize) {
				/* Do nothing */
			}
		}

		template <class T>
		void DArray <T>::grow()
		{
			if (m_stepSize == -1) {
				/* Double array size */
				if (m_arraySize == 0) {
					setSize(64);
				} else {
					setSize(m_arraySize * 2);
				}
			} else {
				/* Increase array size by fixed amount */
				setSize(m_arraySize + m_stepSize);
			}
		}

		template <class T>
		void DArray <T>::setStepSize(int _stepSize)
		{
			m_stepSize = _stepSize;
		}

		template <class T>
		void DArray <T>::setStepDouble()
		{
			m_stepSize = -1;
		}

		template <class T>
		size_t DArray <T>::insert(T const & newdata)
		{
			size_t freeslot = getNextFree();

			m_array[freeslot] = newdata;
			if (m_shadow[freeslot] == 0) m_numUsed++;

			m_shadow[freeslot] = 1;
			return freeslot;
		}

		template <class T>
		void DArray <T>::insert(T const & newdata, size_t index)
		{
			while (index >= m_arraySize) grow();

			m_array[index] = newdata;
			if (m_shadow[index] == 0) m_numUsed++;

			m_shadow[index] = 1;
		}

		template <class T>
		void DArray <T>::empty()
		{
			delete [] m_array;
			m_array = NULL;

			delete [] m_shadow;
			m_shadow = NULL;

			m_emptyNodes->empty();
			m_emptyNodes->push((size_t)-1);

			m_arraySize = 0;
			m_numUsed = 0;
		}

		template <class T>
		size_t DArray <T>::getNextFree()
		{
			/* WARNING: This function assumes the node returned */
			/*          will be used by the calling function. */

			if (!m_shadow)
				grow();

			size_t freeslot = (size_t)-2;

			while ((freeslot = m_emptyNodes->pop()) != (size_t)-1) {
				if (m_shadow[freeslot] == 0)
					break;
			}

			if (freeslot == (size_t)-1) {
				m_emptyNodes->push((size_t)-1);
				freeslot = m_arraySize;
				grow();
			}

			if (m_shadow[freeslot] == 0)
				m_numUsed++;

			m_shadow[freeslot] = 1;

			return freeslot;
		}

		template <class T>
		T DArray <T>::get(size_t index) const
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			return m_array[index];
		}

		template <class T>
		T & DArray <T>::operator [](size_t index)
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			return m_array[index];
		}

		template <class T>
		const T &DArray <T>::operator [](size_t index) const
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			return m_array[index];
		}

		template <class T>
		size_t DArray<T>::mem_usage() const
		{
			size_t ret = sizeof(*this);
			ret += m_arraySize * sizeof(T);
			ret += m_arraySize * sizeof(char);
			return ret;
		}

		template <class T>
		void DArray <T>::remove(size_t index)
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			m_emptyNodes->push(index);

			if (m_shadow[index] == 1) m_numUsed--;

			m_shadow[index] = 0;
		}

		template <class T>
		size_t DArray <T>::find(T const & newdata)
		{
			for (size_t a = 0; a < m_arraySize; ++a)
				if (m_shadow[a])
					if (Compare(m_array[a], newdata) == 0)
						return a;

			return -1;
		}

		template <class T>
		int DArray <T>::sort(Sorter<T> *_sortMethod)
		{
			int ret;

			if (m_numUsed < 2)
				return 0;

			T *temp_array = new T[m_numUsed];
			T *temp_ptr = temp_array;

			memset(temp_array, 0, m_numUsed * sizeof(T));

			for (size_t i = 0; i < m_arraySize; i++) {
				if (valid(i)) {
					*temp_ptr = m_array[i];
					temp_ptr++;
				}
			}

			ret = _sortMethod->Sort(temp_array, m_numUsed);

			delete [] m_shadow;
			m_shadow = new char[m_numUsed];
			memset(m_shadow, 1, m_numUsed);

			delete [] m_array;
			m_array = temp_array;

			m_arraySize = m_numUsed;

			rebuildStack();
			recount();

			return ret;
		}

		template <class T>
		int DArray <T>::sort(Sorter<T> &_sortMethod)
		{
			return sort(&_sortMethod);
		}

		template <class T>
		void DArray<T>::flush()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete m_array[i];
				}
			}
			empty();
		}

		template <class T>
		void DArray<T>::flushArray()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete [] m_array[i];
				}
			}
			empty();
		}

		/* BELOW ARE DEPRECATED FUNCTIONS */

#if !defined (DISABLE_DEPRECATED_CODE)
		template <class T>
		void DArray<T>::EmptyAndDelete()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete m_array[i];
				}
			}

			empty();
		}

		template <class T>
		void DArray<T>::EmptyAndDeleteArray()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete [] m_array[i];
				}
			}
			empty();
		}

		template <class T>
		void DArray<T>::ChangeData(T const & _rec, size_t index)
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);
			m_array[index] = _rec;
		}
#endif
	}
}
<commit_msg>darray: make growth heuristic less aggressive<commit_after>/*
 *   CrissCross
 *   A multi-purpose cross-platform library.
 *
 *   A product of Uplink Laboratories.
 *
 *   (c) 2006-2010 Steven Noonan.
 *   Licensed under the New BSD License.
 *
 */

#ifndef __included_cc_darray_h
#error "This file shouldn't be compiled directly."
#endif

#include <crisscross/debug.h>

#include <crisscross/darray.h>
#include <crisscross/dstack.h>

namespace CrissCross
{
	namespace Data
	{
		template <class T>
		DArray <T>::DArray()
		{
			m_stepSize = -1;
			m_numUsed = m_arraySize = 0;
			m_shadow = NULL;
			m_array = NULL;
			m_emptyNodes = new DStack<size_t>;
			m_emptyNodes->push((size_t)-1);
		}

		template <class T>
		DArray <T>::DArray(T *_array, size_t _indices)
		{
			m_array = new T[_indices];
			memcpy(m_array, _array, _indices * sizeof(T));

			m_shadow = new char[_indices];
			memset(m_shadow, 0, _indices * sizeof(char));

			m_numUsed = 0;
			for (size_t i = 0; i < _indices; i++) {
				m_shadow[i] = m_array[i] != NULL ? 1 : 0;
				if (m_shadow[i]) {
					m_numUsed++;
				}
			}

			m_arraySize = _indices;
			m_stepSize = -1;
			m_emptyNodes = new DStack<size_t>;

			rebuildStack();
		}

		template <class T>
		DArray <T>::DArray(DArray<T> const &_array)
		{
			m_array = new T[_array.m_arraySize];
			memcpy(m_array, _array.m_array, _array.m_arraySize * sizeof(T));

			m_shadow = new char[_array.m_arraySize];
			memset(m_shadow, 0, _array.m_arraySize * sizeof(char));

			m_numUsed = 0;
			for (size_t i = 0; i < _array.m_arraySize; i++)	{
				m_shadow[i] = m_array[i] != NULL ? 1 : 0;
				if (m_shadow[i]) {
					m_numUsed++;
				}
			}

			m_arraySize = _array.m_arraySize;
			m_stepSize = _array.m_stepSize;
			m_emptyNodes = new DStack<size_t>;

			rebuildStack();
		}

		template <class T>
		DArray <T>::DArray(int _newStepSize)
		{
			if (_newStepSize < 1)
				m_stepSize = -1;
			else
				m_stepSize = _newStepSize;

			m_numUsed = m_arraySize = 0;
			m_shadow = NULL;
			m_array = NULL;
			m_emptyNodes = new DStack<size_t> (_newStepSize + 1);
			m_emptyNodes->push((size_t)-1);
		}

		template <class T>
		DArray <T>::~DArray()
		{
			empty();
			delete m_emptyNodes;
			m_emptyNodes = NULL;
		}

		template <class T>
		void DArray <T>::rebuildStack()
		{
			/*  Reset free list */

			m_emptyNodes->empty();
			m_emptyNodes->push((size_t)-1);

			/* Step through, rebuilding */

			for (size_t i = m_arraySize - 1; (int)i >= 0; i--)
				if (m_shadow[i] == 0)
					m_emptyNodes->push(i);
		}

		template <class T>
		void DArray <T>::recount()
		{
			m_numUsed = 0;
			for (size_t i = 0; i < m_arraySize; i++)
				if (m_shadow[i] == 1)
					m_numUsed++;
		}

		template <class T>
		void DArray <T>::setSize(size_t newsize)
		{
			if (newsize > m_arraySize) {
				size_t oldarraysize = m_arraySize;

				m_arraySize = newsize;
				T *temparray = new T[m_arraySize];
				char *tempshadow = new char[m_arraySize];

				if (m_array && m_shadow) {
					memcpy(&temparray[0], &m_array[0], sizeof(temparray[0]) * oldarraysize);
					memcpy(&tempshadow[0], &m_shadow[0], sizeof(tempshadow[0]) * oldarraysize);
				}

				memset(&temparray[oldarraysize], 0, sizeof(temparray[0]) * (m_arraySize - oldarraysize));
				memset(&tempshadow[oldarraysize], 0, sizeof(tempshadow[0]) * (m_arraySize - oldarraysize));

				for (size_t a = m_arraySize - 1; (int)a >= (int)oldarraysize; a--) {
					m_emptyNodes->push(a);
				}

				delete [] m_array;
				delete [] m_shadow;

				m_array = temparray;
				m_shadow = tempshadow;
			} else if (newsize < m_arraySize) {
				m_arraySize = newsize;
				T *temparray = new T[m_arraySize];
				char *tempshadow = new char[m_arraySize];

				if (m_array && m_shadow) {
					memcpy(&temparray[0], &m_array[0], sizeof(temparray[0]) * m_arraySize);
					memcpy(&tempshadow[0], &m_shadow[0], sizeof(tempshadow[0]) * m_arraySize);
				}

				/* We may have lost more than one node. It's worth rebuilding over. */
				rebuildStack();
				recount();

				delete [] m_array;
				delete [] m_shadow;

				m_array = temparray;
				m_shadow = tempshadow;
			} else if (newsize == m_arraySize) {
				/* Do nothing */
			}
		}

		template <class T>
		void DArray <T>::grow()
		{
			/* Most of the data types we store in DArrays will the system
			 * pointer size. Try to keep our array approximately the size of
			 * a 4K page
			 */
			const size_t growthHeuristic = 4096 / sizeof(void *);

			if (m_stepSize == -1) {
				/* Double array size */
				if (m_arraySize == 0) {
					setSize(8);
				} else if (m_arraySize <= growthHeuristic) {
					setSize(m_arraySize * 2);
				} else {
					setSize(m_arraySize + growthHeuristic);
				}
			} else {
				/* Increase array size by fixed amount */
				setSize(m_arraySize + m_stepSize);
			}
		}

		template <class T>
		void DArray <T>::setStepSize(int _stepSize)
		{
			m_stepSize = _stepSize;
		}

		template <class T>
		void DArray <T>::setStepDouble()
		{
			m_stepSize = -1;
		}

		template <class T>
		size_t DArray <T>::insert(T const & newdata)
		{
			size_t freeslot = getNextFree();

			m_array[freeslot] = newdata;
			if (m_shadow[freeslot] == 0) m_numUsed++;

			m_shadow[freeslot] = 1;
			return freeslot;
		}

		template <class T>
		void DArray <T>::insert(T const & newdata, size_t index)
		{
			while (index >= m_arraySize) grow();

			m_array[index] = newdata;
			if (m_shadow[index] == 0) m_numUsed++;

			m_shadow[index] = 1;
		}

		template <class T>
		void DArray <T>::empty()
		{
			delete [] m_array;
			m_array = NULL;

			delete [] m_shadow;
			m_shadow = NULL;

			m_emptyNodes->empty();
			m_emptyNodes->push((size_t)-1);

			m_arraySize = 0;
			m_numUsed = 0;
		}

		template <class T>
		size_t DArray <T>::getNextFree()
		{
			/* WARNING: This function assumes the node returned */
			/*          will be used by the calling function. */

			if (!m_shadow)
				grow();

			size_t freeslot = (size_t)-2;

			while ((freeslot = m_emptyNodes->pop()) != (size_t)-1) {
				if (m_shadow[freeslot] == 0)
					break;
			}

			if (freeslot == (size_t)-1) {
				m_emptyNodes->push((size_t)-1);
				freeslot = m_arraySize;
				grow();
			}

			if (m_shadow[freeslot] == 0)
				m_numUsed++;

			m_shadow[freeslot] = 1;

			return freeslot;
		}

		template <class T>
		T DArray <T>::get(size_t index) const
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			return m_array[index];
		}

		template <class T>
		T & DArray <T>::operator [](size_t index)
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			return m_array[index];
		}

		template <class T>
		const T &DArray <T>::operator [](size_t index) const
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			return m_array[index];
		}

		template <class T>
		size_t DArray<T>::mem_usage() const
		{
			size_t ret = sizeof(*this);
			ret += m_arraySize * sizeof(T);
			ret += m_arraySize * sizeof(char);
			return ret;
		}

		template <class T>
		void DArray <T>::remove(size_t index)
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);

			m_emptyNodes->push(index);

			if (m_shadow[index] == 1) m_numUsed--;

			m_shadow[index] = 0;
		}

		template <class T>
		size_t DArray <T>::find(T const & newdata)
		{
			for (size_t a = 0; a < m_arraySize; ++a)
				if (m_shadow[a])
					if (Compare(m_array[a], newdata) == 0)
						return a;

			return -1;
		}

		template <class T>
		int DArray <T>::sort(Sorter<T> *_sortMethod)
		{
			int ret;

			if (m_numUsed < 2)
				return 0;

			T *temp_array = new T[m_numUsed];
			T *temp_ptr = temp_array;

			memset(temp_array, 0, m_numUsed * sizeof(T));

			for (size_t i = 0; i < m_arraySize; i++) {
				if (valid(i)) {
					*temp_ptr = m_array[i];
					temp_ptr++;
				}
			}

			ret = _sortMethod->Sort(temp_array, m_numUsed);

			delete [] m_shadow;
			m_shadow = new char[m_numUsed];
			memset(m_shadow, 1, m_numUsed);

			delete [] m_array;
			m_array = temp_array;

			m_arraySize = m_numUsed;

			rebuildStack();
			recount();

			return ret;
		}

		template <class T>
		int DArray <T>::sort(Sorter<T> &_sortMethod)
		{
			return sort(&_sortMethod);
		}

		template <class T>
		void DArray<T>::flush()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete m_array[i];
				}
			}
			empty();
		}

		template <class T>
		void DArray<T>::flushArray()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete [] m_array[i];
				}
			}
			empty();
		}

		/* BELOW ARE DEPRECATED FUNCTIONS */

#if !defined (DISABLE_DEPRECATED_CODE)
		template <class T>
		void DArray<T>::EmptyAndDelete()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete m_array[i];
				}
			}

			empty();
		}

		template <class T>
		void DArray<T>::EmptyAndDeleteArray()
		{
			for (size_t i = 0; i < m_arraySize; ++i) {
				if (valid(i)) {
					delete [] m_array[i];
				}
			}
			empty();
		}

		template <class T>
		void DArray<T>::ChangeData(T const & _rec, size_t index)
		{
			CoreAssert(index < m_arraySize);
			CoreAssert(m_shadow[index]);
			m_array[index] = _rec;
		}
#endif
	}
}
<|endoftext|>


<commit_before><commit_msg>darray: check validity of index before using<commit_after><|endoftext|>