<commit_before>#include "ProcessLock.hh"

#ifdef LINUX
#include <linux/futex.h>
#include <sys/syscall.h>
#else
#include <sched.h>
#endif

#include <stdexcept>

#include <phosg/Process.hh>
#include <phosg/Strings.hh>

using namespace std;

namespace sharedstructures {

bool ProcessLock::is_locked() const {
  return this->lock.load() != 0;
}

bool ProcessReadWriteLock::is_locked(bool writing) const {
  if (writing) {
    return this->write_lock.load() != 0;
  }

  for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
    if (this->reader_tokens[x].load() != 0) {
      return true;
    }
  }
  return false;
}

static const uint8_t PID_BITS = 18;
static const uint8_t START_TIME_BITS = 32 - PID_BITS;
static const uint8_t SPIN_LIMIT = 10;

static int32_t this_process_token() {
  return (this_process_start_time() << PID_BITS) | getpid_cached();
}

static int32_t start_time_for_token(int32_t token) {
  return (token & ~((1 << PID_BITS) - 1)) >> PID_BITS;
}

static pid_t pid_for_token(int32_t token) {
  return token & ((1 << PID_BITS) - 1);
}

static int32_t mask_start_time(int32_t start_time) {
  return start_time & ((1 << START_TIME_BITS) - 1);
}

static bool process_for_token_is_running(int32_t token) {
  pid_t pid = pid_for_token(token);
  uint64_t start_time_token = start_time_for_token(token);
  uint64_t start_time = start_time_for_pid(pid);
  return (start_time != 0) &&
         (mask_start_time(start_time) == mask_start_time(start_time_token));
}

#ifdef LINUX

static bool futex_wait(atomic<int32_t>* lock, int32_t expected_value,
    const struct timespec* timeout) {
  if (syscall(SYS_futex, lock, FUTEX_WAIT, expected_value, timeout, NULL, 0) == -1) {
    if ((errno != EAGAIN) && (errno != EINTR) && (errno != ETIMEDOUT) && (errno != EWOULDBLOCK)) {
      throw runtime_error("futex_wait failed: " + string_for_error(errno));
    }
    return false;
  }
  return true;
}

static void futex_wake(atomic<int32_t>* lock, int32_t num_wakes) {
  if (syscall(SYS_futex, lock, FUTEX_WAKE, 0, NULL, NULL, 0) == -1) {
    throw runtime_error("futex_wake failed: " + string_for_error(errno));
  }
}

static bool acquire_process_lock(atomic<int32_t>* lock) {
  static const struct timespec timeout = {1, 0}; // 1 second
  int32_t desired_value = this_process_token();

  for (;;) {
    int32_t expected_value = 0;
    if (lock->compare_exchange_strong(expected_value, desired_value)) {
      return false;
    }

    // someone else is holding the lock; wait for them to be done.
    // expected_value now contains the other process' token (not zero). if we
    // were not woken by FUTEX_WAKE, then another process may still be holding
    // the lock; check if it's running.
    if (!futex_wait(lock, expected_value, &timeout)) {
      if (!process_for_token_is_running(expected_value)) {
        // the holding process died; steal the lock from it. if we get the lock,
        // repair the allocator structures since they could be in an
        // inconsistent state. if we don't get the lock, then another process
        // got there first and we'll just keep waiting
        if (lock->compare_exchange_strong(expected_value, desired_value)) {
          return true;
        }
      }
    }
  }
}

static void release_process_lock(atomic<int32_t>* lock) {
  lock->store(0);
  futex_wake(lock, 1);
}

static bool wait_for_reader_release(atomic<int32_t>* lock,
    int32_t existing_token) {
  static const struct timespec timeout = {1, 0}; // 1 second

  while (!futex_wait(lock, existing_token, &timeout)) {
    if (!process_for_token_is_running(existing_token)) {
      lock->store(0);
      return true;
    }
  }
  return false;
}

#else // MACOSX

static bool acquire_process_lock(atomic<int32_t>* lock) {
  int32_t desired_value = this_process_token();

  for (;;) {
    // try several times to get the lock
    int32_t expected_value;
    uint8_t spin_count = 0;
    while (spin_count < SPIN_LIMIT) {
      expected_value = 0;
      if (lock->compare_exchange_weak(expected_value, desired_value)) {
        return false;
      }
      spin_count++;
    }

    // if we didn't get the lock, wait up to 1 second, then check if the holder
    // is still running

    // os x doesn't have futex
    // TODO: implement futex-like functionality on osx
    sched_yield();

    if (!process_for_token_is_running(expected_value)) {
      // the holding process died; steal the lock from it. if we get the lock,
      // repair the allocator structures since they could be in an
      // inconsistent state. if we don't get the lock, then another process
      // got there first and we'll just keep waiting
      if (lock->compare_exchange_strong(expected_value, desired_value)) {
        return true;
      }
    }
  }
}

static void release_process_lock(atomic<int32_t>* lock) {
  lock->store(0);
}

static bool wait_for_reader_release(atomic<int32_t>* lock,
    int32_t existing_token) {
  // TODO: do something better here (no futex on os x)
  while (lock->load()) {
    sched_yield();
    if (!process_for_token_is_running(existing_token)) {
      if (lock->compare_exchange_strong(existing_token, 0)) {
        return true;
      }
    }
  }
  return false;
}

#endif

static void release_cb(void* void_lock, size_t size) {
  atomic<int32_t>* lock = reinterpret_cast<atomic<int32_t>*>(void_lock);
  release_process_lock(lock);
}

static void wait_for_reader_drain(ProcessReadWriteLock* data, bool wait_all) {
  if (wait_all) {
    for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
      int32_t existing_token = data->reader_tokens[x].load();
      if (existing_token == 0) {
        continue; // no process in this reader slot
      }

      // wait for this reader to release. if they don't, then check if the
      // process is still running, and clear the lock if it's not. because this
      // process was a reader, we don't need to repair the allocator state if we
      // cleared its lock.
      wait_for_reader_release(&data->reader_tokens[x], existing_token);
    }

  } else {
    // first check for an empty slot and return it if found
    for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
      int32_t existing_token = data->reader_tokens[x].load();
      if (existing_token == 0) {
        return;
      }
    }

    // no empty slots; pick an "arbitrary" slot and wait on it
    int32_t reader_slot = getpid_cached() % NUM_READER_SLOTS;
    int32_t existing_token = data->reader_tokens[reader_slot].load();
    wait_for_reader_release(&data->reader_tokens[reader_slot], existing_token);
  }
}

ProcessLockGuard::ProcessLockGuard(ProcessLockGuard&& other) :
    stolen(other.stolen), pool(other.pool), offset(other.offset) {
  other.pool = NULL;
}

ProcessLockGuard::ProcessLockGuard(Pool* pool, uint64_t offset) : stolen(false),
    pool(pool), offset(offset) {
  atomic<int32_t>* lock = this->pool->at<atomic<int32_t>>(this->offset);
  this->stolen = acquire_process_lock(lock);
}

ProcessLockGuard::~ProcessLockGuard() {
  if (!this->pool) {
    return;
  }

  try {
    atomic<int32_t>* lock = this->pool->at<atomic<int32_t>>(this->offset);
    release_process_lock(lock);
  } catch (const bad_alloc& e) {
    // this can happen if the pool was expanded and no longer fits in this
    // process' address space
    this->pool->map_and_call(this->offset, sizeof(int32_t), &release_cb);
    throw;
  }
}

size_t ProcessLockGuard::data_size() {
  // everything must be 64-bit aligned, so even though we only use 32 bits, we
  // claim to use 64
  return sizeof(int64_t);
}

ProcessReadWriteLockGuard::ProcessReadWriteLockGuard(
    ProcessReadWriteLockGuard&& other) : stolen(other.stolen), pool(other.pool),
    offset(other.offset), reader_slot(other.reader_slot) {
  other.pool = NULL;
}

ProcessReadWriteLockGuard::ProcessReadWriteLockGuard(Pool* pool,
    uint64_t offset, bool writing) : stolen(false), pool(pool), offset(offset) {
  auto* data = this->pool->at<ProcessReadWriteLock>(this->offset);

  if (writing) {
    // take the write lock, then wait for readers to drain or die. because we're
    // holding the write lock, no new readers can be added
    this->reader_slot = -1;
    this->stolen = acquire_process_lock(&data->write_lock);
    wait_for_reader_drain(data, true);

  } else {
    this->reader_slot = NUM_READER_SLOTS;

    int32_t reader_token = this_process_token();
    do {
      // take the write lock, find an empty reader slot and take it, then release
      // the write lock
      acquire_process_lock(&data->write_lock);
      for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
        if (data->reader_tokens[x] == 0) {
          data->reader_tokens[x].store(reader_token);
          this->reader_slot = x;
          break;
        }
      }
      release_process_lock(&data->write_lock);

      // if there were no available reader slots, wait for any slot to drain and
      // try again
      if (this->reader_slot == NUM_READER_SLOTS) {
        wait_for_reader_drain(data, false);
      }
    } while (this->reader_slot == NUM_READER_SLOTS);
  }
}

ProcessReadWriteLockGuard::~ProcessReadWriteLockGuard() {
  if (!this->pool) {
    return;
  }

  auto* data = this->pool->at<ProcessReadWriteLock>(this->offset);
  if (this->reader_slot < 0) {
    release_process_lock(&data->write_lock);
  } else {
    release_process_lock(&data->reader_tokens[this->reader_slot]);
  }
}

} // namespace sharedstructures
<commit_msg>fix incorrect return checking for futex_wait<commit_after>#include "ProcessLock.hh"

#ifdef LINUX
#include <linux/futex.h>
#include <sys/syscall.h>
#else
#include <sched.h>
#endif

#include <stdexcept>

#include <phosg/Process.hh>
#include <phosg/Strings.hh>

using namespace std;

namespace sharedstructures {

bool ProcessLock::is_locked() const {
  return this->lock.load() != 0;
}

bool ProcessReadWriteLock::is_locked(bool writing) const {
  if (writing) {
    return this->write_lock.load() != 0;
  }

  for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
    if (this->reader_tokens[x].load() != 0) {
      return true;
    }
  }
  return false;
}

static const uint8_t PID_BITS = 18;
static const uint8_t START_TIME_BITS = 32 - PID_BITS;
static const uint8_t SPIN_LIMIT = 10;

static int32_t this_process_token() {
  return (this_process_start_time() << PID_BITS) | getpid_cached();
}

static int32_t start_time_for_token(int32_t token) {
  return (token & ~((1 << PID_BITS) - 1)) >> PID_BITS;
}

static pid_t pid_for_token(int32_t token) {
  return token & ((1 << PID_BITS) - 1);
}

static int32_t mask_start_time(int32_t start_time) {
  return start_time & ((1 << START_TIME_BITS) - 1);
}

static bool process_for_token_is_running(int32_t token) {
  pid_t pid = pid_for_token(token);
  uint64_t start_time_token = start_time_for_token(token);
  uint64_t start_time = start_time_for_pid(pid);
  return (start_time != 0) &&
         (mask_start_time(start_time) == mask_start_time(start_time_token));
}

#ifdef LINUX

static bool futex_wait(atomic<int32_t>* lock, int32_t expected_value,
    const struct timespec* timeout) {
  if (syscall(SYS_futex, lock, FUTEX_WAIT, expected_value, timeout, NULL, 0) == -1) {
    if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
      return true; // value didn't match the input
    }
    if ((errno == EINTR) || (errno == ETIMEDOUT)) {
      return false; // timed out or interrupted
    }
    // some other thing
    throw runtime_error("futex_wait failed: " + string_for_error(errno));
  }
  return true;
}

static void futex_wake(atomic<int32_t>* lock, int32_t num_wakes) {
  if (syscall(SYS_futex, lock, FUTEX_WAKE, 0, NULL, NULL, 0) == -1) {
    throw runtime_error("futex_wake failed: " + string_for_error(errno));
  }
}

static bool acquire_process_lock(atomic<int32_t>* lock) {
  static const struct timespec timeout = {1, 0}; // 1 second
  int32_t desired_value = this_process_token();

  for (;;) {
    int32_t expected_value = 0;
    if (lock->compare_exchange_strong(expected_value, desired_value)) {
      return false;
    }

    // someone else is holding the lock; wait for them to be done.
    // expected_value now contains the other process' token (not zero). if we
    // were not woken by FUTEX_WAKE, then another process may still be holding
    // the lock; check if it's running.
    if (!futex_wait(lock, expected_value, &timeout)) {
      if (!process_for_token_is_running(expected_value)) {
        // the holding process died; steal the lock from it. if we get the lock,
        // repair the allocator structures since they could be in an
        // inconsistent state. if we don't get the lock, then another process
        // got there first and we'll just keep waiting
        if (lock->compare_exchange_strong(expected_value, desired_value)) {
          return true;
        }
      }
    }
  }
}

static void release_process_lock(atomic<int32_t>* lock) {
  lock->store(0);
  futex_wake(lock, 1);
}

static bool wait_for_reader_release(atomic<int32_t>* lock,
    int32_t existing_token) {
  static const struct timespec timeout = {1, 0}; // 1 second

  while (!futex_wait(lock, existing_token, &timeout)) {
    if (!process_for_token_is_running(existing_token)) {
      lock->store(0);
      return true;
    }
  }
  return false;
}

#else // MACOSX

static bool acquire_process_lock(atomic<int32_t>* lock) {
  int32_t desired_value = this_process_token();

  for (;;) {
    // try several times to get the lock
    int32_t expected_value;
    uint8_t spin_count = 0;
    while (spin_count < SPIN_LIMIT) {
      expected_value = 0;
      if (lock->compare_exchange_weak(expected_value, desired_value)) {
        return false;
      }
      spin_count++;
    }

    // if we didn't get the lock, wait up to 1 second, then check if the holder
    // is still running

    // os x doesn't have futex
    // TODO: implement futex-like functionality on osx
    sched_yield();

    if (!process_for_token_is_running(expected_value)) {
      // the holding process died; steal the lock from it. if we get the lock,
      // repair the allocator structures since they could be in an
      // inconsistent state. if we don't get the lock, then another process
      // got there first and we'll just keep waiting
      if (lock->compare_exchange_strong(expected_value, desired_value)) {
        return true;
      }
    }
  }
}

static void release_process_lock(atomic<int32_t>* lock) {
  lock->store(0);
}

static bool wait_for_reader_release(atomic<int32_t>* lock,
    int32_t existing_token) {
  // TODO: do something better here (no futex on os x)
  while (lock->load()) {
    sched_yield();
    if (!process_for_token_is_running(existing_token)) {
      if (lock->compare_exchange_strong(existing_token, 0)) {
        return true;
      }
    }
  }
  return false;
}

#endif

static void release_cb(void* void_lock, size_t size) {
  atomic<int32_t>* lock = reinterpret_cast<atomic<int32_t>*>(void_lock);
  release_process_lock(lock);
}

static void wait_for_reader_drain(ProcessReadWriteLock* data, bool wait_all) {
  if (wait_all) {
    for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
      int32_t existing_token = data->reader_tokens[x].load();
      if (existing_token == 0) {
        continue; // no process in this reader slot
      }

      // wait for this reader to release. if they don't, then check if the
      // process is still running, and clear the lock if it's not. because this
      // process was a reader, we don't need to repair the allocator state if we
      // cleared its lock.
      wait_for_reader_release(&data->reader_tokens[x], existing_token);
    }

  } else {
    // first check for an empty slot and return it if found
    for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
      int32_t existing_token = data->reader_tokens[x].load();
      if (existing_token == 0) {
        return;
      }
    }

    // no empty slots; pick an "arbitrary" slot and wait on it
    int32_t reader_slot = getpid_cached() % NUM_READER_SLOTS;
    int32_t existing_token = data->reader_tokens[reader_slot].load();
    wait_for_reader_release(&data->reader_tokens[reader_slot], existing_token);
  }
}

ProcessLockGuard::ProcessLockGuard(ProcessLockGuard&& other) :
    stolen(other.stolen), pool(other.pool), offset(other.offset) {
  other.pool = NULL;
}

ProcessLockGuard::ProcessLockGuard(Pool* pool, uint64_t offset) : stolen(false),
    pool(pool), offset(offset) {
  atomic<int32_t>* lock = this->pool->at<atomic<int32_t>>(this->offset);
  this->stolen = acquire_process_lock(lock);
}

ProcessLockGuard::~ProcessLockGuard() {
  if (!this->pool) {
    return;
  }

  try {
    atomic<int32_t>* lock = this->pool->at<atomic<int32_t>>(this->offset);
    release_process_lock(lock);
  } catch (const bad_alloc& e) {
    // this can happen if the pool was expanded and no longer fits in this
    // process' address space
    this->pool->map_and_call(this->offset, sizeof(int32_t), &release_cb);
  }
}

size_t ProcessLockGuard::data_size() {
  // everything must be 64-bit aligned, so even though we only use 32 bits, we
  // claim to use 64
  return sizeof(int64_t);
}

ProcessReadWriteLockGuard::ProcessReadWriteLockGuard(
    ProcessReadWriteLockGuard&& other) : stolen(other.stolen), pool(other.pool),
    offset(other.offset), reader_slot(other.reader_slot) {
  other.pool = NULL;
}

ProcessReadWriteLockGuard::ProcessReadWriteLockGuard(Pool* pool,
    uint64_t offset, bool writing) : stolen(false), pool(pool), offset(offset) {
  auto* data = this->pool->at<ProcessReadWriteLock>(this->offset);

  if (writing) {
    // take the write lock, then wait for readers to drain or die. because we're
    // holding the write lock, no new readers can be added
    this->reader_slot = -1;
    this->stolen = acquire_process_lock(&data->write_lock);
    wait_for_reader_drain(data, true);

  } else {
    this->reader_slot = NUM_READER_SLOTS;

    int32_t reader_token = this_process_token();
    do {
      // take the write lock, find an empty reader slot and take it, then release
      // the write lock
      acquire_process_lock(&data->write_lock);
      for (size_t x = 0; x < NUM_READER_SLOTS; x++) {
        if (data->reader_tokens[x] == 0) {
          data->reader_tokens[x].store(reader_token);
          this->reader_slot = x;
          break;
        }
      }
      release_process_lock(&data->write_lock);

      // if there were no available reader slots, wait for any slot to drain and
      // try again
      if (this->reader_slot == NUM_READER_SLOTS) {
        wait_for_reader_drain(data, false);
      }
    } while (this->reader_slot == NUM_READER_SLOTS);
  }
}

ProcessReadWriteLockGuard::~ProcessReadWriteLockGuard() {
  if (!this->pool) {
    return;
  }

  auto* data = this->pool->at<ProcessReadWriteLock>(this->offset);
  if (this->reader_slot < 0) {
    release_process_lock(&data->write_lock);
  } else {
    release_process_lock(&data->reader_tokens[this->reader_slot]);
  }
}

} // namespace sharedstructures
<|endoftext|>


<commit_before>// This code is based on Sabberstone project.
// Copyright (c) 2017-2018 SabberStone Team, darkfriend77 & rnilva
// Hearthstone++ is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <hspp/Actions/Draw.hpp>
#include <hspp/Actions/Generic.hpp>
#include <hspp/Cards/Cards.hpp>
#include <hspp/Games/Game.hpp>
#include <hspp/Games/GameManager.hpp>

#include <effolkronium/random.hpp>

#include <algorithm>

using Random = effolkronium::random_static;

namespace Hearthstonepp
{
Game::Game(GameConfig& gameConfig) : m_gameConfig(gameConfig)
{
    // Set game to player
    for (auto& p : m_players)
    {
        p.SetGame(this);
    }

    // Add hero and hero power
    GetPlayer1().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player1Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player1Class));
    GetPlayer2().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player2Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player2Class));

    // Set opponent player
    GetPlayer1().SetOpponent(&GetPlayer2());
    GetPlayer2().SetOpponent(&GetPlayer1());
}

Player& Game::GetPlayer1()
{
    return m_players[0];
}

Player& Game::GetPlayer2()
{
    return m_players[1];
}

Player& Game::GetCurrentPlayer()
{
    return *m_currentPlayer;
}

Player& Game::GetOpponentPlayer()
{
    return m_currentPlayer->GetOpponent();
}

std::size_t Game::GetNextID()
{
    return m_entityID++;
}

std::size_t Game::GetNextOOP()
{
    return m_oopIndex++;
}

void Game::BeginFirst()
{
    // Set next step
    nextStep = Step::BEGIN_SHUFFLE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginShuffle()
{
    // Shuffle cards in deck
    if (m_gameConfig.doShuffle)
    {
        GetPlayer1().GetDeck().Shuffle();
        GetPlayer2().GetDeck().Shuffle();
    }

    // Set next step
    nextStep = Step::BEGIN_DRAW;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginDraw()
{
    for (auto& p : m_players)
    {
        // Draw 3 cards
        Generic::Draw(p);
        Generic::Draw(p);
        Generic::Draw(p);

        if (&p != m_firstPlayer)
        {
            // Draw 4th card for second player
            Generic::Draw(p);

            // Give "The Coin" card to second player
            Card coin = Cards::GetInstance().FindCardByID("GAME_005");
            p.GetHand().AddCard(*Entity::GetFromCard(p, std::move(coin)));
        }
    }

    // Set next step
    nextStep =
        m_gameConfig.skipMulligan ? Step::MAIN_BEGIN : Step::BEGIN_MULLIGAN;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginMulligan()
{
    // Start mulligan state
    GetPlayer1().mulliganState = Mulligan::INPUT;
    GetPlayer2().mulliganState = Mulligan::INPUT;
}

void Game::MainBegin()
{
    // Set next step
    nextStep = Step::MAIN_READY;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainReady()
{
    // Reset the number of attacked
    for (auto& p : m_players)
    {
        // Hero
        p.GetHero()->numAttacked = 0;
        // Field
        for (auto& m : p.GetField().GetAllMinions())
        {
            m->numAttacked = 0;
        }
    }

    // Reset exhaust for current player
    auto& curPlayer = GetCurrentPlayer();
    // Hero
    curPlayer.GetHero()->SetGameTag(GameTag::EXHAUSTED, 0);
    // Weapon
    if (curPlayer.GetHero()->weapon != nullptr)
    {
        curPlayer.GetHero()->weapon->SetGameTag(GameTag::EXHAUSTED, 0);
    }
    // Hero power
    curPlayer.GetHero()->heroPower->SetGameTag(GameTag::EXHAUSTED, 0);
    // Field
    for (auto& m : curPlayer.GetField().GetAllMinions())
    {
        m->SetGameTag(GameTag::EXHAUSTED, 0);
    }

    // Set next step
    nextStep = Step::MAIN_START_TRIGGERS;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainStartTriggers()
{
    // Set next step
    nextStep = Step::MAIN_RESOURCE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainResource()
{
    auto& curPlayer = GetCurrentPlayer();

    // Add mana crystal to current player
    Generic::ChangeManaCrystal(curPlayer, 1, false);

    // Reset current mana
    curPlayer.currentMana = curPlayer.maximumMana;

    // Set next step
    nextStep = Step::MAIN_DRAW;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainDraw()
{
    // Draw a card for current player
    Generic::Draw(GetCurrentPlayer());

    // Set next step
    nextStep = Step::MAIN_START;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainStart()
{
    // Set next step
    nextStep = Step::MAIN_ACTION;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainEnd()
{
    // Set next step
    nextStep = Step::MAIN_CLEANUP;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainCleanUp()
{
    auto& curPlayer = GetCurrentPlayer();

    // Unfreeze all characters they control that are Frozen, don't have
    // summoning sickness (or do have Charge) and have not attacked that turn
    // Hero
    if (curPlayer.GetHero()->GetGameTag(GameTag::FROZEN) == 1 &&
        curPlayer.GetHero()->numAttacked == 0)
    {
        curPlayer.GetHero()->SetGameTag(GameTag::FROZEN, 0);
    }
    // Field
    for (auto& m : curPlayer.GetField().GetAllMinions())
    {
        if (m->GetGameTag(GameTag::FROZEN) == 1 && m->numAttacked == 0 &&
            m->GetGameTag(GameTag::EXHAUSTED) == 0)
        {
            m->SetGameTag(GameTag::FROZEN, 0);
        }
    }

    // Set next step
    nextStep = Step::MAIN_NEXT;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainNext()
{
    // Set player for next turn
    m_currentPlayer = &m_currentPlayer->GetOpponent();

    // Count next turn
    m_turn++;

    // Set next step
    nextStep = Step::MAIN_READY;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::FinalWrapUp()
{
    // Set game states according by result
    for (auto& p : m_players)
    {
        if (p.playState == +PlayState::LOSING ||
            p.playState == +PlayState::CONCEDED)
        {
            p.playState = PlayState::LOST;
            p.GetOpponent().playState = PlayState::WON;
        }
    }

    // Set next step
    nextStep = Step::FINAL_GAMEOVER;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::FinalGameOver()
{
    // Set game state to complete
    state = State::COMPLETE;
}

void Game::StartGame()
{
    // Reverse card order in deck
    if (!m_gameConfig.doShuffle)
    {
        std::reverse(m_gameConfig.player1Deck.begin(),
                     m_gameConfig.player1Deck.end());
        std::reverse(m_gameConfig.player2Deck.begin(),
                     m_gameConfig.player2Deck.end());
    }

    // Set up decks
    for (auto& card : m_gameConfig.player1Deck)
    {
        if (card.cardType == +CardType::INVALID)
        {
            continue;
        }

        Entity* entity = Entity::GetFromCard(GetPlayer1(), std::move(card));
        GetPlayer1().GetDeck().AddCard(*entity);
    }
    for (auto& card : m_gameConfig.player2Deck)
    {
        if (card.cardType == +CardType::INVALID)
        {
            continue;
        }

        Entity* entity = Entity::GetFromCard(GetPlayer2(), std::move(card));
        GetPlayer2().GetDeck().AddCard(*entity);
    }

    // Fill cards to deck
    if (m_gameConfig.doFillDecks)
    {
        for (auto& p : m_players)
        {
            for (auto& cardID : m_gameConfig.fillCardIDs)
            {
                Card card = Cards::GetInstance().FindCardByID(cardID);
                Entity* entity = Entity::GetFromCard(p, std::move(card));
                p.GetDeck().AddCard(*entity);
            }
        }
    }

    // Set game states
    state = State::RUNNING;
    for (auto& p : m_players)
    {
        p.playState = PlayState::PLAYING;
    }

    // Determine first player
    switch (m_gameConfig.startPlayer)
    {
        case PlayerType::RANDOM:
        {
            auto val = Random::get(0, 1);
            m_firstPlayer = &m_players[val];
            break;
        }
        case PlayerType::PLAYER1:
            m_firstPlayer = &m_players[0];
            break;
        case PlayerType::PLAYER2:
            m_firstPlayer = &m_players[1];
            break;
    }
    m_currentPlayer = m_firstPlayer;

    // Set first turn
    m_turn = 1;

    // Set next step
    nextStep = Step::BEGIN_FIRST;
    GameManager::ProcessNextStep(*this, nextStep);
}
}  // namespace Hearthstonepp<commit_msg>[ci skip] feat(game-state): Implement BeginMulligan() method<commit_after>// This code is based on Sabberstone project.
// Copyright (c) 2017-2018 SabberStone Team, darkfriend77 & rnilva
// Hearthstone++ is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2018 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <hspp/Actions/Choose.hpp>
#include <hspp/Actions/Draw.hpp>
#include <hspp/Actions/Generic.hpp>
#include <hspp/Cards/Cards.hpp>
#include <hspp/Games/Game.hpp>
#include <hspp/Games/GameManager.hpp>

#include <effolkronium/random.hpp>

#include <algorithm>

using Random = effolkronium::random_static;

namespace Hearthstonepp
{
Game::Game(GameConfig& gameConfig) : m_gameConfig(gameConfig)
{
    // Set game to player
    for (auto& p : m_players)
    {
        p.SetGame(this);
    }

    // Add hero and hero power
    GetPlayer1().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player1Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player1Class));
    GetPlayer2().AddHeroAndPower(
        Cards::GetInstance().GetHeroCard(gameConfig.player2Class),
        Cards::GetInstance().GetDefaultHeroPower(gameConfig.player2Class));

    // Set opponent player
    GetPlayer1().SetOpponent(&GetPlayer2());
    GetPlayer2().SetOpponent(&GetPlayer1());
}

Player& Game::GetPlayer1()
{
    return m_players[0];
}

Player& Game::GetPlayer2()
{
    return m_players[1];
}

Player& Game::GetCurrentPlayer()
{
    return *m_currentPlayer;
}

Player& Game::GetOpponentPlayer()
{
    return m_currentPlayer->GetOpponent();
}

std::size_t Game::GetNextID()
{
    return m_entityID++;
}

std::size_t Game::GetNextOOP()
{
    return m_oopIndex++;
}

void Game::BeginFirst()
{
    // Set next step
    nextStep = Step::BEGIN_SHUFFLE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginShuffle()
{
    // Shuffle cards in deck
    if (m_gameConfig.doShuffle)
    {
        GetPlayer1().GetDeck().Shuffle();
        GetPlayer2().GetDeck().Shuffle();
    }

    // Set next step
    nextStep = Step::BEGIN_DRAW;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginDraw()
{
    for (auto& p : m_players)
    {
        // Draw 3 cards
        Generic::Draw(p);
        Generic::Draw(p);
        Generic::Draw(p);

        if (&p != m_firstPlayer)
        {
            // Draw 4th card for second player
            Generic::Draw(p);

            // Give "The Coin" card to second player
            Card coin = Cards::GetInstance().FindCardByID("GAME_005");
            p.GetHand().AddCard(*Entity::GetFromCard(p, std::move(coin)));
        }
    }

    // Set next step
    nextStep =
        m_gameConfig.skipMulligan ? Step::MAIN_BEGIN : Step::BEGIN_MULLIGAN;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::BeginMulligan()
{
    // Start mulligan state
    GetPlayer1().mulliganState = Mulligan::INPUT;
    GetPlayer2().mulliganState = Mulligan::INPUT;

    // Collect cards that can redraw
    std::vector<std::size_t> p1HandIDs, p2HandIDs;
    for (auto& entity : GetPlayer1().GetHand().GetAllCards())
    {
        p1HandIDs.emplace_back(entity->id);
    }
    for (auto& entity : GetPlayer2().GetHand().GetAllCards())
    {
        p2HandIDs.emplace_back(entity->id);
    }

    // Create choice for each player
    Generic::CreateChoice(GetPlayer1(), ChoiceType::MULLIGAN,
                          ChoiceAction::HAND, p1HandIDs);
    Generic::CreateChoice(GetPlayer2(), ChoiceType::MULLIGAN,
                          ChoiceAction::HAND, p2HandIDs);
}

void Game::MainBegin()
{
    // Set next step
    nextStep = Step::MAIN_READY;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainReady()
{
    // Reset the number of attacked
    for (auto& p : m_players)
    {
        // Hero
        p.GetHero()->numAttacked = 0;
        // Field
        for (auto& m : p.GetField().GetAllMinions())
        {
            m->numAttacked = 0;
        }
    }

    // Reset exhaust for current player
    auto& curPlayer = GetCurrentPlayer();
    // Hero
    curPlayer.GetHero()->SetGameTag(GameTag::EXHAUSTED, 0);
    // Weapon
    if (curPlayer.GetHero()->weapon != nullptr)
    {
        curPlayer.GetHero()->weapon->SetGameTag(GameTag::EXHAUSTED, 0);
    }
    // Hero power
    curPlayer.GetHero()->heroPower->SetGameTag(GameTag::EXHAUSTED, 0);
    // Field
    for (auto& m : curPlayer.GetField().GetAllMinions())
    {
        m->SetGameTag(GameTag::EXHAUSTED, 0);
    }

    // Set next step
    nextStep = Step::MAIN_START_TRIGGERS;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainStartTriggers()
{
    // Set next step
    nextStep = Step::MAIN_RESOURCE;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainResource()
{
    auto& curPlayer = GetCurrentPlayer();

    // Add mana crystal to current player
    Generic::ChangeManaCrystal(curPlayer, 1, false);

    // Reset current mana
    curPlayer.currentMana = curPlayer.maximumMana;

    // Set next step
    nextStep = Step::MAIN_DRAW;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainDraw()
{
    // Draw a card for current player
    Generic::Draw(GetCurrentPlayer());

    // Set next step
    nextStep = Step::MAIN_START;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainStart()
{
    // Set next step
    nextStep = Step::MAIN_ACTION;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainEnd()
{
    // Set next step
    nextStep = Step::MAIN_CLEANUP;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainCleanUp()
{
    auto& curPlayer = GetCurrentPlayer();

    // Unfreeze all characters they control that are Frozen, don't have
    // summoning sickness (or do have Charge) and have not attacked that turn
    // Hero
    if (curPlayer.GetHero()->GetGameTag(GameTag::FROZEN) == 1 &&
        curPlayer.GetHero()->numAttacked == 0)
    {
        curPlayer.GetHero()->SetGameTag(GameTag::FROZEN, 0);
    }
    // Field
    for (auto& m : curPlayer.GetField().GetAllMinions())
    {
        if (m->GetGameTag(GameTag::FROZEN) == 1 && m->numAttacked == 0 &&
            m->GetGameTag(GameTag::EXHAUSTED) == 0)
        {
            m->SetGameTag(GameTag::FROZEN, 0);
        }
    }

    // Set next step
    nextStep = Step::MAIN_NEXT;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::MainNext()
{
    // Set player for next turn
    m_currentPlayer = &m_currentPlayer->GetOpponent();

    // Count next turn
    m_turn++;

    // Set next step
    nextStep = Step::MAIN_READY;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::FinalWrapUp()
{
    // Set game states according by result
    for (auto& p : m_players)
    {
        if (p.playState == +PlayState::LOSING ||
            p.playState == +PlayState::CONCEDED)
        {
            p.playState = PlayState::LOST;
            p.GetOpponent().playState = PlayState::WON;
        }
    }

    // Set next step
    nextStep = Step::FINAL_GAMEOVER;
    GameManager::ProcessNextStep(*this, nextStep);
}

void Game::FinalGameOver()
{
    // Set game state to complete
    state = State::COMPLETE;
}

void Game::StartGame()
{
    // Reverse card order in deck
    if (!m_gameConfig.doShuffle)
    {
        std::reverse(m_gameConfig.player1Deck.begin(),
                     m_gameConfig.player1Deck.end());
        std::reverse(m_gameConfig.player2Deck.begin(),
                     m_gameConfig.player2Deck.end());
    }

    // Set up decks
    for (auto& card : m_gameConfig.player1Deck)
    {
        if (card.cardType == +CardType::INVALID)
        {
            continue;
        }

        Entity* entity = Entity::GetFromCard(GetPlayer1(), std::move(card));
        GetPlayer1().GetDeck().AddCard(*entity);
    }
    for (auto& card : m_gameConfig.player2Deck)
    {
        if (card.cardType == +CardType::INVALID)
        {
            continue;
        }

        Entity* entity = Entity::GetFromCard(GetPlayer2(), std::move(card));
        GetPlayer2().GetDeck().AddCard(*entity);
    }

    // Fill cards to deck
    if (m_gameConfig.doFillDecks)
    {
        for (auto& p : m_players)
        {
            for (auto& cardID : m_gameConfig.fillCardIDs)
            {
                Card card = Cards::GetInstance().FindCardByID(cardID);
                Entity* entity = Entity::GetFromCard(p, std::move(card));
                p.GetDeck().AddCard(*entity);
            }
        }
    }

    // Set game states
    state = State::RUNNING;
    for (auto& p : m_players)
    {
        p.playState = PlayState::PLAYING;
    }

    // Determine first player
    switch (m_gameConfig.startPlayer)
    {
        case PlayerType::RANDOM:
        {
            auto val = Random::get(0, 1);
            m_firstPlayer = &m_players[val];
            break;
        }
        case PlayerType::PLAYER1:
            m_firstPlayer = &m_players[0];
            break;
        case PlayerType::PLAYER2:
            m_firstPlayer = &m_players[1];
            break;
    }
    m_currentPlayer = m_firstPlayer;

    // Set first turn
    m_turn = 1;

    // Set next step
    nextStep = Step::BEGIN_FIRST;
    GameManager::ProcessNextStep(*this, nextStep);
}
}  // namespace Hearthstonepp<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <std_msgs/String.h>
#include <string>
#include "serialDriver.c"
#include <sstream>      // std::stringstream

class serialListener{
	public:
	ros::NodeHandle handle;
	ros::Publisher arduino;
	std_msgs::String serialmsg;
	int checklastln(const char* toCheck , int maxLength){
		for(int i=0;i<maxLength;i++){
			if(toCheck[i]==10){
				return 1;
			}
			if(toCheck[i]==0){
				return 0;
			}
		}
	}
	std::stringstream read;
	void poll(){
		ROS_INFO("polling");
		read<<(char*)readline();

		if(read.str()[0]!=0&&read.str()[0]!=10){
			serialmsg.data=read.str();
			ROS_INFO("SerialListener:received data: %s" , read.str().c_str());
			if(checklastln(read.str().c_str(),255)){
				arduino.publish(serialmsg);
				ROS_INFO("SerialListener: Read %s", read.str().c_str());
				read.str("");
			}
		}
	}

	serialListener():handle("~"){
		arduino=handle.advertise<std_msgs::String>("/tawi/arduino/serial",100);
	}
};

int main (int argc, char **argv){
	ros::init(argc, argv, "serialListener");
	serialListener serial;
	ros::Rate hz(5);
	while(ros::ok()){
		serial.poll();
		ros::spinOnce();
		hz.sleep();
	}
}
<commit_msg>conformation code added<commit_after>#include <ros/ros.h>
#include <std_msgs/String.h>
#include <string>
#include "serialDriver.c"
#include <sstream>      // std::stringstream

class serialListener{
	public:
	ros::NodeHandle handle;
	ros::Publisher arduino;
	std_msgs::String serialmsg;
	int checklastln(const char* toCheck , int maxLength){
		for(int i=0;i<maxLength;i++){
			if(toCheck[i]==10){
				return 1;
			}
			if(toCheck[i]==0){
				return 0;
			}
		}
	}
	int validatemsg(std::string msg){
		if(msg[0]=='c'||msg[0]=='w')
			return 1;
		return 0;
	}
	void writeSerial(std::string shit){
		ROS_INFO("confirming");
		std::stringstream sysCall;
	        sysCall<<"/home/ubuntu/robotica-minor-5/com/arduino-serial/arduino-serial --port=/dev/ttyACM0 --send="<<shit;
		std::string temp= sysCall.str();
		system(temp.c_str());
	}

	std::stringstream read;

	void poll(){
		ROS_INFO("polling");
		read<<(char*)readline();

		if(read.str()[0]!=0&&read.str()[0]!=10){
			serialmsg.data=read.str();
			ROS_INFO("SerialListener:received data: %s" , read.str().c_str());
			if(checklastln(read.str().c_str(),255)){
				if(validatemsg(read.str())){
					writeSerial("conf");
					arduino.publish(serialmsg);
					ROS_INFO("SerialListener: Read %s", read.str().c_str());
					read.str("");
				}
			}
		}
	}

	serialListener():handle("~"){
		arduino=handle.advertise<std_msgs::String>("/tawi/arduino/serial",100);
	}
};

int main (int argc, char **argv){
	ros::init(argc, argv, "serialListener");
	serialListener serial;
	ros::Rate hz(5);
	while(ros::ok()){
		serial.poll();
		ros::spinOnce();
		hz.sleep();
	}
}
<|endoftext|>


<commit_before>//===-------- LoopDataPrefetch.cpp - Loop Data Prefetching Pass -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Loop Data Prefetching Pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loop-data-prefetch"
#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
using namespace llvm;

// By default, we limit this to creating 16 PHIs (which is a little over half
// of the allocatable register set).
static cl::opt<bool>
PrefetchWrites("loop-prefetch-writes", cl::Hidden, cl::init(false),
               cl::desc("Prefetch write addresses"));

namespace llvm {
  void initializeLoopDataPrefetchPass(PassRegistry&);
}

namespace {

  class LoopDataPrefetch : public FunctionPass {
  public:
    static char ID; // Pass ID, replacement for typeid
    LoopDataPrefetch() : FunctionPass(ID) {
      initializeLoopDataPrefetchPass(*PassRegistry::getPassRegistry());
    }

    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.addRequired<AssumptionCacheTracker>();
      AU.addPreserved<DominatorTreeWrapperPass>();
      AU.addRequired<LoopInfoWrapperPass>();
      AU.addPreserved<LoopInfoWrapperPass>();
      AU.addRequired<ScalarEvolutionWrapperPass>();
      // FIXME: For some reason, preserving SE here breaks LSR (even if
      // this pass changes nothing).
      // AU.addPreserved<ScalarEvolutionWrapperPass>();
      AU.addRequired<TargetTransformInfoWrapperPass>();
    }

    bool runOnFunction(Function &F) override;
    bool runOnLoop(Loop *L);

  private:
    AssumptionCache *AC;
    LoopInfo *LI;
    ScalarEvolution *SE;
    const TargetTransformInfo *TTI;
    const DataLayout *DL;
  };
}

char LoopDataPrefetch::ID = 0;
INITIALIZE_PASS_BEGIN(LoopDataPrefetch, "loop-data-prefetch",
                      "Loop Data Prefetch", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_END(LoopDataPrefetch, "loop-data-prefetch",
                    "Loop Data Prefetch", false, false)

FunctionPass *llvm::createLoopDataPrefetchPass() { return new LoopDataPrefetch(); }

bool LoopDataPrefetch::runOnFunction(Function &F) {
  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
  SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
  DL = &F.getParent()->getDataLayout();
  AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);

  assert(TTI->getCacheLineSize() && "Cache line size is not set for target");
  assert(TTI->getPrefetchDistance() &&
         "Prefetch distance is not set for target");

  bool MadeChange = false;

  for (auto I = LI->begin(), IE = LI->end(); I != IE; ++I)
    for (auto L = df_begin(*I), LE = df_end(*I); L != LE; ++L)
      MadeChange |= runOnLoop(*L);

  return MadeChange;
}

bool LoopDataPrefetch::runOnLoop(Loop *L) {
  bool MadeChange = false;

  // Only prefetch in the inner-most loop
  if (!L->empty())
    return MadeChange;

  SmallPtrSet<const Value *, 32> EphValues;
  CodeMetrics::collectEphemeralValues(L, AC, EphValues);

  // Calculate the number of iterations ahead to prefetch
  CodeMetrics Metrics;
  for (Loop::block_iterator I = L->block_begin(), IE = L->block_end();
       I != IE; ++I) {

    // If the loop already has prefetches, then assume that the user knows
    // what he or she is doing and don't add any more.
    for (BasicBlock::iterator J = (*I)->begin(), JE = (*I)->end();
         J != JE; ++J)
      if (CallInst *CI = dyn_cast<CallInst>(J))
        if (Function *F = CI->getCalledFunction())
          if (F->getIntrinsicID() == Intrinsic::prefetch)
            return MadeChange;

    Metrics.analyzeBasicBlock(*I, *TTI, EphValues);
  }
  unsigned LoopSize = Metrics.NumInsts;
  if (!LoopSize)
    LoopSize = 1;

  unsigned ItersAhead = TTI->getPrefetchDistance() / LoopSize;
  if (!ItersAhead)
    ItersAhead = 1;

  SmallVector<std::pair<Instruction *, const SCEVAddRecExpr *>, 16> PrefLoads;
  for (Loop::block_iterator I = L->block_begin(), IE = L->block_end();
       I != IE; ++I) {
    for (BasicBlock::iterator J = (*I)->begin(), JE = (*I)->end();
        J != JE; ++J) {
      Value *PtrValue;
      Instruction *MemI;

      if (LoadInst *LMemI = dyn_cast<LoadInst>(J)) {
        MemI = LMemI;
        PtrValue = LMemI->getPointerOperand();
      } else if (StoreInst *SMemI = dyn_cast<StoreInst>(J)) {
        if (!PrefetchWrites) continue;
        MemI = SMemI;
        PtrValue = SMemI->getPointerOperand();
      } else continue;

      unsigned PtrAddrSpace = PtrValue->getType()->getPointerAddressSpace();
      if (PtrAddrSpace)
        continue;

      if (L->isLoopInvariant(PtrValue))
        continue;

      const SCEV *LSCEV = SE->getSCEV(PtrValue);
      const SCEVAddRecExpr *LSCEVAddRec = dyn_cast<SCEVAddRecExpr>(LSCEV);
      if (!LSCEVAddRec)
        continue;

      // We don't want to double prefetch individual cache lines. If this load
      // is known to be within one cache line of some other load that has
      // already been prefetched, then don't prefetch this one as well.
      bool DupPref = false;
      for (SmallVector<std::pair<Instruction *, const SCEVAddRecExpr *>,
             16>::iterator K = PrefLoads.begin(), KE = PrefLoads.end();
           K != KE; ++K) {
        const SCEV *PtrDiff = SE->getMinusSCEV(LSCEVAddRec, K->second);
        if (const SCEVConstant *ConstPtrDiff =
            dyn_cast<SCEVConstant>(PtrDiff)) {
          int64_t PD = std::abs(ConstPtrDiff->getValue()->getSExtValue());
          if (PD < (int64_t) TTI->getCacheLineSize()) {
            DupPref = true;
            break;
          }
        }
      }
      if (DupPref)
        continue;

      const SCEV *NextLSCEV = SE->getAddExpr(LSCEVAddRec, SE->getMulExpr(
        SE->getConstant(LSCEVAddRec->getType(), ItersAhead),
        LSCEVAddRec->getStepRecurrence(*SE)));
      if (!isSafeToExpand(NextLSCEV, *SE))
        continue;

      PrefLoads.push_back(std::make_pair(MemI, LSCEVAddRec));

      Type *I8Ptr = Type::getInt8PtrTy((*I)->getContext(), PtrAddrSpace);
      SCEVExpander SCEVE(*SE, J->getModule()->getDataLayout(), "prefaddr");
      Value *PrefPtrValue = SCEVE.expandCodeFor(NextLSCEV, I8Ptr, MemI);

      IRBuilder<> Builder(MemI);
      Module *M = (*I)->getParent()->getParent();
      Type *I32 = Type::getInt32Ty((*I)->getContext());
      Value *PrefetchFunc = Intrinsic::getDeclaration(M, Intrinsic::prefetch);
      Builder.CreateCall(
          PrefetchFunc,
          {PrefPtrValue,
           ConstantInt::get(I32, MemI->mayReadFromMemory() ? 0 : 1),
           ConstantInt::get(I32, 3), ConstantInt::get(I32, 1)});

      MadeChange = true;
    }
  }

  return MadeChange;
}

<commit_msg>[LoopDataPrefetch] If prefetch distance is not set, skip pass<commit_after>//===-------- LoopDataPrefetch.cpp - Loop Data Prefetching Pass -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a Loop Data Prefetching Pass.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loop-data-prefetch"
#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/ScalarEvolutionExpander.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
using namespace llvm;

// By default, we limit this to creating 16 PHIs (which is a little over half
// of the allocatable register set).
static cl::opt<bool>
PrefetchWrites("loop-prefetch-writes", cl::Hidden, cl::init(false),
               cl::desc("Prefetch write addresses"));

namespace llvm {
  void initializeLoopDataPrefetchPass(PassRegistry&);
}

namespace {

  class LoopDataPrefetch : public FunctionPass {
  public:
    static char ID; // Pass ID, replacement for typeid
    LoopDataPrefetch() : FunctionPass(ID) {
      initializeLoopDataPrefetchPass(*PassRegistry::getPassRegistry());
    }

    void getAnalysisUsage(AnalysisUsage &AU) const override {
      AU.addRequired<AssumptionCacheTracker>();
      AU.addPreserved<DominatorTreeWrapperPass>();
      AU.addRequired<LoopInfoWrapperPass>();
      AU.addPreserved<LoopInfoWrapperPass>();
      AU.addRequired<ScalarEvolutionWrapperPass>();
      // FIXME: For some reason, preserving SE here breaks LSR (even if
      // this pass changes nothing).
      // AU.addPreserved<ScalarEvolutionWrapperPass>();
      AU.addRequired<TargetTransformInfoWrapperPass>();
    }

    bool runOnFunction(Function &F) override;
    bool runOnLoop(Loop *L);

  private:
    AssumptionCache *AC;
    LoopInfo *LI;
    ScalarEvolution *SE;
    const TargetTransformInfo *TTI;
    const DataLayout *DL;
  };
}

char LoopDataPrefetch::ID = 0;
INITIALIZE_PASS_BEGIN(LoopDataPrefetch, "loop-data-prefetch",
                      "Loop Data Prefetch", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_END(LoopDataPrefetch, "loop-data-prefetch",
                    "Loop Data Prefetch", false, false)

FunctionPass *llvm::createLoopDataPrefetchPass() { return new LoopDataPrefetch(); }

bool LoopDataPrefetch::runOnFunction(Function &F) {
  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
  SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
  DL = &F.getParent()->getDataLayout();
  AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
  TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);

  // If PrefetchDistance is not set, don't run the pass.  This gives an
  // opportunity for targets to run this pass for selected subtargets only
  // (whose TTI sets PrefetchDistance).
  if (TTI->getPrefetchDistance() == 0)
    return false;
  assert(TTI->getCacheLineSize() && "Cache line size is not set for target");

  bool MadeChange = false;

  for (auto I = LI->begin(), IE = LI->end(); I != IE; ++I)
    for (auto L = df_begin(*I), LE = df_end(*I); L != LE; ++L)
      MadeChange |= runOnLoop(*L);

  return MadeChange;
}

bool LoopDataPrefetch::runOnLoop(Loop *L) {
  bool MadeChange = false;

  // Only prefetch in the inner-most loop
  if (!L->empty())
    return MadeChange;

  SmallPtrSet<const Value *, 32> EphValues;
  CodeMetrics::collectEphemeralValues(L, AC, EphValues);

  // Calculate the number of iterations ahead to prefetch
  CodeMetrics Metrics;
  for (Loop::block_iterator I = L->block_begin(), IE = L->block_end();
       I != IE; ++I) {

    // If the loop already has prefetches, then assume that the user knows
    // what he or she is doing and don't add any more.
    for (BasicBlock::iterator J = (*I)->begin(), JE = (*I)->end();
         J != JE; ++J)
      if (CallInst *CI = dyn_cast<CallInst>(J))
        if (Function *F = CI->getCalledFunction())
          if (F->getIntrinsicID() == Intrinsic::prefetch)
            return MadeChange;

    Metrics.analyzeBasicBlock(*I, *TTI, EphValues);
  }
  unsigned LoopSize = Metrics.NumInsts;
  if (!LoopSize)
    LoopSize = 1;

  unsigned ItersAhead = TTI->getPrefetchDistance() / LoopSize;
  if (!ItersAhead)
    ItersAhead = 1;

  SmallVector<std::pair<Instruction *, const SCEVAddRecExpr *>, 16> PrefLoads;
  for (Loop::block_iterator I = L->block_begin(), IE = L->block_end();
       I != IE; ++I) {
    for (BasicBlock::iterator J = (*I)->begin(), JE = (*I)->end();
        J != JE; ++J) {
      Value *PtrValue;
      Instruction *MemI;

      if (LoadInst *LMemI = dyn_cast<LoadInst>(J)) {
        MemI = LMemI;
        PtrValue = LMemI->getPointerOperand();
      } else if (StoreInst *SMemI = dyn_cast<StoreInst>(J)) {
        if (!PrefetchWrites) continue;
        MemI = SMemI;
        PtrValue = SMemI->getPointerOperand();
      } else continue;

      unsigned PtrAddrSpace = PtrValue->getType()->getPointerAddressSpace();
      if (PtrAddrSpace)
        continue;

      if (L->isLoopInvariant(PtrValue))
        continue;

      const SCEV *LSCEV = SE->getSCEV(PtrValue);
      const SCEVAddRecExpr *LSCEVAddRec = dyn_cast<SCEVAddRecExpr>(LSCEV);
      if (!LSCEVAddRec)
        continue;

      // We don't want to double prefetch individual cache lines. If this load
      // is known to be within one cache line of some other load that has
      // already been prefetched, then don't prefetch this one as well.
      bool DupPref = false;
      for (SmallVector<std::pair<Instruction *, const SCEVAddRecExpr *>,
             16>::iterator K = PrefLoads.begin(), KE = PrefLoads.end();
           K != KE; ++K) {
        const SCEV *PtrDiff = SE->getMinusSCEV(LSCEVAddRec, K->second);
        if (const SCEVConstant *ConstPtrDiff =
            dyn_cast<SCEVConstant>(PtrDiff)) {
          int64_t PD = std::abs(ConstPtrDiff->getValue()->getSExtValue());
          if (PD < (int64_t) TTI->getCacheLineSize()) {
            DupPref = true;
            break;
          }
        }
      }
      if (DupPref)
        continue;

      const SCEV *NextLSCEV = SE->getAddExpr(LSCEVAddRec, SE->getMulExpr(
        SE->getConstant(LSCEVAddRec->getType(), ItersAhead),
        LSCEVAddRec->getStepRecurrence(*SE)));
      if (!isSafeToExpand(NextLSCEV, *SE))
        continue;

      PrefLoads.push_back(std::make_pair(MemI, LSCEVAddRec));

      Type *I8Ptr = Type::getInt8PtrTy((*I)->getContext(), PtrAddrSpace);
      SCEVExpander SCEVE(*SE, J->getModule()->getDataLayout(), "prefaddr");
      Value *PrefPtrValue = SCEVE.expandCodeFor(NextLSCEV, I8Ptr, MemI);

      IRBuilder<> Builder(MemI);
      Module *M = (*I)->getParent()->getParent();
      Type *I32 = Type::getInt32Ty((*I)->getContext());
      Value *PrefetchFunc = Intrinsic::getDeclaration(M, Intrinsic::prefetch);
      Builder.CreateCall(
          PrefetchFunc,
          {PrefPtrValue,
           ConstantInt::get(I32, MemI->mayReadFromMemory() ? 0 : 1),
           ConstantInt::get(I32, 3), ConstantInt::get(I32, 1)});

      MadeChange = true;
    }
  }

  return MadeChange;
}

<|endoftext|>


<commit_before>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2021 Antti Nuortimo.
//
// 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 (at your option) 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 Affero 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, see <https://www.gnu.org/licenses/>.

#include "child_module.hpp"
#include "parent_module.hpp"
#include "entity.hpp"

namespace yli::ontology
{
    class ParentModule;

    void ChildModule::bind_to_parent_module()
    {
        // requirements:
        // `this->parent` must not be `nullptr`.
        // `this->entity` must not be `nullptr`.

        if (this->parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        // get `childID` from the `ParentModule` and set pointer to this child.
        this->parent_module->bind_child(this->entity);
    }

    ChildModule::~ChildModule()
    {
        // destructor.

        // requirements:
        // `this->parent` must not be `nullptr`.

        if (this->parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        // Set pointer to this `Entity` to `nullptr`.
        this->parent_module->unbind_child(this->entity->childID);
    }

    yli::ontology::Entity* ChildModule::get_parent() const
    {
        if (this->parent_module == nullptr)
        {
            return nullptr;
        }

        return this->parent_module->get_entity();
    }

    void ChildModule::unbind_child() const
    {
        if (this->parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        this->parent_module->unbind_child(entity->get_childID());
    }

    void ChildModule::set_parent_module_and_bind_to_new_parent(yli::ontology::ParentModule* const new_parent_module)
    {
        if (new_parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        this->parent_module = new_parent_module;
        this->parent_module->bind_child(this->entity);
    }
}
<commit_msg>Remove unnecessary forward declaration.<commit_after>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2021 Antti Nuortimo.
//
// 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 (at your option) 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 Affero 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, see <https://www.gnu.org/licenses/>.

#include "child_module.hpp"
#include "parent_module.hpp"
#include "entity.hpp"

namespace yli::ontology
{
    void ChildModule::bind_to_parent_module()
    {
        // requirements:
        // `this->parent` must not be `nullptr`.
        // `this->entity` must not be `nullptr`.

        if (this->parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        // get `childID` from the `ParentModule` and set pointer to this child.
        this->parent_module->bind_child(this->entity);
    }

    ChildModule::~ChildModule()
    {
        // destructor.

        // requirements:
        // `this->parent` must not be `nullptr`.

        if (this->parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        // Set pointer to this `Entity` to `nullptr`.
        this->parent_module->unbind_child(this->entity->childID);
    }

    yli::ontology::Entity* ChildModule::get_parent() const
    {
        if (this->parent_module == nullptr)
        {
            return nullptr;
        }

        return this->parent_module->get_entity();
    }

    void ChildModule::unbind_child() const
    {
        if (this->parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        this->parent_module->unbind_child(entity->get_childID());
    }

    void ChildModule::set_parent_module_and_bind_to_new_parent(yli::ontology::ParentModule* const new_parent_module)
    {
        if (new_parent_module == nullptr)
        {
            return;
        }

        if (this->entity == nullptr)
        {
            return;
        }

        this->parent_module = new_parent_module;
        this->parent_module->bind_child(this->entity);
    }
}
<|endoftext|>


<commit_before><commit_msg>`ontology::get_ground_level`: use `std::size_t` instead of `GLuint`.<commit_after><|endoftext|>


<commit_before>#include <math.h>
#include <iostream>
#include <ctime>
#include <limits>

#define MID(a, b) ((a+b)/2)
#define POW(a) (a*a)

template<long long int res, long long int l = 1, long long int r = res>
struct SQRT;

template<long long int res, long long int r>
struct SQRT<res, r, r> {
   static const long long int value = r;
};

template <long long int res, long long int l, long long int r>
struct SQRT {
   static const long long int value = SQRT<res,
                                (POW(MID(r, l)) >= res ?  l : MID(r, l)+1),
                                (POW(MID(r, l)) >= res ? MID(r, l) : r)>::value;
};

template <bool Condition, typename TrueResult, typename FalseResult>
struct if_;

template <typename TrueResult, typename FalseResult>
struct if_<true, TrueResult, FalseResult>
{
   typedef TrueResult result;
};

template <typename TrueResult, typename FalseResult>
struct if_<false, TrueResult, FalseResult>
{
   typedef FalseResult result;
};
/////////////////

class end_of_sieve
{
   public:
   bool isComposite(int n)
   {
      return false;
   }

   int print()
   {
      /* done! */
      return 0;
   }
};

template <int base, int max, typename listOfNaturals>
class sieve_iterate_rest
{
   enum { value = base };

   public:
   bool isComposite(int n)
   {
      listOfNaturals N;
      return N.isComposite(n);
   }

   int print()
   {
      typename if_< ((base + 2) <= max),
                  sieve_iterate_rest<base + 2, max, listOfNaturals>,
                  end_of_sieve>::result sieve;
      int count = 0;

      if ( not sieve.isComposite(base) )
      {
         std::cout << value << std::endl;
         count ++;
      }
      return count + sieve.print();
   }
};

class end_of_list
{
   public:
   bool has(int n)
   {
      return false;
   }
};

template <int base, int max>
class sieve_mark_multiples_iter
{
   enum { value = base };

   typename if_< (base + 2 * base) <= max,
              sieve_mark_multiples_iter<base + 2 * base, max>,
              end_of_list >::result multiplesOfBase;

   public:
   bool has(int n)
   {
      if ( n == value )
         return true;
      else
         return multiplesOfBase.has(n);
   }
};

template <int base, int max, typename listOfNaturals>
class sieve_mark_multiples
{
   enum { value = base };

   public:
   bool isComposite(int n)
   {
      typename if_< (base + 2 * base) <= max,
                  sieve_mark_multiples_iter<base + 2 * base, max>,
                  end_of_list >::result multiplesOfBase;
      listOfNaturals naturals;

      if ( n == value )
         return false;
      else
         if ( multiplesOfBase.has(n) )
            return true;
         else
            return naturals.isComposite(n);
   }
};

template <int max, typename listOfNaturals>
class sieve_mark_multiples<2, max, listOfNaturals>
{
   public:
   bool isComposite(int n)
   {
      return (n % 2 == 0);
   }
};

template <int base, int sqrt, int max, typename listOfNaturals>
class sieve_explore
{
   enum { value = base };
   typename if_< base <= sqrt,
               sieve_explore<base + 2, sqrt, max, sieve_mark_multiples<base, max, listOfNaturals> >,
               sieve_iterate_rest<base + 2, max, listOfNaturals> >::result sieve;

   public:
   int print()
   {
      listOfNaturals N;
      int count = 0;

      if ( not N.isComposite(base) )
      {
         std::cout << value << std::endl;
         count++;
      }
      return count + sieve.print();
   }
};

template <int sqrt, int max, typename listOfNaturals>
class sieve_explore<2, sqrt, max, listOfNaturals>
{
   enum { value = 2 };
   typename if_< value <= sqrt,
               sieve_explore<value + 1, sqrt, max, sieve_mark_multiples<2, max, listOfNaturals> >,
               sieve_iterate_rest<value + 1, max, listOfNaturals> >::result sieve;
   public:
   int print()
   {
      std::cout << value << std::endl;
      int count = 1;
      if (max > value)
         count += sieve.print();
      return count;
   }
};

template <int n>
class erasthostenes_t {
public:
   int sieve()
   {
      if (n > 1)
      {
         sieve_explore<2, SQRT<n>::value, n, end_of_sieve> sieve;
         return sieve.print();
      }
      return 0;
   }
};

int main(int argc, char ** argv)
{
   //const int max_number = 32288611;
   const int max_number = 20;
   time_t t1, t2;

   time(&t1);

   erasthostenes_t<max_number> Erasthostenes;
   int calculatedPrimes = Erasthostenes.sieve();

   time(&t2);
   std::cout.precision(std::numeric_limits<double>::digits10);
   std::cerr << "Used " << std::fixed << difftime(t2, t1)
             << " seconds to calculate " << calculatedPrimes
             << " primes." << std::endl;
}
<commit_msg>Fix bug that didn't check if a number close to the max boundary was composite or not.<commit_after>#include <math.h>
#include <iostream>
#include <ctime>
#include <limits>

#define MID(a, b) ((a+b)/2)
#define POW(a) (a*a)

template<long long int res, long long int l = 1, long long int r = res>
struct SQRT;

template<long long int res, long long int r>
struct SQRT<res, r, r> {
   static const long long int value = r;
};

template <long long int res, long long int l, long long int r>
struct SQRT {
   static const long long int value = SQRT<res,
                                (POW(MID(r, l)) >= res ?  l : MID(r, l)+1),
                                (POW(MID(r, l)) >= res ? MID(r, l) : r)>::value;
};

template <bool Condition, typename TrueResult, typename FalseResult>
struct if_;

template <typename TrueResult, typename FalseResult>
struct if_<true, TrueResult, FalseResult>
{
   typedef TrueResult result;
};

template <typename TrueResult, typename FalseResult>
struct if_<false, TrueResult, FalseResult>
{
   typedef FalseResult result;
};
/////////////////

class end_of_sieve
{
   public:
   bool isComposite(int n)
   {
      return true;
   }

   int print()
   {
      /* done! */
      return 0;
   }
};

template <int base, int max, typename listOfNaturals>
class sieve_iterate_rest
{
   enum { value = base };

   public:
   bool isComposite(int n)
   {
      listOfNaturals N;
      return N.isComposite(n);
   }

   int print()
   {
      typename if_< ((base + 2) <= max + 2),
                  sieve_iterate_rest<base + 2, max, listOfNaturals>,
                  end_of_sieve>::result sieve;
      int count = 0;

      if ( not sieve.isComposite(base) )
      {
         std::cout << value << std::endl;
         count ++;
      }
      return count + sieve.print();
   }
};

class end_of_list
{
   public:
   bool has(int n)
   {
      return false;
   }
};

template <int pivot, int base, int max>
class sieve_mark_multiples_iter
{
   enum { value = pivot };

   typename if_< (pivot + 2 * base) <= max,
              sieve_mark_multiples_iter<pivot + 2 * base, base, max>,
              end_of_list >::result multiplesOfBase;

   public:
   bool has(int n)
   {
      //std::cout << "Checking " << n << " (value = " << value << ", base = " << base << ")." << std::endl;
      if ( n == value )
         return true;
      else
         return multiplesOfBase.has(n);
   }
};

template <int base, int max, typename listOfNaturals>
class sieve_mark_multiples
{
   enum { value = base };

   public:
   bool isComposite(int n)
   {
      typename if_< (base + 2 * base) <= max,
                  sieve_mark_multiples_iter<base + 2 * base, base, max>,
                  end_of_list >::result multiplesOfBase;
      listOfNaturals naturals;

      if ( n == value )
         return false;
      else
         if ( multiplesOfBase.has(n) )
            return true;
         else
            return naturals.isComposite(n);
   }
};

template <int max, typename listOfNaturals>
class sieve_mark_multiples<2, max, listOfNaturals>
{
   public:
   bool isComposite(int n)
   {
      return (n % 2 == 0);
   }
};

template <int base, int sqrt, int max, typename listOfNaturals>
class sieve_explore
{
   enum { value = base };
   typename if_< base <= sqrt,
               sieve_explore<base + 2, sqrt, max, sieve_mark_multiples<base, max, listOfNaturals> >,
               sieve_iterate_rest<base + 2, max, listOfNaturals> >::result sieve;

   public:
   int print()
   {
      listOfNaturals N;
      int count = 0;

      if ( not N.isComposite(base) )
      {
         std::cout << value << std::endl;
         count++;
      }
      return count + sieve.print();
   }
};

template <int sqrt, int max, typename listOfNaturals>
class sieve_explore<2, sqrt, max, listOfNaturals>
{
   enum { value = 2 };
   typename if_< value <= sqrt,
               sieve_explore<value + 1, sqrt, max, sieve_mark_multiples<2, max, listOfNaturals> >,
               sieve_iterate_rest<value + 1, max, listOfNaturals> >::result sieve;
   public:
   int print()
   {
      std::cout << value << std::endl;
      int count = 1;
      if (max > value)
         count += sieve.print();
      return count;
   }
};

template <int n>
class erasthostenes_t {
public:
   int sieve()
   {
      if (n > 1)
      {
         sieve_explore<2, SQRT<n>::value, n, end_of_sieve> sieve;
         return sieve.print();
      }
      return 0;
   }
};

int main(int argc, char ** argv)
{
   //const int max_number = 32288611;
   const int max_number = 40;
   time_t t1, t2;

   time(&t1);

   erasthostenes_t<max_number> Erasthostenes;
   int calculatedPrimes = Erasthostenes.sieve();

   time(&t2);
   std::cout.precision(std::numeric_limits<double>::digits10);
   std::cerr << "Used " << std::fixed << difftime(t2, t1)
             << " seconds to calculate " << calculatedPrimes
             << " primes." << std::endl;
}
<|endoftext|>


<commit_before>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online 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 (at your option) any later version.
 *
 * Cyvasse Online 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 Affero 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, see <http://www.gnu.org/licenses/>.
 */

#ifndef _CYVMATH_HEXAGON_HPP_
#define _CYVMATH_HEXAGON_HPP_

#include <functional>
#include <set>
#include <string>
#include <stdexcept>
#include <utility>
#include <vector>
#include <cmath>

namespace cyvmath
{
	/// A coordinate on the hexboard (see mockup/hexboard-coordinates-internal.svg)
	template <int l>
	class _Coordinate
	{
		public:
			typedef std::vector<_Coordinate> CoordinateVec;

		private:
			int8_t _x;
			int8_t _y;

			_Coordinate(int8_t x, int8_t y)
				: _x(x)
				, _y(y)
			{
			}

		public:
			_Coordinate(const _Coordinate&) = default;
			_Coordinate& operator=(const _Coordinate& other) = default;

			int8_t x() const
			{
				return _x;
			}

			int8_t y() const
			{
				return _y;
			}

			int8_t z() const
			{
				return -(_x + _y);
			}

			int16_t dump() const
			{
				return (_x << 8) | _y;
			}

		private:
			static bool isValid(int8_t x, int8_t y)
			{
				return x >= 0 && x < (l * 2 - 1) &&
				       y >= 0 && y < (l * 2 - 1) &&
				       (x + y) >= (l - 1) &&
				       (x + y) <= (l - 1) * 3;
			}

			bool isValid() const
			{
				return isValid(_x, _y);
			}

			operator bool() const
			{
				return isValid();
			}

		public:
			bool operator==(_Coordinate other) const
			{
				return _x == other._x && _y == other._y;
			}

			bool operator!=(_Coordinate other) const
			{
				return _x != other._x || _y != other._y;
			}

			bool operator<(_Coordinate other) const
			{
				return dump() < other.dump();
			}

			/** Get the distance to another coordinate in form of the amount
			    of single moves to adjacent tiles required to move there
			 */
			int8_t getDistance(_Coordinate other) const
			{
				// Concept from http://keekerdc.com/2011/03/hexagon-grids-coordinate-systems-and-distance-calculations/
				// I have no idea why the maximum of x-, y- and z-difference
				// of the coordinates equals the distance between them...
				return *(std::set<int>({abs(_x - other._x), abs(_y - other._y), abs(z() - other.z())}).rbegin());
			}

			/// Check if the given coordinate is reachable in one orthogonal move
			bool isOrthogonal(_Coordinate other) const
			{
				return _x == other._x || _y == other._y || z() == other.z();
			}

			/** Like getDistance(), but return -1 if the given coordinate
			    is not reachable in one orthogonal move

			    An orthogonal move is a straight move in one of the six
			    directions of the neighboring hex-tiles.
			 */
			int8_t getDistanceOrthogonal(_Coordinate other) const
			{
				if(!isOrthogonal(other))
					return -1;

				return getDistance(other);
			}

			/** Get all coordinates reachable in one orthogonal move of
			    maximally the provided distance of tiles

			    The default value is the maximal distance possible on
			    this hexagon (no distance limit).
			 */
			CoordinateVec getCoordinatesOrthogonal(int8_t distance = (l * 2 - 2)) const
			{
				CoordinateVec vec;

				for(int direction = 0; direction < 6; direction++)
				{
					std::pair<int, int> op;
					switch(direction)
					{
						case 0: op = {-1,  1}; break; // top left
						case 1: op = { 0,  1}; break; // top right
						case 2: op = { 1,  0}; break; // right
						case 3: op = { 1, -1}; break; // bottom right
						case 4: op = { 0, -1}; break; // bottom left
						case 5: op = {-1,  0}; break; // left
					}

					_Coordinate tmpCoord(*this);
					for(int i = 0; i < distance; i++)
					{
						tmpCoord = {tmpCoord->_x + op.first, tmpCoord->_y + op.second};

						// if one step into this direction results in a
						// invalid coordinate, all further ones do too
						if(!tmpCoord)
							break;

						vec.push_back(tmpCoord);
					}
				}

				return vec;
			}

			/// Check if the given coordinate is reachable in one diagonal move
			bool isDiagonal(_Coordinate other) const
			{
				int8_t dX = abs(_x - other._x);
				int8_t dY = abs(_y - other._y);
				int8_t dZ = abs(z() - other.z());

				return (dX == dY && dX == dZ / 2) ||
				       (dX == dZ && dX == dY / 2) ||
				       (dY == dZ && dY == dX / 2);
			}

			/** Get the diagonal distance to a coordinate, or -1 if
			    the coordinate isn't reachable in one diagonal move

			    A diagonal move is a straight move in one of the six
			    directions of the lines between the neighboring hex-tiles.
			 */
			int8_t getDistanceDiagonal(_Coordinate other) const
			{
				if(!isDiagonal(other))
					return -1;

				return getDistance(other) / 2;
			}

			/** Get the distance to another coordinate with the same distance to
			    the center Coordinate along the line of these coordinates, or -1
			    if the coordinate isn't reachable while only moving on that line.

			    All possible movement targets here are along a hexagonal line.
			    The direct distance from this coordinate to another one on that
			    line may be different than the distance along the line.
			 */
			// There certainly is no other rule set than MikeL's that uses this
			// but there probably is no better place to put this code either.
			int8_t getDistanceHexagonalLine(_Coordinate other, _Coordinate center) const
			{
				// Check if the given coordinate has the same distance to center as this
				if(getDistance(center) != other.getDistance(center))
					return -1;

				// TODO
			}

			/// Check if the given coordinate is a direct neighbor
			bool isAdjacent(_Coordinate other) const
			{
				return getDistance() == 1;
			}

			/// Get all adjacent coordinates
			CoordinateVec getCoordinatesAdjacent()
			{
				return getCoordinatesOrthogonal(1);
			}

			bool set(int8_t x, int8_t y)
			{
				if(isValid(x, y))
				{
					_x = x;
					_y = y;

					return true;
				}

				return false;
			}

			/// @{
			/// Create a Coordinate object from an x and an y
			/// If the coordinte is invalid, return nullptr
			static std::unique_ptr<_Coordinate> create(int8_t x, int8_t y)
			{
				if(isValid(x, y))
					return std::unique_ptr<_Coordinate>(new _Coordinate(x, y));

				return nullptr;
			}

			static std::unique_ptr<_Coordinate> create(std::pair<int8_t, int8_t> c)
			{
				if(isValid(c.first, c.second))
					return std::unique_ptr<_Coordinate>(new _Coordinate(c.first, c.second));

				return nullptr;
			}
			/// @}

			/// Create a Coordinate object from a coordinate in the public notation
			/// (see mockup/hexboard-coordinates-public.svg)
			static std::unique_ptr<_Coordinate> createFromStr(const std::string& str)
			{
				// This function will currently fail on hexagons with l > 13 because there
				// would be multiple letters for the y coordinate in the public notation.
				// TODO: Decide on whether to set a maximum l of 13 or to alter this function

				if(str.length() < 2)
					return nullptr;

				/* x: When using char's for calculations, their ASCII values are used,
				      and as the uppercase letters are consecutive in the ASCII table,
				      this will result in 0 for 'A', 1 for 'B' and so on.
				      We don't accept lowercase letters.
				   y: Public coordinate notation starts with 1, we start with 0
				 */
				return {str.at(0) - 'A', std::stoi(str.substr(1)) - 1};
			}
	};

	/* This should rather be a namespace, but namespaces cannot have template parameters.
	   hexagon<6>::Coordinate is way better understandable than hexagon::Coordinate<6>
	   so this is implemented as a template class with a deleted constructor.
	   The template parameter l stands for the edge length of the hexagon.
	 */
	template <int l>
	class hexagon
	{
		/* The smallest possible hexagon has 7 tiles and an edge lenth of 2
		   The largest possible hexagon in which the highest x and y can be represented
		   using a signed 8 bit integer has an edge length of 64 (=> width and height 127)
		 */
		static_assert(l >= 2,  "The minimum size of the hexagon edge length is 2.");
		static_assert(l <= 64, "The maximum size of the hexagon edge length is 64.");

		private:
			hexagon() = delete;

		public:
			typedef _Coordinate<l> Coordinate;
			typedef typename _Coordinate<l>::CoordinateVec CoordinateVec;

			/// Get the edge length of the hexagon (template parameter)
			static const int edgeLength = l;

			/// Get a container with all possible coordinates in this hexagon
			static CoordinateVec getAllCoordinates()
			{
				static CoordinateVec vec;

				if(vec.empty())
				{
					for(int x = 0; x < (2 * l) - 1; x++)
					{
						for(int y = 0; y < (2 * l) - 1; y++)
						{
							std::unique_ptr<Coordinate> c = Coordinate::create(x, y);

							if(c) vec.push_back(*c);
						}
					}
				}

				return vec;
			}
	};
}

namespace std
{
	template <int l>
	struct hash<cyvmath::_Coordinate<l>>
	{
		size_t operator()(const cyvmath::_Coordinate<l>& coord) const
		{
			return hash<int16_t>()(coord.dump());
		}
	};
}

#endif // _CYVMATH_HEXAGON_HPP_
<commit_msg>Added getCoordinatesDiagonal() to hexagon::Coordinate<commit_after>/* Copyright 2014 Jonas Platte
 *
 * This file is part of Cyvasse Online.
 *
 * Cyvasse Online 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 (at your option) any later version.
 *
 * Cyvasse Online 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 Affero 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, see <http://www.gnu.org/licenses/>.
 */

#ifndef _CYVMATH_HEXAGON_HPP_
#define _CYVMATH_HEXAGON_HPP_

#include <array>
#include <functional>
#include <set>
#include <string>
#include <stdexcept>
#include <utility>
#include <vector>
#include <cmath>

namespace cyvmath
{
	/// A coordinate on the hexboard (see mockup/hexboard-coordinates-internal.svg)
	template <int l>
	class _Coordinate
	{
		public:
			typedef std::vector<_Coordinate> CoordinateVec;

		private:
			int8_t _x;
			int8_t _y;

			_Coordinate(int8_t x, int8_t y)
				: _x(x)
				, _y(y)
			{
			}

		public:
			_Coordinate(const _Coordinate&) = default;
			_Coordinate& operator=(const _Coordinate& other) = default;

			int8_t x() const
			{
				return _x;
			}

			int8_t y() const
			{
				return _y;
			}

			int8_t z() const
			{
				return -(_x + _y);
			}

			int16_t dump() const
			{
				return (_x << 8) | _y;
			}

		private:
			static bool isValid(int8_t x, int8_t y)
			{
				return x >= 0 && x < (l * 2 - 1) &&
				       y >= 0 && y < (l * 2 - 1) &&
				       (x + y) >= (l - 1) &&
				       (x + y) <= (l - 1) * 3;
			}

			bool isValid() const
			{
				return isValid(_x, _y);
			}

			operator bool() const
			{
				return isValid();
			}

			CoordinateVec getCoordinates(const std::array<std::pair<int8_t, int8_t>, 6>& steps, int8_t distance) const
			{
				CoordinateVec vec;

				for(int direction = 0; direction < 6; direction++)
				{
					std::pair<int, int> op = steps.at(direction);

					_Coordinate tmpCoord(*this);
					for(int i = 0; i < distance; i++)
					{
						tmpCoord = {tmpCoord->_x + op.first, tmpCoord->_y + op.second};

						// if one step into this direction results in a
						// invalid coordinate, all further ones do too
						if(!tmpCoord)
							break;

						vec.push_back(tmpCoord);
					}
				}

				return vec;
			}

		public:
			bool operator==(_Coordinate other) const
			{
				return _x == other._x && _y == other._y;
			}

			bool operator!=(_Coordinate other) const
			{
				return _x != other._x || _y != other._y;
			}

			bool operator<(_Coordinate other) const
			{
				return dump() < other.dump();
			}

			/** Get the distance to another coordinate in form of the amount
			    of single moves to adjacent tiles required to move there
			 */
			int8_t getDistance(_Coordinate other) const
			{
				// Concept from http://keekerdc.com/2011/03/hexagon-grids-coordinate-systems-and-distance-calculations/
				// I have no idea why the maximum of x-, y- and z-difference
				// of the coordinates equals the distance between them...
				return *(std::set<int>({abs(_x - other._x), abs(_y - other._y), abs(z() - other.z())}).rbegin());
			}

			/// Check if the given coordinate is reachable in one orthogonal move
			bool isOrthogonal(_Coordinate other) const
			{
				return _x == other._x || _y == other._y || z() == other.z();
			}

			/** Like getDistance(), but return -1 if the given coordinate
			    is not reachable in one orthogonal move

			    An orthogonal move is a straight move in one of the six
			    directions of the neighboring hex-tiles.
			 */
			int8_t getDistanceOrthogonal(_Coordinate other) const
			{
				if(!isOrthogonal(other))
					return -1;

				return getDistance(other);
			}

			/** Get all coordinates reachable in one orthogonal move of
			    maximally the provided distance of tiles

			    The default value is the maximal distance possible on
			    this hexagon (no distance limit).
			 */
			CoordinateVec getCoordinatesOrthogonal(int8_t distance = (l * 2 - 2)) const
			{
				static const std::array<std::pair<int8_t, int8_t>, 6> steps = {
						std::make_pair(-1,  1), // top left
						std::make_pair( 0,  1), // top right
						std::make_pair( 1,  0), // right
						std::make_pair( 1, -1), // bottom right
						std::make_pair( 0, -1), // bottom left
						std::make_pair(-1,  0)  // left
					};

				return getCoordinates(steps, distance);
			}

			/// Check if the given coordinate is reachable in one diagonal move
			bool isDiagonal(_Coordinate other) const
			{
				int8_t dX = abs(_x - other._x);
				int8_t dY = abs(_y - other._y);
				int8_t dZ = abs(z() - other.z());

				return (dX == dY && dX == dZ / 2) ||
				       (dX == dZ && dX == dY / 2) ||
				       (dY == dZ && dY == dX / 2);
			}

			/** Get the diagonal distance to a coordinate, or -1 if
			    the coordinate isn't reachable in one diagonal move

			    A diagonal move is a straight move in one of the six
			    directions of the lines between the neighboring hex-tiles.
			 */
			int8_t getDistanceDiagonal(_Coordinate other) const
			{
				if(!isDiagonal(other))
					return -1;

				return getDistance(other) / 2;
			}

			/** Get all coordinates reachable in one diagonal move of
			    maximally the provided distance of tiles

			    The default value is the maximal distance possible on
			    this hexagon (no distance limit).
			 */
			CoordinateVec getCoordinatesDiagonal(int8_t distance = (l * 1)) const
			{
				static const std::array<std::pair<int8_t, int8_t>, 6> steps = {
						std::make_pair(-1,  2), // top
						std::make_pair( 1,  1), // top right
						std::make_pair( 2, -1), // bottom right
						std::make_pair( 1, -2), // bottom
						std::make_pair(-1, -1), // bottom left
						std::make_pair(-2,  1)  // top left
					};

				return getCoordinates(steps, distance);
			}

			/** Get the distance to another coordinate with the same distance to
			    the center Coordinate along the line of these coordinates, or -1
			    if the coordinate isn't reachable while only moving on that line.

			    All possible movement targets here are along a hexagonal line.
			    The direct distance from this coordinate to another one on that
			    line may be different than the distance along the line.
			 */
			// There certainly is no other rule set than MikeL's that uses this
			// but there probably is no better place to put this code either.
			int8_t getDistanceHexagonalLine(_Coordinate other, _Coordinate center) const
			{
				// Check if the given coordinate has the same distance to center as this
				if(getDistance(center) != other.getDistance(center))
					return -1;

				// TODO
			}

			/// Check if the given coordinate is a direct neighbor
			bool isAdjacent(_Coordinate other) const
			{
				return getDistance() == 1;
			}

			/// Get all adjacent coordinates
			CoordinateVec getCoordinatesAdjacent()
			{
				return getCoordinatesOrthogonal(1);
			}

			bool set(int8_t x, int8_t y)
			{
				if(isValid(x, y))
				{
					_x = x;
					_y = y;

					return true;
				}

				return false;
			}

			/// @{
			/// Create a Coordinate object from an x and an y
			/// If the coordinte is invalid, return nullptr
			static std::unique_ptr<_Coordinate> create(int8_t x, int8_t y)
			{
				if(isValid(x, y))
					return std::unique_ptr<_Coordinate>(new _Coordinate(x, y));

				return nullptr;
			}

			static std::unique_ptr<_Coordinate> create(std::pair<int8_t, int8_t> c)
			{
				if(isValid(c.first, c.second))
					return std::unique_ptr<_Coordinate>(new _Coordinate(c.first, c.second));

				return nullptr;
			}
			/// @}

			/// Create a Coordinate object from a coordinate in the public notation
			/// (see mockup/hexboard-coordinates-public.svg)
			static std::unique_ptr<_Coordinate> createFromStr(const std::string& str)
			{
				// This function will currently fail on hexagons with l > 13 because there
				// would be multiple letters for the y coordinate in the public notation.
				// TODO: Decide on whether to set a maximum l of 13 or to alter this function

				if(str.length() < 2)
					return nullptr;

				/* x: When using char's for calculations, their ASCII values are used,
				      and as the uppercase letters are consecutive in the ASCII table,
				      this will result in 0 for 'A', 1 for 'B' and so on.
				      We don't accept lowercase letters.
				   y: Public coordinate notation starts with 1, we start with 0
				 */
				return {str.at(0) - 'A', std::stoi(str.substr(1)) - 1};
			}
	};

	/* This should rather be a namespace, but namespaces cannot have template parameters.
	   hexagon<6>::Coordinate is way better understandable than hexagon::Coordinate<6>
	   so this is implemented as a template class with a deleted constructor.
	   The template parameter l stands for the edge length of the hexagon.
	 */
	template <int l>
	class hexagon
	{
		/* The smallest possible hexagon has 7 tiles and an edge lenth of 2
		   The largest possible hexagon in which the highest x and y can be represented
		   using a signed 8 bit integer has an edge length of 64 (=> width and height 127)
		 */
		static_assert(l >= 2,  "The minimum size of the hexagon edge length is 2.");
		static_assert(l <= 64, "The maximum size of the hexagon edge length is 64.");

		private:
			hexagon() = delete;

		public:
			typedef _Coordinate<l> Coordinate;
			typedef typename _Coordinate<l>::CoordinateVec CoordinateVec;

			/// Get the edge length of the hexagon (template parameter)
			static const int edgeLength = l;

			/// Get a container with all possible coordinates in this hexagon
			static CoordinateVec getAllCoordinates()
			{
				static CoordinateVec vec;

				if(vec.empty())
				{
					for(int x = 0; x < (2 * l) - 1; x++)
					{
						for(int y = 0; y < (2 * l) - 1; y++)
						{
							std::unique_ptr<Coordinate> c = Coordinate::create(x, y);

							if(c) vec.push_back(*c);
						}
					}
				}

				return vec;
			}
	};
}

namespace std
{
	template <int l>
	struct hash<cyvmath::_Coordinate<l>>
	{
		size_t operator()(const cyvmath::_Coordinate<l>& coord) const
		{
			return hash<int16_t>()(coord.dump());
		}
	};
}

#endif // _CYVMATH_HEXAGON_HPP_
<|endoftext|>