<commit_before>
#include <deque>
#include <iterator>
#include <list>
#include <vector>
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest.h"
#include "iguana/json_reader.hpp"
#include "test_headers.h"
#include <iguana/json.hpp>
#include <iguana/json_util.hpp>
#include <iostream>

TEST_CASE("test parse item num_t") {
  {
    std::string str{"1.4806532964699196e-22"};
    double p{};
    iguana::parse_item(p, str.begin(), str.end());
    CHECK(p == 1.4806532964699196e-22);
  }
  {
    std::string str{""};
    double p{};
    CHECK_THROWS(iguana::parse_item(p, str.begin(), str.end()));
  }
  {
    std::string str{"1.0"};
    int p{};
    iguana::parse_item(p, str.begin(), str.end());
    CHECK(p == 1);
  }
  {
    std::string str{"3000000"};
    long long p{};
    iguana::parse_item(p, str.begin(), str.end());
    CHECK(p == 3000000);
  }
  {
    std::string str;
    str.append(300, '1');
    int p{};
    CHECK_THROWS(iguana::parse_item(p, str.begin(), str.end()));
  }
  {
    std::list<char> arr{'[', '0', '.', '9', ']'};
    std::vector<double> test;
    iguana::from_json(test, arr);
    CHECK(test[0] == 0.9);

    std::deque<char> arr1{'[', '0', '.', '9', ']'};
    iguana::from_json(test, arr1);
    CHECK(test[0] == 0.9);
  }
  {
    std::list<char> arr{'0', '.', '9'};
    for (int i = 0; i < 999; i++) {
      arr.push_back('1');
    }

    double test = 0;
    CHECK_THROWS(iguana::parse_item(test, arr.begin(), arr.end()));
  }
}

TEST_CASE("test parse item array_t") {
  {
    std::string str{"[1, -222]"};
    std::array<int, 2> test;
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test[0] == 1);
    CHECK(test[1] == -222);
  }
  {
    std::string str{"[1, -222,"};
    std::array<int, 2> test;
    CHECK_NOTHROW(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[   "};
    std::array<int, 2> test;
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[ ]  "};
    std::array<int, 2> test;
    CHECK_NOTHROW(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[ 1.2345]  "};
    std::array<int, 2> test;
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
}

TEST_CASE("test parse item str_t") {
  {
    std::string str{"\"aaaaaaaaaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(1, test.size()));
  }
  {
    // this case throw at json_util@line 132
    std::string str{"\"aaa1\""};
    std::string test{};
    // iguana::parse_item(test, str.begin(), str.end());
    // CHECK(test == str.substr(1, test.size()));
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('\\');
    str.push_back('a');
    str.push_back('\"');
    str.push_back('a');
    str.push_back('a');
    str.push_back('1');
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());

    auto begin = str.begin();
    std::advance(begin, 2);
    CHECK(test == "a");
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('a');
    str.push_back('a');
    str.push_back('a');
    str.push_back('1');
    std::string test{};
    test.resize(3);
    iguana::parse_item(test, str.begin(), str.end());
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('\\');
    str.push_back('a');
    str.push_back('\"');
    std::string test{};
    test.resize(1);
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == "a");
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('a');
    str.push_back('\\');
    str.push_back('\"');
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    // CHECK(test == "a");
  }
  {
    std::string str{"\"\\aaaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(2, test.size()));
  }
  {
    std::string str{"\"aaaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(1, test.size()));
  }
}

TEST_CASE("test parse item seq container") {
  {
    std::string str{"[0,1,2,3]"};
    std::vector<double> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test.size() == 4);
    CHECK(test[0] == 0);
    CHECK(test[1] == 1);
    CHECK(test[2] == 2);
    CHECK(test[3] == 3);
  }
  {
    std::string str{"[0,1,2,3,]"};
    std::vector<double> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[0,1,2,3,"};
    std::vector<double> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[0,1,2"};
    std::array<int, 3> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }

  {
      std::string str{ "[0,1,2" };
      std::list<int> test{};
      CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
}

TEST_CASE("test parse item map container") {
  {
    std::string str{"{\"key1\":\"value1\", \"key2\":\"value2\"}"};
    std::map<std::string, std::string> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test.size() == 2);
    CHECK(test.at("key1") == "value1");
    CHECK(test.at("key2") == "value2");
  }
}

TEST_CASE("test parse item char") {
  {
    std::string str{"\"c\""};
    char test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == 'c');
  }
  {
    std::string str{"\""};
    char test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{R"("\)"};
    char test{};
    CHECK_THROWS_WITH(iguana::parse_item(test, str.begin(), str.end()),
                      "Unxpected end of buffer");
  }
  {
    std::string str{""};
    char test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"\"\\a\""};
    char test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == 'a');
  }
}

TEST_CASE("test parse item tuple") {
  {
    std::string str{"[1],\"a\",1.5]"};

    std::tuple<int, std::string, double> tp;

    iguana::parse_item(tp, str.begin(), str.end());
    CHECK(std::get<0>(tp) == 1);
  }
  {
    std::string str{"[1,\"a\",1.5,[1,1.5]]"};

    std::tuple<int, std::string, double, std::tuple<int, double>> tp;

    iguana::parse_item(tp, str.begin(), str.end());
    CHECK(std::get<0>(tp) == 1);
  }
}

TEST_CASE("test parse item bool") {
  {
    std::string str{"true"};
    bool test = false;
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == true);
  }
  {
    std::string str{"false"};
    bool test = true;
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == false);
  }
  {
    std::string str{"True"};
    bool test = false;

    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"False"};
    bool test = true;

    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"\"false\""};
    bool test = false;

    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{""};
    bool test = false;
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
}

TEST_CASE("test parse item optional") {
  {
    std::string str{"null"};
    std::optional<int> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(!test.has_value());
  }
  {
    std::string str{""};
    std::optional<int> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"1"};
    std::optional<int> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(*test == 1);
  }
}

TEST_CASE("test unknown fields") {
  std::string str = R"({"dummy":0, "name":"tom", "age":20})";
  person p;
  CHECK_THROWS_WITH(iguana::from_json(p, str), "Unknown key: dummy");

  std::string str1 = R"({"name":"tom", "age":20})";
  person p1;
  iguana::from_json(p1, str1);

  std::string str2 = R"({"\name":"\tom", "age":20})";
  person p2;
  iguana::from_json(p2, str2);
  std::cout << p2.name << "\n";
  CHECK(p2.name == "tom");
}

TEST_CASE("test from_json_file") {
  std::string str = R"({"name":"tom", "age":20})";
  std::string filename = "test.json";
  std::ofstream out(filename, std::ios::binary);
  out.write(str.data(), str.size());
  out.close();

  person obj;
  iguana::from_json_file(obj, filename);
  CHECK(obj.name == "tom");
  CHECK(obj.age == 20);

  std::filesystem::remove(filename);

  person p;
  CHECK_THROWS_AS(iguana::from_json_file(p, "not_exist.json"),
                  std::runtime_error);

  std::string cur_path = std::filesystem::current_path().string();
  std::filesystem::create_directories("dummy_test_dir");
  CHECK_THROWS_AS(iguana::from_json_file(p, "dummy_test_dir"),
                  std::runtime_error);
  std::filesystem::remove("dummy_test_dir");

  std::ofstream out1("dummy_test_dir.json", std::ios::binary);
  CHECK_THROWS_AS(iguana::from_json_file(p, "dummy_test_dir.json"),
                  std::runtime_error);
  out1.close();
  std::filesystem::remove("dummy_test_dir.json");
}

// doctest comments
// 'function' : must be 'attribute' - see issue #182
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) int main(int argc, char **argv) {
  return doctest::Context(argc, argv).run();
}
DOCTEST_MSVC_SUPPRESS_WARNING_POP<commit_msg>open bug UT<commit_after>
#include <deque>
#include <iterator>
#include <list>
#include <vector>
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest.h"
#include "iguana/json_reader.hpp"
#include "test_headers.h"
#include <iguana/json.hpp>
#include <iguana/json_util.hpp>
#include <iostream>

TEST_CASE("test parse item num_t") {
  {
    std::string str{"1.4806532964699196e-22"};
    double p{};
    iguana::parse_item(p, str.begin(), str.end());
    CHECK(p == 1.4806532964699196e-22);
  }
  {
    std::string str{""};
    double p{};
    CHECK_THROWS(iguana::parse_item(p, str.begin(), str.end()));
  }
  {
    std::string str{"1.0"};
    int p{};
    iguana::parse_item(p, str.begin(), str.end());
    CHECK(p == 1);
  }
  {
    std::string str{"3000000"};
    long long p{};
    iguana::parse_item(p, str.begin(), str.end());
    CHECK(p == 3000000);
  }
  {
    std::string str;
    str.append(300, '1');
    int p{};
    CHECK_THROWS(iguana::parse_item(p, str.begin(), str.end()));
  }
  {
    std::list<char> arr{'[', '0', '.', '9', ']'};
    std::vector<double> test;
    iguana::from_json(test, arr);
    CHECK(test[0] == 0.9);

    std::deque<char> arr1{'[', '0', '.', '9', ']'};
    iguana::from_json(test, arr1);
    CHECK(test[0] == 0.9);
  }
  {
    std::list<char> arr{'0', '.', '9'};
    for (int i = 0; i < 999; i++) {
      arr.push_back('1');
    }

    double test = 0;
    CHECK_THROWS(iguana::parse_item(test, arr.begin(), arr.end()));
  }
}

TEST_CASE("test parse item array_t") {
  {
    std::string str{"[1, -222]"};
    std::array<int, 2> test;
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test[0] == 1);
    CHECK(test[1] == -222);
  }
  {
    std::string str{"[1, -222,"};
    std::array<int, 2> test;
    CHECK_NOTHROW(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[   "};
    std::array<int, 2> test;
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[ ]  "};
    std::array<int, 2> test;
    CHECK_NOTHROW(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[ 1.2345]  "};
    std::array<int, 2> test;
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
}

TEST_CASE("test parse item str_t") {
  {
    std::string str{"\"aaaaaaaaaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(1, test.size()));
  }
  {
    // this case throw at json_util@line 132
    std::string str{"\"aaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(1, test.size()));
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('\\');
    str.push_back('a');
    str.push_back('\"');
    str.push_back('a');
    str.push_back('a');
    str.push_back('1');
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());

    auto begin = str.begin();
    std::advance(begin, 2);
    CHECK(test == "a");
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('a');
    str.push_back('a');
    str.push_back('a');
    str.push_back('1');
    std::string test{};
    test.resize(3);
    iguana::parse_item(test, str.begin(), str.end());
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('\\');
    str.push_back('a');
    str.push_back('\"');
    std::string test{};
    test.resize(1);
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == "a");
  }
  {
    std::list<char> str;
    str.push_back('\"');
    str.push_back('a');
    str.push_back('\\');
    str.push_back('\"');
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == "a");
  }
  {
    std::string str{"\"\\aaaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(2, test.size()));
  }
  {
    std::string str{"\"aaaa1\""};
    std::string test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == str.substr(1, test.size()));
  }
}

TEST_CASE("test parse item seq container") {
  {
    std::string str{"[0,1,2,3]"};
    std::vector<double> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test.size() == 4);
    CHECK(test[0] == 0);
    CHECK(test[1] == 1);
    CHECK(test[2] == 2);
    CHECK(test[3] == 3);
  }
  {
    std::string str{"[0,1,2,3,]"};
    std::vector<double> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[0,1,2,3,"};
    std::vector<double> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"[0,1,2"};
    std::array<int, 3> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }

  {
      std::string str{ "[0,1,2" };
      std::list<int> test{};
      CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
}

TEST_CASE("test parse item map container") {
  {
    std::string str{"{\"key1\":\"value1\", \"key2\":\"value2\"}"};
    std::map<std::string, std::string> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test.size() == 2);
    CHECK(test.at("key1") == "value1");
    CHECK(test.at("key2") == "value2");
  }
}

TEST_CASE("test parse item char") {
  {
    std::string str{"\"c\""};
    char test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == 'c');
  }
  {
    std::string str{"\""};
    char test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{R"("\)"};
    char test{};
    CHECK_THROWS_WITH(iguana::parse_item(test, str.begin(), str.end()),
                      "Unxpected end of buffer");
  }
  {
    std::string str{""};
    char test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"\"\\a\""};
    char test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == 'a');
  }
}

TEST_CASE("test parse item tuple") {
  {
    std::string str{"[1],\"a\",1.5]"};

    std::tuple<int, std::string, double> tp;

    iguana::parse_item(tp, str.begin(), str.end());
    CHECK(std::get<0>(tp) == 1);
  }
  {
    std::string str{"[1,\"a\",1.5,[1,1.5]]"};

    std::tuple<int, std::string, double, std::tuple<int, double>> tp;

    iguana::parse_item(tp, str.begin(), str.end());
    CHECK(std::get<0>(tp) == 1);
  }
}

TEST_CASE("test parse item bool") {
  {
    std::string str{"true"};
    bool test = false;
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == true);
  }
  {
    std::string str{"false"};
    bool test = true;
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(test == false);
  }
  {
    std::string str{"True"};
    bool test = false;

    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"False"};
    bool test = true;

    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"\"false\""};
    bool test = false;

    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{""};
    bool test = false;
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
}

TEST_CASE("test parse item optional") {
  {
    std::string str{"null"};
    std::optional<int> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(!test.has_value());
  }
  {
    std::string str{""};
    std::optional<int> test{};
    CHECK_THROWS(iguana::parse_item(test, str.begin(), str.end()));
  }
  {
    std::string str{"1"};
    std::optional<int> test{};
    iguana::parse_item(test, str.begin(), str.end());
    CHECK(*test == 1);
  }
}

TEST_CASE("test unknown fields") {
  std::string str = R"({"dummy":0, "name":"tom", "age":20})";
  person p;
  CHECK_THROWS_WITH(iguana::from_json(p, str), "Unknown key: dummy");

  std::string str1 = R"({"name":"tom", "age":20})";
  person p1;
  iguana::from_json(p1, str1);

  std::string str2 = R"({"\name":"\tom", "age":20})";
  person p2;
  iguana::from_json(p2, str2);
  std::cout << p2.name << "\n";
  CHECK(p2.name == "tom");
}

TEST_CASE("test from_json_file") {
  std::string str = R"({"name":"tom", "age":20})";
  std::string filename = "test.json";
  std::ofstream out(filename, std::ios::binary);
  out.write(str.data(), str.size());
  out.close();

  person obj;
  iguana::from_json_file(obj, filename);
  CHECK(obj.name == "tom");
  CHECK(obj.age == 20);

  std::filesystem::remove(filename);

  person p;
  CHECK_THROWS_AS(iguana::from_json_file(p, "not_exist.json"),
                  std::runtime_error);

  std::string cur_path = std::filesystem::current_path().string();
  std::filesystem::create_directories("dummy_test_dir");
  CHECK_THROWS_AS(iguana::from_json_file(p, "dummy_test_dir"),
                  std::runtime_error);
  std::filesystem::remove("dummy_test_dir");

  std::ofstream out1("dummy_test_dir.json", std::ios::binary);
  CHECK_THROWS_AS(iguana::from_json_file(p, "dummy_test_dir.json"),
                  std::runtime_error);
  out1.close();
  std::filesystem::remove("dummy_test_dir.json");
}

// doctest comments
// 'function' : must be 'attribute' - see issue #182
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) int main(int argc, char **argv) {
  return doctest::Context(argc, argv).run();
}
DOCTEST_MSVC_SUPPRESS_WARNING_POP<|endoftext|>


<commit_before><commit_msg>Remove pointless (and potentially redundant) code.<commit_after><|endoftext|>


<commit_before>#include "game/enemy_tracker.h"

using game::Position;
using game::Race;

namespace game {

EnemyTracker::EnemyTracker(game::CarTracker& car_tracker,
    const game::Race& race,
    const std::string& color,
    const Position& position)
  : car_tracker_(car_tracker), race_(race), color_(color),
    velocity_predictor_(car_tracker, race) {
  state_ = CarState(position);
  piece_speed_.resize(race_.track().pieces().size(), 0);
  piece_data_points_.resize(race_.track().pieces().size(), 0);
}

void EnemyTracker::RecordTick(const game::Position& position) {
  if (skip_time_ >= 0) skip_time_--;
  if (skip_time_ == 0) state_ = CarState(position);
  if (skip_time_ < 0) accelerating_ = false;

  if (dead_) time_since_crash_++;
}

bool EnemyTracker::ShouldRecord() const {
  if (accelerating_ || dead_ || finished_ || disabled_) return false;
  return true;
}

void EnemyTracker::RecordPosition(const game::Position& position) {
  RecordTick(position);
  state_ = car_tracker_.CreateCarState(state_, position);

  if (ShouldRecord()) {
    int piece = state_.position().piece();

    piece_speed_[piece] =
      double(piece_speed_[piece] * piece_data_points_[piece] + state_.velocity()) /
      double(piece_data_points_[piece] + 1);

    piece_data_points_[piece]++;

    average_speed_ =
      double(average_speed_ * average_data_points_ + state_.velocity()) /
      double(average_data_points_ + 1);

    average_data_points_++;
  }

  velocity_predictor_.Record(state_);
}

// TODO OBSOLETE
Position EnemyTracker::PositionAfterTime(int time, int target_lane) const {
  auto state = state_;

  if (target_lane != -1) {
    if (state.position().end_lane() - 1 == target_lane)
      state.set_switch_state(Switch::kSwitchLeft);

    if (state.position().end_lane() + 1 == target_lane)
      state.set_switch_state(Switch::kSwitchRight);
  }

  // Wait until spawn
  if (dead_ == true)
    time -= time_to_spawn();

  // Do rest ticks regularly
  for (int i = 0; i < min(time, 1000); i++) {
    double throttle = car_tracker_.velocity_model().PredictThrottle(
        Velocity(state.position()));

    // Acceleration from too low speed
    if (state.velocity() < 0.9 * Velocity(state.position()))
      throttle = 1;

    state = car_tracker_.Predict(state, Command(throttle));
  }

  return state.position();
}

int EnemyTracker::TimeToPosition(const Position& target, vector<Position>* steps) const {
  auto position = state_.position();
  int velocity = state_.velocity();

  int time = 0;

  if (steps != nullptr)
    steps->push_back(position);

  if (dead_) {
    if (steps != nullptr)
      for (int i = 1; i <= time_to_spawn(); i++)
        steps->push_back(position);
    time = time_to_spawn();
    velocity = 0;
  }

  const int kCarLength = race_.cars()[0].length();

  for (int limit = 0; limit < 1000; limit++, time++) {
    double target_velocity = Velocity(position);
    double reachable_velocity = car_tracker_.velocity_model().Predict(velocity, 1);

    // TODO turbo
    if (target_velocity > reachable_velocity * 1.05) { // Acceleration from too low speed
      position = car_tracker_.PredictPosition(position, reachable_velocity, target.end_lane());
      velocity = reachable_velocity;
    } else {
      position = car_tracker_.PredictPosition(position, target_velocity, target.end_lane());
      velocity = target_velocity;
    }

    if (steps != nullptr)
      steps->push_back(position);

    if (car_tracker_.DistanceBetween(target, position, nullptr, velocity) < velocity)
      return time;
  }

  return 10000;
}

// Checks if time difference on that part of track is enough to overtake him
// Based on best laptime right now
bool EnemyTracker::CanOvertake(const EnemyTracker& noobek, int from, int to) {
  if (best_lap_ == -1 || noobek.best_lap() == -1)
    return true;

  // Cant overtake faster
  if (best_lap_ > noobek.best_lap())
    return false;

  // TODO hella inaccurate
  int pieces = from <= to ? to - from + 1 : to + race_.track().pieces().size() - from + 1;

  double percent = double(pieces) / double(race_.track().pieces().size());

  int ticks_difference = double(noobek.best_lap() - best_lap_) * percent;

  const double kCarLength = race_.cars().at(0).length();

  double distance = 0;
  for (int i = 0; i < ticks_difference; i++) {
    distance += piece_speed_[to];
    // TODO
    if (distance > 2.0 * kCarLength)
      return true;
  }

  return false;
}

double EnemyTracker::Velocity(const Position& position) const {
  double v = velocity_predictor_.Velocity(position);
  return v;

  double velocity = piece_speed_[position.piece()];
  if (velocity < 1e-9) // Not yet calculated
    velocity = average_speed_;
  return velocity;
}

// Record methods

void EnemyTracker::RecordLapTime(int time) {
  ready_ = true;
  lap_times_.push_back(time);
  if (best_lap_ == -1 || best_lap_ > time)
    best_lap_ = time;
}

void EnemyTracker::RecordCrash() {
  time_since_crash_ = 0;
  dead_ = true;
}

void EnemyTracker::DNF() {
  disabled_ = true;
}

void EnemyTracker::FinishedRace() {
  finished_ = true;
}

void EnemyTracker::Resurrect() {
  if (!disabled_) {
    skip_time_ = kSkipTime;
    accelerating_ = true;
    finished_ = false;
    dead_ = false;
  }
}

void EnemyTracker::Spawned() {
  state_.ResetTurbo();
  dead_ = false;
  accelerating_ = true;
  skip_time_ = kSkipTime;
}

void EnemyTracker::TurboStarted() {
  state_.EnableTurbo();
}

void EnemyTracker::NewTurbo(const Turbo& turbo) {
  state_.AddNewTurbo(turbo);
}

}  // namespace game
<commit_msg>fix int bug in TimeToPosition<commit_after>#include "game/enemy_tracker.h"

using game::Position;
using game::Race;

namespace game {

EnemyTracker::EnemyTracker(game::CarTracker& car_tracker,
    const game::Race& race,
    const std::string& color,
    const Position& position)
  : car_tracker_(car_tracker), race_(race), color_(color),
    velocity_predictor_(car_tracker, race) {
  state_ = CarState(position);
  piece_speed_.resize(race_.track().pieces().size(), 0);
  piece_data_points_.resize(race_.track().pieces().size(), 0);
}

void EnemyTracker::RecordTick(const game::Position& position) {
  if (skip_time_ >= 0) skip_time_--;
  if (skip_time_ == 0) state_ = CarState(position);
  if (skip_time_ < 0) accelerating_ = false;

  if (dead_) time_since_crash_++;
}

bool EnemyTracker::ShouldRecord() const {
  if (accelerating_ || dead_ || finished_ || disabled_) return false;
  return true;
}

void EnemyTracker::RecordPosition(const game::Position& position) {
  RecordTick(position);
  state_ = car_tracker_.CreateCarState(state_, position);

  if (ShouldRecord()) {
    int piece = state_.position().piece();

    piece_speed_[piece] =
      double(piece_speed_[piece] * piece_data_points_[piece] + state_.velocity()) /
      double(piece_data_points_[piece] + 1);

    piece_data_points_[piece]++;

    average_speed_ =
      double(average_speed_ * average_data_points_ + state_.velocity()) /
      double(average_data_points_ + 1);

    average_data_points_++;
  }

  velocity_predictor_.Record(state_);
}

// TODO OBSOLETE
Position EnemyTracker::PositionAfterTime(int time, int target_lane) const {
  auto state = state_;

  if (target_lane != -1) {
    if (state.position().end_lane() - 1 == target_lane)
      state.set_switch_state(Switch::kSwitchLeft);

    if (state.position().end_lane() + 1 == target_lane)
      state.set_switch_state(Switch::kSwitchRight);
  }

  // Wait until spawn
  if (dead_ == true)
    time -= time_to_spawn();

  // Do rest ticks regularly
  for (int i = 0; i < min(time, 1000); i++) {
    double throttle = car_tracker_.velocity_model().PredictThrottle(
        Velocity(state.position()));

    // Acceleration from too low speed
    if (state.velocity() < 0.9 * Velocity(state.position()))
      throttle = 1;

    state = car_tracker_.Predict(state, Command(throttle));
  }

  return state.position();
}

int EnemyTracker::TimeToPosition(const Position& target, vector<Position>* steps) const {
  auto position = state_.position();
  double velocity = state_.velocity();

  int time = 0;

  if (steps != nullptr)
    steps->push_back(position);

  if (dead_) {
    if (steps != nullptr)
      for (int i = 1; i <= time_to_spawn(); i++)
        steps->push_back(position);
    time = time_to_spawn();
    velocity = 0;
  }

  const double kCarLength = race_.cars()[0].length();

  for (int limit = 0; limit < 1000; limit++, time++) {
    double target_velocity = Velocity(position);
    double reachable_velocity = car_tracker_.velocity_model().Predict(velocity, 1);

    // TODO turbo
    if (target_velocity > reachable_velocity * 1.05) { // Acceleration from too low speed
      position = car_tracker_.PredictPosition(position, reachable_velocity, target.end_lane());
      velocity = reachable_velocity;
    } else {
      position = car_tracker_.PredictPosition(position, target_velocity, target.end_lane());
      velocity = target_velocity;
    }

    if (steps != nullptr)
      steps->push_back(position);

    if (car_tracker_.DistanceBetween(target, position, nullptr, velocity) < velocity)
      return time;
  }

  return 10000;
}

// Checks if time difference on that part of track is enough to overtake him
// Based on best laptime right now
bool EnemyTracker::CanOvertake(const EnemyTracker& noobek, int from, int to) {
  if (best_lap_ == -1 || noobek.best_lap() == -1)
    return true;

  // Cant overtake faster
  if (best_lap_ > noobek.best_lap())
    return false;

  // TODO hella inaccurate
  int pieces = from <= to ? to - from + 1 : to + race_.track().pieces().size() - from + 1;

  double percent = double(pieces) / double(race_.track().pieces().size());

  int ticks_difference = double(noobek.best_lap() - best_lap_) * percent;

  const double kCarLength = race_.cars().at(0).length();

  double distance = 0;
  for (int i = 0; i < ticks_difference; i++) {
    distance += piece_speed_[to];
    // TODO
    if (distance > 2.0 * kCarLength)
      return true;
  }

  return false;
}

double EnemyTracker::Velocity(const Position& position) const {
  double v = velocity_predictor_.Velocity(position);
  return v;

  double velocity = piece_speed_[position.piece()];
  if (velocity < 1e-9) // Not yet calculated
    velocity = average_speed_;
  return velocity;
}

// Record methods

void EnemyTracker::RecordLapTime(int time) {
  ready_ = true;
  lap_times_.push_back(time);
  if (best_lap_ == -1 || best_lap_ > time)
    best_lap_ = time;
}

void EnemyTracker::RecordCrash() {
  time_since_crash_ = 0;
  dead_ = true;
}

void EnemyTracker::DNF() {
  disabled_ = true;
}

void EnemyTracker::FinishedRace() {
  finished_ = true;
}

void EnemyTracker::Resurrect() {
  if (!disabled_) {
    skip_time_ = kSkipTime;
    accelerating_ = true;
    finished_ = false;
    dead_ = false;
  }
}

void EnemyTracker::Spawned() {
  state_.ResetTurbo();
  dead_ = false;
  accelerating_ = true;
  skip_time_ = kSkipTime;
}

void EnemyTracker::TurboStarted() {
  state_.EnableTurbo();
}

void EnemyTracker::NewTurbo(const Turbo& turbo) {
  state_.AddNewTurbo(turbo);
}

}  // namespace game
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/internal/posix_wrapper/message_queue.hpp"
#include "iceoryx_hoofs/internal/posix_wrapper/unix_domain_socket.hpp"
#include "iceoryx_hoofs/platform/socket.hpp"
#include "iceoryx_hoofs/posix_wrapper/posix_call.hpp"

#include "test.hpp"

#include <atomic>
#include <chrono>
#include <thread>

namespace
{
using namespace ::testing;
using namespace ::testing::internal;
using namespace iox;
using namespace iox::posix;
using namespace iox::units::duration_literals;
using namespace iox::units;

using sendCall_t = std::function<cxx::expected<IpcChannelError>(const std::string&)>;
using receiveCall_t = std::function<cxx::expected<std::string, IpcChannelError>()>;

constexpr char goodName[] = "channel_test";

/// @req
/// @brief This test suite verifies the functionality which is specific to the UnixDomainSocket class
/// @pre server and client object are allocated and move to the member object of the fixture
/// @post StdErr is capture and outputed to StdCout
/// @note Most of the UnixDomainSocket functionality is tested in "IpcChannel_test"
class UnixDomainSocket_test : public Test
{
  public:
    void SetUp()
    {
        auto serverResult = UnixDomainSocket::create(
            goodName, IpcChannelSide::SERVER, UnixDomainSocket::MAX_MESSAGE_SIZE, MaxMsgNumber);
        ASSERT_THAT(serverResult.has_error(), Eq(false));
        server = std::move(serverResult.value());
        CaptureStderr();

        auto clientResult = UnixDomainSocket::create(
            goodName, IpcChannelSide::CLIENT, UnixDomainSocket::MAX_MESSAGE_SIZE, MaxMsgNumber);
        ASSERT_THAT(clientResult.has_error(), Eq(false));
        client = std::move(clientResult.value());
    }

    void TearDown()
    {
        std::string output = GetCapturedStderr();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    ~UnixDomainSocket_test()
    {
    }

    void createTestSocket(const UnixDomainSocket::UdsName_t& name)
    {
        static constexpr int32_t ERROR_CODE = -1;
        struct sockaddr_un sockAddr;
        int32_t sockfd;

        memset(&sockAddr, 0, sizeof(sockAddr));
        sockAddr.sun_family = AF_LOCAL;
        strncpy(sockAddr.sun_path, name.c_str(), name.size());

        iox::posix::posixCall(iox_socket)(AF_LOCAL, SOCK_DGRAM, 0)
            .failureReturnValue(ERROR_CODE)
            .evaluate()
            .and_then([&](auto& r) { sockfd = r.value; })
            .or_else([](auto&) {
                std::cerr << "unable to create socket\n";
                std::terminate();
            });

        iox::posix::posixCall(iox_bind)(sockfd, reinterpret_cast<struct sockaddr*>(&sockAddr), sizeof(sockAddr))
            .failureReturnValue(ERROR_CODE)
            .evaluate()
            .or_else([](auto&) {
                std::cerr << "unable to bind socket\n";
                std::terminate();
            });
    }

    void signalThreadReady()
    {
        doWaitForThread.store(false, std::memory_order_relaxed);
    }

    void waitForThread()
    {
        while (doWaitForThread.load(std::memory_order_relaxed))
        {
            std::this_thread::yield();
        }
    }

    const std::chrono::milliseconds WAIT_IN_MS{10};
    std::atomic_bool doWaitForThread{true};
    static constexpr uint64_t MaxMsgNumber = 10U;
    UnixDomainSocket server;
    UnixDomainSocket client;
};

constexpr uint64_t UnixDomainSocket_test::MaxMsgNumber;

TEST_F(UnixDomainSocket_test, UnlinkEmptySocketNameLeadsToInvalidChannelNameError)
{
    auto ret = UnixDomainSocket::unlinkIfExists(UnixDomainSocket::NoPathPrefix, "");
    ASSERT_TRUE(ret.has_error());
    EXPECT_THAT(ret.get_error(), Eq(IpcChannelError::INVALID_CHANNEL_NAME));
}

TEST_F(UnixDomainSocket_test, UnlinkEmptySocketNameWithPathPrefixLeadsToInvalidChannelNameError)
{
    auto ret = UnixDomainSocket::unlinkIfExists("");
    ASSERT_TRUE(ret.has_error());
    EXPECT_THAT(ret.get_error(), Eq(IpcChannelError::INVALID_CHANNEL_NAME));
}

TEST_F(UnixDomainSocket_test, UnlinkTooLongSocketNameWithPathPrefixLeadsToInvalidChannelNameError)
{
    UnixDomainSocket::UdsName_t longSocketName;
    for (uint64_t i = 0U; i < UnixDomainSocket::LONGEST_VALID_NAME - strlen(UnixDomainSocket::PATH_PREFIX) + 1; ++i)
    {
        longSocketName.append(cxx::TruncateToCapacity, "o");
    }
    auto ret = UnixDomainSocket::unlinkIfExists(longSocketName);
    ASSERT_TRUE(ret.has_error());
    EXPECT_THAT(ret.get_error(), Eq(IpcChannelError::INVALID_CHANNEL_NAME));
}

TEST_F(UnixDomainSocket_test, UnlinkExistingSocketIsSuccessful)
{
    UnixDomainSocket::UdsName_t socketFileName = UnixDomainSocket::PATH_PREFIX;
    socketFileName.append(cxx::TruncateToCapacity, "iceoryx-hoofs-moduletest.socket");
    createTestSocket(socketFileName);
    auto ret = UnixDomainSocket::unlinkIfExists(UnixDomainSocket::NoPathPrefix, socketFileName);
    EXPECT_FALSE(ret.has_error());
}

TEST_F(UnixDomainSocket_test, UnlinkExistingSocketWithPathPrefixLeadsIsSuccessful)
{
    UnixDomainSocket::UdsName_t socketFileName = "iceoryx-hoofs-moduletest.socket";
    UnixDomainSocket::UdsName_t socketFileNameWithPrefix = UnixDomainSocket::PATH_PREFIX;
    socketFileNameWithPrefix.append(cxx::TruncateToCapacity, socketFileName);
    createTestSocket(socketFileNameWithPrefix);
    auto ret = UnixDomainSocket::unlinkIfExists(socketFileName);
    EXPECT_FALSE(ret.has_error());
}

void sendOnServerLeadsToError(const sendCall_t& send)
{
    cxx::string<10> message{"Foo"};
    auto result = send(message);
    EXPECT_TRUE(result.has_error());
    ASSERT_THAT(result.get_error(), Eq(IpcChannelError::INTERNAL_LOGIC_ERROR));
}

TEST_F(UnixDomainSocket_test, TimedSendOnServerLeadsToError)
{
    sendOnServerLeadsToError([&](auto& msg) { return server.timedSend(msg, 1_ms); });
}

TEST_F(UnixDomainSocket_test, SendOnServerLeadsToError)
{
    sendOnServerLeadsToError([&](auto& msg) { return server.send(msg); });
}

void successfulSendAndReceive(const std::string& message, const sendCall_t& send, const receiveCall_t& receive)
{
    ASSERT_FALSE(send(message).has_error());

    auto receivedMessage = receive();
    ASSERT_FALSE(receivedMessage.has_error());
    EXPECT_EQ(message, *receivedMessage);
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithSendAndReceive)
{
    successfulSendAndReceive(
        "what's hypnotoads eye color?",
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithTimedSendAndReceive)
{
    successfulSendAndReceive(
        "the earth is a disc on the back of hypnotoad",
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithTimedSendAndTimedReceive)
{
    successfulSendAndReceive(
        "it is not the sun that rises, it is hypnotoad who is opening its eyes",
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithSendAndTimedReceive)
{
    successfulSendAndReceive(
        "what is the most beautiful color in the world? it's hypnotoad.",
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithSendAndReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.send(msg); }, [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithTimedSendAndReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.timedSend(msg, 1_ms); }, [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithTimedSendAndTimedReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.timedSend(msg, 1_ms); }, [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithSendAndTimedReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.send(msg); }, [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithSendAndReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithTimedSendAndReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithTimedSendAndTimedReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithSendAndTimedReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.timedReceive(1_ms); });
}

void unableToSendTooLongMessage(const sendCall_t& send)
{
    std::string message(UnixDomainSocket::MAX_MESSAGE_SIZE + 1, 'x');
    auto result = send(message);
    ASSERT_TRUE(result.has_error());
    EXPECT_EQ(result.get_error(), IpcChannelError::MESSAGE_TOO_LONG);
}

TEST_F(UnixDomainSocket_test, UnableToSendTooLongMessageWithSend)
{
    unableToSendTooLongMessage([&](auto& msg) { return client.send(msg); });
}

TEST_F(UnixDomainSocket_test, UnableToSendTooLongMessageWithTimedSend)
{
    unableToSendTooLongMessage([&](auto& msg) { return client.timedSend(msg, 1_ms); });
}

void receivingOnClientLeadsToError(const receiveCall_t& receive)
{
    auto result = receive();
    EXPECT_TRUE(result.has_error());
    ASSERT_THAT(result.get_error(), Eq(IpcChannelError::INTERNAL_LOGIC_ERROR));
}

TEST_F(UnixDomainSocket_test, ReceivingOnClientLeadsToErrorWithReceive)
{
    receivingOnClientLeadsToError([&] { return client.receive(); });
}

TEST_F(UnixDomainSocket_test, ReceivingOnClientLeadsToErrorWithTimedReceive)
{
    receivingOnClientLeadsToError([&] { return client.timedReceive(1_ms); });
}

// is not supported on mac os and behaves there like receive
#if !defined(__APPLE__)
TEST_F(UnixDomainSocket_test, TimedReceiveBlocks)
{
    auto start = std::chrono::steady_clock::now();
    auto msg = server.timedReceive(units::Duration::fromMilliseconds(WAIT_IN_MS.count()));
    auto end = std::chrono::steady_clock::now();
    EXPECT_THAT(end - start, Gt(WAIT_IN_MS));

    ASSERT_TRUE(msg.has_error());
    EXPECT_EQ(msg.get_error(), IpcChannelError::TIMEOUT);
}

TEST_F(UnixDomainSocket_test, TimedReceiveBlocksUntilMessageIsReceived)
{
    std::string message = "asdasda";
    std::thread waitThread([&] {
        this->signalThreadReady();
        auto start = std::chrono::steady_clock::now();
        auto msg = server.timedReceive(units::Duration::fromMilliseconds(WAIT_IN_MS.count() * 2));
        auto end = std::chrono::steady_clock::now();
        EXPECT_THAT(end - start, Gt(WAIT_IN_MS));

        ASSERT_FALSE(msg.has_error());
        EXPECT_EQ(*msg, message);
    });

    this->waitForThread();
    std::this_thread::sleep_for(WAIT_IN_MS);
    ASSERT_FALSE(client.send(message).has_error());
    waitThread.join();
}
#endif
} // namespace
<commit_msg>iox-#33 do not terminate directly in unit test - use ASSERT_ instead<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/internal/posix_wrapper/message_queue.hpp"
#include "iceoryx_hoofs/internal/posix_wrapper/unix_domain_socket.hpp"
#include "iceoryx_hoofs/platform/socket.hpp"
#include "iceoryx_hoofs/posix_wrapper/posix_call.hpp"

#include "test.hpp"

#include <atomic>
#include <chrono>
#include <thread>

namespace
{
using namespace ::testing;
using namespace ::testing::internal;
using namespace iox;
using namespace iox::posix;
using namespace iox::units::duration_literals;
using namespace iox::units;

using sendCall_t = std::function<cxx::expected<IpcChannelError>(const std::string&)>;
using receiveCall_t = std::function<cxx::expected<std::string, IpcChannelError>()>;

constexpr char goodName[] = "channel_test";

/// @req
/// @brief This test suite verifies the functionality which is specific to the UnixDomainSocket class
/// @pre server and client object are allocated and move to the member object of the fixture
/// @post StdErr is capture and outputed to StdCout
/// @note Most of the UnixDomainSocket functionality is tested in "IpcChannel_test"
class UnixDomainSocket_test : public Test
{
  public:
    void SetUp()
    {
        auto serverResult = UnixDomainSocket::create(
            goodName, IpcChannelSide::SERVER, UnixDomainSocket::MAX_MESSAGE_SIZE, MaxMsgNumber);
        ASSERT_THAT(serverResult.has_error(), Eq(false));
        server = std::move(serverResult.value());
        CaptureStderr();

        auto clientResult = UnixDomainSocket::create(
            goodName, IpcChannelSide::CLIENT, UnixDomainSocket::MAX_MESSAGE_SIZE, MaxMsgNumber);
        ASSERT_THAT(clientResult.has_error(), Eq(false));
        client = std::move(clientResult.value());
    }

    void TearDown()
    {
        std::string output = GetCapturedStderr();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    ~UnixDomainSocket_test()
    {
    }

    bool createTestSocket(const UnixDomainSocket::UdsName_t& name)
    {
        static constexpr int32_t ERROR_CODE = -1;
        struct sockaddr_un sockAddr;

        memset(&sockAddr, 0, sizeof(sockAddr));
        sockAddr.sun_family = AF_LOCAL;
        strncpy(sockAddr.sun_path, name.c_str(), name.size());

        bool socketCreationSuccess = true;
        iox::posix::posixCall(iox_socket)(AF_LOCAL, SOCK_DGRAM, 0)
            .failureReturnValue(ERROR_CODE)
            .evaluate()
            .and_then([&](auto& r) {
                iox::posix::posixCall(iox_bind)(
                    r.value, reinterpret_cast<struct sockaddr*>(&sockAddr), sizeof(sockAddr))
                    .failureReturnValue(ERROR_CODE)
                    .evaluate()
                    .or_else([&](auto&) {
                        std::cerr << "unable to bind socket\n";
                        socketCreationSuccess = false;
                    });
            })
            .or_else([&](auto&) {
                std::cerr << "unable to create socket\n";
                socketCreationSuccess = false;
            });

        return socketCreationSuccess;
    }

    void signalThreadReady()
    {
        doWaitForThread.store(false, std::memory_order_relaxed);
    }

    void waitForThread()
    {
        while (doWaitForThread.load(std::memory_order_relaxed))
        {
            std::this_thread::yield();
        }
    }

    const std::chrono::milliseconds WAIT_IN_MS{10};
    std::atomic_bool doWaitForThread{true};
    static constexpr uint64_t MaxMsgNumber = 10U;
    UnixDomainSocket server;
    UnixDomainSocket client;
};

constexpr uint64_t UnixDomainSocket_test::MaxMsgNumber;

TEST_F(UnixDomainSocket_test, UnlinkEmptySocketNameLeadsToInvalidChannelNameError)
{
    auto ret = UnixDomainSocket::unlinkIfExists(UnixDomainSocket::NoPathPrefix, "");
    ASSERT_TRUE(ret.has_error());
    EXPECT_THAT(ret.get_error(), Eq(IpcChannelError::INVALID_CHANNEL_NAME));
}

TEST_F(UnixDomainSocket_test, UnlinkEmptySocketNameWithPathPrefixLeadsToInvalidChannelNameError)
{
    auto ret = UnixDomainSocket::unlinkIfExists("");
    ASSERT_TRUE(ret.has_error());
    EXPECT_THAT(ret.get_error(), Eq(IpcChannelError::INVALID_CHANNEL_NAME));
}

TEST_F(UnixDomainSocket_test, UnlinkTooLongSocketNameWithPathPrefixLeadsToInvalidChannelNameError)
{
    UnixDomainSocket::UdsName_t longSocketName;
    for (uint64_t i = 0U; i < UnixDomainSocket::LONGEST_VALID_NAME - strlen(UnixDomainSocket::PATH_PREFIX) + 1; ++i)
    {
        longSocketName.append(cxx::TruncateToCapacity, "o");
    }
    auto ret = UnixDomainSocket::unlinkIfExists(longSocketName);
    ASSERT_TRUE(ret.has_error());
    EXPECT_THAT(ret.get_error(), Eq(IpcChannelError::INVALID_CHANNEL_NAME));
}

TEST_F(UnixDomainSocket_test, UnlinkExistingSocketIsSuccessful)
{
    UnixDomainSocket::UdsName_t socketFileName = UnixDomainSocket::PATH_PREFIX;
    socketFileName.append(cxx::TruncateToCapacity, "iceoryx-hoofs-moduletest.socket");
    ASSERT_TRUE(createTestSocket(socketFileName));
    auto ret = UnixDomainSocket::unlinkIfExists(UnixDomainSocket::NoPathPrefix, socketFileName);
    EXPECT_FALSE(ret.has_error());
}

TEST_F(UnixDomainSocket_test, UnlinkExistingSocketWithPathPrefixLeadsIsSuccessful)
{
    UnixDomainSocket::UdsName_t socketFileName = "iceoryx-hoofs-moduletest.socket";
    UnixDomainSocket::UdsName_t socketFileNameWithPrefix = UnixDomainSocket::PATH_PREFIX;
    socketFileNameWithPrefix.append(cxx::TruncateToCapacity, socketFileName);
    ASSERT_TRUE(createTestSocket(socketFileNameWithPrefix));
    auto ret = UnixDomainSocket::unlinkIfExists(socketFileName);
    EXPECT_FALSE(ret.has_error());
}

// the current contract of the unix domain socket is that a server can only receive
// and the client can only send
void sendOnServerLeadsToError(const sendCall_t& send)
{
    cxx::string<10> message{"Foo"};
    auto result = send(message);
    EXPECT_TRUE(result.has_error());
    EXPECT_THAT(result.get_error(), Eq(IpcChannelError::INTERNAL_LOGIC_ERROR));
}

TEST_F(UnixDomainSocket_test, TimedSendOnServerLeadsToError)
{
    sendOnServerLeadsToError([&](auto& msg) { return server.timedSend(msg, 1_ms); });
}

TEST_F(UnixDomainSocket_test, SendOnServerLeadsToError)
{
    sendOnServerLeadsToError([&](auto& msg) { return server.send(msg); });
}

void successfulSendAndReceive(const std::string& message, const sendCall_t& send, const receiveCall_t& receive)
{
    ASSERT_FALSE(send(message).has_error());

    auto receivedMessage = receive();
    ASSERT_FALSE(receivedMessage.has_error());
    EXPECT_EQ(message, *receivedMessage);
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithSendAndReceive)
{
    successfulSendAndReceive(
        "what's hypnotoads eye color?",
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithTimedSendAndReceive)
{
    successfulSendAndReceive(
        "the earth is a disc on the back of hypnotoad",
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithTimedSendAndTimedReceive)
{
    successfulSendAndReceive(
        "it is not the sun that rises, it is hypnotoad who is opening its eyes",
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfNonEmptyMessageWithSendAndTimedReceive)
{
    successfulSendAndReceive(
        "what is the most beautiful color in the world? it's hypnotoad.",
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithSendAndReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.send(msg); }, [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithTimedSendAndReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.timedSend(msg, 1_ms); }, [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithTimedSendAndTimedReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.timedSend(msg, 1_ms); }, [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfEmptyMessageWithSendAndTimedReceive)
{
    successfulSendAndReceive(
        "", [&](auto& msg) { return client.send(msg); }, [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithSendAndReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithTimedSendAndReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.receive(); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithTimedSendAndTimedReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.timedSend(msg, 1_ms); },
        [&]() { return server.timedReceive(1_ms); });
}

TEST_F(UnixDomainSocket_test, SuccessfulCommunicationOfMaxLengthMessageWithSendAndTimedReceive)
{
    successfulSendAndReceive(
        std::string(UnixDomainSocket::MAX_MESSAGE_SIZE, 'x'),
        [&](auto& msg) { return client.send(msg); },
        [&]() { return server.timedReceive(1_ms); });
}

void unableToSendTooLongMessage(const sendCall_t& send)
{
    std::string message(UnixDomainSocket::MAX_MESSAGE_SIZE + 1, 'x');
    auto result = send(message);
    ASSERT_TRUE(result.has_error());
    EXPECT_EQ(result.get_error(), IpcChannelError::MESSAGE_TOO_LONG);
}

TEST_F(UnixDomainSocket_test, UnableToSendTooLongMessageWithSend)
{
    unableToSendTooLongMessage([&](auto& msg) { return client.send(msg); });
}

TEST_F(UnixDomainSocket_test, UnableToSendTooLongMessageWithTimedSend)
{
    unableToSendTooLongMessage([&](auto& msg) { return client.timedSend(msg, 1_ms); });
}

// the current contract of the unix domain socket is that a server can only receive
// and the client can only send
void receivingOnClientLeadsToError(const receiveCall_t& receive)
{
    auto result = receive();
    EXPECT_TRUE(result.has_error());
    ASSERT_THAT(result.get_error(), Eq(IpcChannelError::INTERNAL_LOGIC_ERROR));
}

TEST_F(UnixDomainSocket_test, ReceivingOnClientLeadsToErrorWithReceive)
{
    receivingOnClientLeadsToError([&] { return client.receive(); });
}

TEST_F(UnixDomainSocket_test, ReceivingOnClientLeadsToErrorWithTimedReceive)
{
    receivingOnClientLeadsToError([&] { return client.timedReceive(1_ms); });
}

// is not supported on mac os and behaves there like receive
#if !defined(__APPLE__)
TEST_F(UnixDomainSocket_test, TimedReceiveBlocks)
{
    auto start = std::chrono::steady_clock::now();
    auto msg = server.timedReceive(units::Duration::fromMilliseconds(WAIT_IN_MS.count()));
    auto end = std::chrono::steady_clock::now();
    EXPECT_THAT(end - start, Gt(WAIT_IN_MS));

    ASSERT_TRUE(msg.has_error());
    EXPECT_EQ(msg.get_error(), IpcChannelError::TIMEOUT);
}

TEST_F(UnixDomainSocket_test, TimedReceiveBlocksUntilMessageIsReceived)
{
    std::string message = "asdasda";
    std::thread waitThread([&] {
        this->signalThreadReady();
        auto start = std::chrono::steady_clock::now();
        auto msg = server.timedReceive(units::Duration::fromMilliseconds(WAIT_IN_MS.count() * 2));
        auto end = std::chrono::steady_clock::now();
        EXPECT_THAT(end - start, Gt(WAIT_IN_MS));

        ASSERT_FALSE(msg.has_error());
        EXPECT_EQ(*msg, message);
    });

    this->waitForThread();
    std::this_thread::sleep_for(WAIT_IN_MS);
    ASSERT_FALSE(client.send(message).has_error());
    waitThread.join();
}
#endif
} // namespace
<|endoftext|>


<commit_before>#ifndef AX_MATRIX_EXPRESSION_H
#define AX_MATRIX_EXPRESSION_H
#include "TypeTraits.hpp"
#include "OperatorStructs.hpp"
#include "Dimension.hpp"
#include <utility>

namespace ax
{

namespace detail
{

template <typename T_lhs, typename T_oper, typename T_rhs,
          dimension_type I_dim_row, dimension_type I_dim_col>
class MatrixExpression
{
  public:

    static_assert(is_operator_struct<typename T_oper::tag>::value,
                  "invalid Expression Operator");

    using tag = matrix_expression_tag;
    using elem_t = typename T_lhs::elem_t;
    constexpr static dimension_type dim_row = I_dim_row;
    constexpr static dimension_type dim_col = I_dim_col;

    MatrixExpression(const T_lhs& lhs, const T_rhs& rhs)
        : l_(lhs), r_(rhs)
    {}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        return T_oper::apply(l_(i,j), r_(i,j));
    }

    T_lhs const& l_;
    T_rhs const& r_;
};

template <typename T_lhs, typename T_rhs,
          dimension_type I_dim_row, dimension_type I_dim_col>
class MatrixProduct
{
  public:

    using tag = matrix_product_tag;
    using elem_t = typename T_lhs::elem_t;
    constexpr static dimension_type dim_row = I_dim_row;
    constexpr static dimension_type dim_col = I_dim_col;

    MatrixProduct(const T_lhs& lhs, const T_rhs& rhs)
        : l_(lhs), r_(rhs)
    {}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        elem_t retval(0);
        for(std::size_t k(0); k<dimension_row(r_); ++k)
            retval += l_(i,k) * r_(k,j);

        return retval;
    }

    T_lhs const& l_;
    T_rhs const& r_;
};

template<typename T_mat, typename T_vec, dimension_type I_dim>
class MatrixVectorProduct
{
  public:

    static_assert(is_matrix_expression<typename T_mat::tag>::value&&
                  is_vector_expression<typename T_vec::tag>::value,
                  "in matrix_vector_product, invalid type");

    using tag = vector_expression_tag;
    using elem_t = typename T_vec::elem_t;
    constexpr static dimension_type dim = I_dim;

    MatrixVectorProduct(const T_mat& mat, const T_vec& vec)
        : l_(vec), r_(mat)
    {}

    elem_t operator[](const std::size_t i) const
    {
        elem_t retval(0);
        for(std::size_t j=0; j<dim; ++j)
            retval += r_(i, j) * l_[j];
        return retval;
    }

    T_vec const& l_; //XXX: for dimension() function!;
    T_mat const& r_;
};

template<typename T_mat, typename T_vec, dimension_type I_dim>
class VectorMatrixProduct
{
  public:

    static_assert(is_matrix_expression<typename T_mat::tag>::value&&
                  is_vector_expression<typename T_vec::tag>::value,
                  "in vector_matrix_product, invalid type");

    using tag = vector_expression_tag;
    using elem_t = typename T_vec::elem_t;
    constexpr static dimension_type dim = I_dim;

    VectorMatrixProduct(const T_vec& vec, const T_mat& mat)
        : l_(vec), r_(mat)
    {}

    elem_t operator[](const std::size_t i) const
    {
        elem_t retval(0);
        for(std::size_t j=0; j<dim; ++j)
            retval += l_[j] * r_(j, i);
        return retval;
    }

    T_vec const& l_;
    T_mat const& r_;
};

template<typename T_mat, typename T_oper, typename T_scl>
class MatrixScalarExpression
{
  public:

    using tag = matrix_expression_tag;
    using elem_t = typename T_mat::elem_t;
    constexpr static dimension_type dim_row = T_mat::dim_row;
    constexpr static dimension_type dim_col = T_mat::dim_col;

    static_assert(std::is_same<typename T_mat::elem_t, T_scl>::value,
            "type of matrix element and scalar different");
    static_assert(is_operator_struct<typename T_oper::tag>::value,
                  "invalid Expression Operator");

    MatrixScalarExpression(const T_mat& lhs, const T_scl& rhs)
        : l_(lhs), r_(rhs)
    {}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        return T_oper::apply(l_(i,j), r_);
    }

    const T_mat& l_;
    const elem_t r_;
};

template<typename T_mat>
class MatrixTranspose
{
  public:

    using tag = matrix_transpose_tag;
    using elem_t = typename T_mat::elem_t;
    constexpr static std::size_t dim_row = T_mat::dim_col;
    constexpr static std::size_t dim_col = T_mat::dim_row;

    MatrixTranspose(const T_mat& mat): l_(mat){}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        return l_(j, i);
    }

    T_mat const& l_;
};

template<template<typename T_l, typename T_r> class T_oper,
         typename T_lhs, typename T_rhs>
using matrix_operator_type =
    T_oper<typename T_lhs::elem_t, typename T_rhs::elem_t>;

template<template<typename T_l, typename T_r> class T_oper,
         typename T_mat, typename T_scl>
using matrix_scalar_operator_type = T_oper<typename T_mat::elem_t, T_scl>;

}//detail

// for static + static, dyn + dyn
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_same_dimension<T_lhs::dim_col, T_rhs::dim_col>::value&&
    is_same_dimension<T_lhs::dim_row, T_rhs::dim_row>::value>::type*& = enabler>
inline detail::MatrixExpression<T_lhs,
    detail::Add_Operator<typename T_lhs::elem_t, typename T_rhs::elem_t>,
    T_rhs, T_lhs::dim_row, T_lhs::dim_col>
operator+(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixExpression<T_lhs, detail::Add_Operator<
               typename T_lhs::elem_t, typename T_rhs::elem_t>,
               T_rhs, T_lhs::dim_row, T_lhs::dim_col>(lhs, rhs);
}

// for static + static, dyn + dyn
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_same_dimension<T_lhs::dim_col, T_rhs::dim_col>::value&&
    is_same_dimension<T_lhs::dim_row, T_rhs::dim_row>::value
    >::type*& = enabler>
inline detail::MatrixExpression<T_lhs,
    detail::Subtract_Operator<typename T_lhs::elem_t, typename T_rhs::elem_t>,
    T_rhs, T_lhs::dim_row, T_lhs::dim_col>
operator-(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixExpression<T_lhs, detail::Subtract_Operator<
               typename T_lhs::elem_t, typename T_rhs::elem_t>,
               T_rhs, T_lhs::dim_row, T_lhs::dim_col>(lhs, rhs);
}

// for (static, static) * (static, static)
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_same_dimension<T_lhs::dim_col, T_rhs::dim_row>::value&&
    is_static_dimension<T_lhs::dim_col>::value&&
    is_static_dimension<T_lhs::dim_row>::value&&
    is_static_dimension<T_rhs::dim_col>::value&&
    is_static_dimension<T_rhs::dim_row>::value
    >::type*& = enabler>
inline detail::MatrixProduct<T_lhs, T_rhs, T_lhs::dim_row, T_rhs::dim_col>
operator*(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixProduct<T_lhs, T_rhs,
               T_lhs::dim_row, T_rhs::dim_col>(lhs, rhs);
}
// for (static, static) * (static, static)
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_dynamic_dimension<T_lhs::dim_col>::value&&
    is_dynamic_dimension<T_lhs::dim_row>::value&&
    is_dynamic_dimension<T_rhs::dim_col>::value&&
    is_dynamic_dimension<T_rhs::dim_row>::value
    >::type*& = enabler>
inline detail::MatrixProduct<T_lhs, T_rhs, T_lhs::dim_row, T_rhs::dim_col>
operator*(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixProduct<T_lhs, T_rhs,
               T_lhs::dim_row, T_rhs::dim_col>(lhs, rhs);
}

// for matrix * vector
template<class T_mat, class T_vec, typename std::enable_if<
    is_matrix_expression<typename T_mat::tag>::value&&
    is_vector_expression<typename T_vec::tag>::value&&
    is_same_dimension<T_vec::dim, T_mat::dim_col>::value
    >::type*& = enabler>
inline detail::MatrixVectorProduct<T_mat, T_vec, T_mat::dim_row>
operator*(const T_mat& lhs, const T_vec& rhs)
{
    return detail::MatrixVectorProduct<T_mat, T_vec, T_mat::dim_row>(lhs, rhs);
}

// for vector * matrix
template<class T_mat, class T_vec, typename std::enable_if<
    is_matrix_expression<typename T_mat::tag>::value&&
    is_vector_expression<typename T_vec::tag>::value&&
    is_same_dimension<T_vec::dim, T_mat::dim_row>::value
    >::type*& = enabler>
inline detail::VectorMatrixProduct<T_mat, T_vec, T_mat::dim_col>
operator*(const T_vec& lhs, const T_mat& rhs)
{
    return detail::MatrixVectorProduct<T_mat, T_vec, T_mat::dim_col>(lhs, rhs);
}

//left hand side is matrix
template<class T_mat, class T_scl,
         typename std::enable_if<
             is_matrix_expression<typename T_mat::tag>::value&&
             std::is_same<typename T_mat::elem_t, T_scl>::value
             >::type*& = enabler>
inline detail::MatrixScalarExpression<T_mat,
    detail::Multiply_Operator<typename T_mat::elem_t, T_scl>, T_scl>
operator*(const T_mat& lhs, const T_scl& rhs)
{
    return detail::MatrixScalarExpression<T_mat,
        detail::Multiply_Operator<typename T_mat::elem_t, T_scl>,
        T_scl>(lhs /* = matrix*/, rhs /* = scalar*/);
}

//right hand side is matrix
template<class T_scl, class T_mat,
         typename std::enable_if<
             is_matrix_expression<typename T_mat::tag>::value&&
             std::is_same<typename T_mat::elem_t, T_scl>::value
             >::type*& = enabler>
inline detail::MatrixScalarExpression<T_mat,
    detail::Multiply_Operator<typename T_mat::elem_t, T_scl>, T_scl>
operator*(const T_scl& lhs, const T_mat& rhs)
{
    return detail::MatrixScalarExpression<T_mat,
        detail::Multiply_Operator<typename T_mat::elem_t, T_scl>,
        T_scl>(rhs /* = matrix*/, lhs /* = scalar*/);
}

template<class T_mat, class T_scl,
         typename std::enable_if<
             is_matrix_expression<typename T_mat::tag>::value&&
             std::is_same<typename T_mat::elem_t, T_scl>::value
             >::type*& = enabler>
inline detail::MatrixScalarExpression<T_mat,
    detail::Divide_Operator<typename T_mat::elem_t, T_scl>, T_scl>
operator/(const T_mat& mat, const T_scl& scl)
{
    return detail::MatrixScalarExpression<T_mat,
               detail::Divide_Operator<typename T_mat::elem_t, T_scl>,
               T_scl>(mat, scl);
}

template<class T_mat, typename std::enable_if<
         is_matrix_expression<typename T_mat::tag>::value>::type*& = enabler>
inline detail::MatrixTranspose<T_mat> transpose(const T_mat& mat)
{
    return detail::MatrixTranspose<T_mat>(mat);
}

}//ax
#endif//AX_EXPRESSION_H
<commit_msg>fix Matrix * Vector & Vector * Matrix expression<commit_after>#ifndef AX_MATRIX_EXPRESSION_H
#define AX_MATRIX_EXPRESSION_H
#include "TypeTraits.hpp"
#include "OperatorStructs.hpp"
#include "Dimension.hpp"
#include <utility>

namespace ax
{

namespace detail
{

template <typename T_lhs, typename T_oper, typename T_rhs,
          dimension_type I_dim_row, dimension_type I_dim_col>
class MatrixExpression
{
  public:

    static_assert(is_operator_struct<typename T_oper::tag>::value,
                  "invalid Expression Operator");

    using tag = matrix_expression_tag;
    using elem_t = typename T_lhs::elem_t;
    constexpr static dimension_type dim_row = I_dim_row;
    constexpr static dimension_type dim_col = I_dim_col;

    MatrixExpression(const T_lhs& lhs, const T_rhs& rhs)
        : l_(lhs), r_(rhs)
    {}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        return T_oper::apply(l_(i,j), r_(i,j));
    }

    T_lhs const& l_;
    T_rhs const& r_;
};

template <typename T_lhs, typename T_rhs,
          dimension_type I_dim_row, dimension_type I_dim_col>
class MatrixProduct
{
  public:

    using tag = matrix_product_tag;
    using elem_t = typename T_lhs::elem_t;
    constexpr static dimension_type dim_row = I_dim_row;
    constexpr static dimension_type dim_col = I_dim_col;

    MatrixProduct(const T_lhs& lhs, const T_rhs& rhs)
        : l_(lhs), r_(rhs)
    {}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        elem_t retval(0);
        for(std::size_t k(0); k<dimension_row(r_); ++k)
            retval += l_(i,k) * r_(k,j);

        return retval;
    }

    T_lhs const& l_;
    T_rhs const& r_;
};

template<typename T_mat, typename T_vec, dimension_type I_dim>
class MatrixVectorProduct
{
  public:

    static_assert(is_matrix_expression<typename T_mat::tag>::value&&
                  is_vector_expression<typename T_vec::tag>::value,
                  "in matrix_vector_product, invalid type");

    using tag = vector_expression_tag;
    using elem_t = typename T_vec::elem_t;
    constexpr static dimension_type dim = I_dim;

    MatrixVectorProduct(const T_mat& mat, const T_vec& vec)
        : l_(vec), r_(mat)
    {}

    elem_t operator[](const std::size_t i) const
    {
        elem_t retval(0);
        for(std::size_t j=0; j<dimension_col(r_); ++j)
            retval += r_(i, j) * l_[j];
        return retval;
    }

    T_vec const& l_; //XXX: for dimension() function!;
    T_mat const& r_;
};

template<typename T_mat, typename T_vec, dimension_type I_dim>
class VectorMatrixProduct
{
  public:

    static_assert(is_matrix_expression<typename T_mat::tag>::value&&
                  is_vector_expression<typename T_vec::tag>::value,
                  "in vector_matrix_product, invalid type");

    using tag = vector_expression_tag;
    using elem_t = typename T_vec::elem_t;
    constexpr static dimension_type dim = I_dim;

    VectorMatrixProduct(const T_vec& vec, const T_mat& mat)
        : l_(vec), r_(mat)
    {}

    elem_t operator[](const std::size_t i) const
    {
        elem_t retval(0);
        for(std::size_t j=0; j<dimension_row(r_); ++j)
            retval += l_[j] * r_(j, i);
        return retval;
    }

    T_vec const& l_;
    T_mat const& r_;
};

template<typename T_mat, typename T_oper, typename T_scl>
class MatrixScalarExpression
{
  public:

    using tag = matrix_expression_tag;
    using elem_t = typename T_mat::elem_t;
    constexpr static dimension_type dim_row = T_mat::dim_row;
    constexpr static dimension_type dim_col = T_mat::dim_col;

    static_assert(std::is_same<typename T_mat::elem_t, T_scl>::value,
            "type of matrix element and scalar different");
    static_assert(is_operator_struct<typename T_oper::tag>::value,
                  "invalid Expression Operator");

    MatrixScalarExpression(const T_mat& lhs, const T_scl& rhs)
        : l_(lhs), r_(rhs)
    {}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        return T_oper::apply(l_(i,j), r_);
    }

    const T_mat& l_;
    const elem_t r_;
};

template<typename T_mat>
class MatrixTranspose
{
  public:

    using tag = matrix_transpose_tag;
    using elem_t = typename T_mat::elem_t;
    constexpr static std::size_t dim_row = T_mat::dim_col;
    constexpr static std::size_t dim_col = T_mat::dim_row;

    MatrixTranspose(const T_mat& mat): l_(mat){}

    elem_t operator()(const std::size_t i, const std::size_t j) const
    {
        return l_(j, i);
    }

    T_mat const& l_;
};

template<template<typename T_l, typename T_r> class T_oper,
         typename T_lhs, typename T_rhs>
using matrix_operator_type =
    T_oper<typename T_lhs::elem_t, typename T_rhs::elem_t>;

template<template<typename T_l, typename T_r> class T_oper,
         typename T_mat, typename T_scl>
using matrix_scalar_operator_type = T_oper<typename T_mat::elem_t, T_scl>;

}//detail

// for static + static, dyn + dyn
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_same_dimension<T_lhs::dim_col, T_rhs::dim_col>::value&&
    is_same_dimension<T_lhs::dim_row, T_rhs::dim_row>::value>::type*& = enabler>
inline detail::MatrixExpression<T_lhs,
    detail::Add_Operator<typename T_lhs::elem_t, typename T_rhs::elem_t>,
    T_rhs, T_lhs::dim_row, T_lhs::dim_col>
operator+(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixExpression<T_lhs, detail::Add_Operator<
               typename T_lhs::elem_t, typename T_rhs::elem_t>,
               T_rhs, T_lhs::dim_row, T_lhs::dim_col>(lhs, rhs);
}

// for static + static, dyn + dyn
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_same_dimension<T_lhs::dim_col, T_rhs::dim_col>::value&&
    is_same_dimension<T_lhs::dim_row, T_rhs::dim_row>::value
    >::type*& = enabler>
inline detail::MatrixExpression<T_lhs,
    detail::Subtract_Operator<typename T_lhs::elem_t, typename T_rhs::elem_t>,
    T_rhs, T_lhs::dim_row, T_lhs::dim_col>
operator-(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixExpression<T_lhs, detail::Subtract_Operator<
               typename T_lhs::elem_t, typename T_rhs::elem_t>,
               T_rhs, T_lhs::dim_row, T_lhs::dim_col>(lhs, rhs);
}

// for (static, static) * (static, static)
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_same_dimension<T_lhs::dim_col, T_rhs::dim_row>::value&&
    is_static_dimension<T_lhs::dim_col>::value&&
    is_static_dimension<T_lhs::dim_row>::value&&
    is_static_dimension<T_rhs::dim_col>::value&&
    is_static_dimension<T_rhs::dim_row>::value
    >::type*& = enabler>
inline detail::MatrixProduct<T_lhs, T_rhs, T_lhs::dim_row, T_rhs::dim_col>
operator*(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixProduct<T_lhs, T_rhs,
               T_lhs::dim_row, T_rhs::dim_col>(lhs, rhs);
}
// for (static, static) * (static, static)
template<class T_lhs, class T_rhs, typename std::enable_if<
    is_matrix_expression<typename T_lhs::tag>::value&&
    is_matrix_expression<typename T_rhs::tag>::value&&
    is_dynamic_dimension<T_lhs::dim_col>::value&&
    is_dynamic_dimension<T_lhs::dim_row>::value&&
    is_dynamic_dimension<T_rhs::dim_col>::value&&
    is_dynamic_dimension<T_rhs::dim_row>::value
    >::type*& = enabler>
inline detail::MatrixProduct<T_lhs, T_rhs, T_lhs::dim_row, T_rhs::dim_col>
operator*(const T_lhs& lhs, const T_rhs& rhs)
{
    return detail::MatrixProduct<T_lhs, T_rhs,
               T_lhs::dim_row, T_rhs::dim_col>(lhs, rhs);
}

// for matrix * vector
template<class T_mat, class T_vec, typename std::enable_if<
    is_matrix_expression<typename T_mat::tag>::value&&
    is_vector_expression<typename T_vec::tag>::value&&
    is_same_dimension<T_vec::dim, T_mat::dim_col>::value
    >::type*& = enabler>
inline detail::MatrixVectorProduct<T_mat, T_vec, T_mat::dim_row>
operator*(const T_mat& lhs, const T_vec& rhs)
{
    return detail::MatrixVectorProduct<T_mat, T_vec, T_mat::dim_row>(lhs, rhs);
}

// for vector * matrix
template<class T_mat, class T_vec, typename std::enable_if<
    is_matrix_expression<typename T_mat::tag>::value&&
    is_vector_expression<typename T_vec::tag>::value&&
    is_same_dimension<T_vec::dim, T_mat::dim_row>::value
    >::type*& = enabler>
inline detail::VectorMatrixProduct<T_mat, T_vec, T_mat::dim_col>
operator*(const T_vec& lhs, const T_mat& rhs)
{
    return detail::VectorMatrixProduct<T_mat, T_vec, T_mat::dim_col>(lhs, rhs);
}

//left hand side is matrix
template<class T_mat, class T_scl,
         typename std::enable_if<
             is_matrix_expression<typename T_mat::tag>::value&&
             std::is_same<typename T_mat::elem_t, T_scl>::value
             >::type*& = enabler>
inline detail::MatrixScalarExpression<T_mat,
    detail::Multiply_Operator<typename T_mat::elem_t, T_scl>, T_scl>
operator*(const T_mat& lhs, const T_scl& rhs)
{
    return detail::MatrixScalarExpression<T_mat,
        detail::Multiply_Operator<typename T_mat::elem_t, T_scl>,
        T_scl>(lhs /* = matrix*/, rhs /* = scalar*/);
}

//right hand side is matrix
template<class T_scl, class T_mat,
         typename std::enable_if<
             is_matrix_expression<typename T_mat::tag>::value&&
             std::is_same<typename T_mat::elem_t, T_scl>::value
             >::type*& = enabler>
inline detail::MatrixScalarExpression<T_mat,
    detail::Multiply_Operator<typename T_mat::elem_t, T_scl>, T_scl>
operator*(const T_scl& lhs, const T_mat& rhs)
{
    return detail::MatrixScalarExpression<T_mat,
        detail::Multiply_Operator<typename T_mat::elem_t, T_scl>,
        T_scl>(rhs /* = matrix*/, lhs /* = scalar*/);
}

template<class T_mat, class T_scl,
         typename std::enable_if<
             is_matrix_expression<typename T_mat::tag>::value&&
             std::is_same<typename T_mat::elem_t, T_scl>::value
             >::type*& = enabler>
inline detail::MatrixScalarExpression<T_mat,
    detail::Divide_Operator<typename T_mat::elem_t, T_scl>, T_scl>
operator/(const T_mat& mat, const T_scl& scl)
{
    return detail::MatrixScalarExpression<T_mat,
               detail::Divide_Operator<typename T_mat::elem_t, T_scl>,
               T_scl>(mat, scl);
}

template<class T_mat, typename std::enable_if<
         is_matrix_expression<typename T_mat::tag>::value>::type*& = enabler>
inline detail::MatrixTranspose<T_mat> transpose(const T_mat& mat)
{
    return detail::MatrixTranspose<T_mat>(mat);
}

}//ax
#endif//AX_EXPRESSION_H
<|endoftext|>


<commit_before>#include "generated.hpp"
#include "impl_test_interface.hpp"
#include <boost/asio/ip/tcp.hpp>
#include <boost/test/unit_test.hpp>
#include <silicium/error_or.hpp>
#include <warpcoil/beast.hpp>
#include <warpcoil/beast_push_warnings.hpp>
#include <beast/websocket/stream.hpp>
#include <warpcoil/pop_warnings.hpp>
#include "checkpoint.hpp"

BOOST_AUTO_TEST_CASE(websocket_error)
{
    // make sure that these strings are stable
    {
        boost::system::error_code const ec =
            warpcoil::beast::make_error_code(warpcoil::beast::websocket_error::unexpected_opcode);
        BOOST_CHECK_EQUAL("websocket_error", std::string(ec.category().name()));
        BOOST_CHECK_EQUAL("unexpected_opcode", ec.message());
    }
    {
        boost::system::error_code const ec = warpcoil::beast::make_error_code(warpcoil::beast::websocket_error::close);
        BOOST_CHECK_EQUAL("websocket_error", std::string(ec.category().name()));
        BOOST_CHECK_EQUAL("close", ec.message());
    }
}

BOOST_AUTO_TEST_CASE(websocket)
{
    using namespace boost::asio;
    io_service io;

    warpcoil::checkpoint tcp_accepted;
    warpcoil::checkpoint websocket_accepted;
    warpcoil::checkpoint served;
    warpcoil::checkpoint tcp_connected;
    warpcoil::checkpoint websocket_connected;
    warpcoil::checkpoint received_response;

    ip::tcp::acceptor acceptor(io, ip::tcp::endpoint(ip::tcp::v6(), 0), true);
    acceptor.listen();
    ip::tcp::socket accepted_socket(io);
    warpcoil::impl_test_interface server_impl;
    acceptor.async_accept(
        accepted_socket, [&](boost::system::error_code ec)
        {
            tcp_accepted.enter();
            websocket_connected.enable();
            Si::throw_if_error(ec);
            typedef beast::websocket::stream<ip::tcp::socket &> websocket;
            auto session = std::make_shared<warpcoil::beast::async_stream_adaptor<websocket>>(
                websocket(accepted_socket), beast::streambuf());
            session->next_layer().async_accept(
                [session, &server_impl, &websocket_accepted, &served, &received_response](boost::system::error_code ec)
                {
                    websocket_accepted.enter();
                    received_response.enable();
                    Si::throw_if_error(ec);
                    auto splitter = std::make_shared<warpcoil::cpp::message_splitter<decltype(*session)>>(*session);
                    auto writer = std::make_shared<warpcoil::cpp::buffered_writer<decltype(*session)>>(*session);
                    auto server = std::make_shared<
                        async_test_interface_server<decltype(server_impl), decltype(*session), decltype(*session)>>(
                        server_impl, *splitter, *writer);
                    server->serve_one_request([server, session, splitter, writer, &served](boost::system::error_code ec)
                                              {
                                                  served.enter();
                                                  Si::throw_if_error(ec);
                                              });
                });
        });

    ip::tcp::socket connecting_socket(io);
    connecting_socket.async_connect(
        ip::tcp::endpoint(ip::address_v4::loopback(), acceptor.local_endpoint().port()),
        [&](boost::system::error_code ec)
        {
            tcp_connected.enter();
            websocket_accepted.enable();
            Si::throw_if_error(ec);
            typedef beast::websocket::stream<ip::tcp::socket &> websocket;
            auto session = std::make_shared<warpcoil::beast::async_stream_adaptor<websocket>>(
                websocket(connecting_socket), beast::streambuf());
            session->next_layer().async_handshake(
                "localhost", "/",
                [session, &websocket_connected, &received_response, &served](boost::system::error_code ec)
                {
                    websocket_connected.enter();
                    served.enable();
                    Si::throw_if_error(ec);
                    auto splitter = std::make_shared<warpcoil::cpp::message_splitter<decltype(*session)>>(*session);
                    auto writer = std::make_shared<warpcoil::cpp::buffered_writer<decltype(*session)>>(*session);
                    auto client = std::make_shared<async_test_interface_client<decltype(*session), decltype(*session)>>(
                        *writer, *splitter);
                    client->utf8("Alice", [client, writer, splitter, session,
                                           &received_response](Si::error_or<std::string> result)
                                 {
                                     received_response.enter();
                                     BOOST_CHECK_EQUAL("Alice123", result.get());
                                 });
                });
        });

    tcp_accepted.enable();
    tcp_connected.enable();
    io.run();
}
<commit_msg>disable test that takes minutes to compile on VC++ for now<commit_after>#include "generated.hpp"
#include "impl_test_interface.hpp"
#include <boost/asio/ip/tcp.hpp>
#include <boost/test/unit_test.hpp>
#include <silicium/error_or.hpp>
#include <warpcoil/beast.hpp>
#include <warpcoil/beast_push_warnings.hpp>
#include <beast/websocket/stream.hpp>
#include <warpcoil/pop_warnings.hpp>
#include "checkpoint.hpp"

BOOST_AUTO_TEST_CASE(websocket_error)
{
    // make sure that these strings are stable
    {
        boost::system::error_code const ec =
            warpcoil::beast::make_error_code(warpcoil::beast::websocket_error::unexpected_opcode);
        BOOST_CHECK_EQUAL("websocket_error", std::string(ec.category().name()));
        BOOST_CHECK_EQUAL("unexpected_opcode", ec.message());
    }
    {
        boost::system::error_code const ec = warpcoil::beast::make_error_code(warpcoil::beast::websocket_error::close);
        BOOST_CHECK_EQUAL("websocket_error", std::string(ec.category().name()));
        BOOST_CHECK_EQUAL("close", ec.message());
    }
}

#ifndef _MSC_VER
// serve_one_request in the test below takes minutes to compile with Visual C++ 2015 Update 3 for an unknown reason.
BOOST_AUTO_TEST_CASE(websocket)
{
    using namespace boost::asio;
    io_service io;

    warpcoil::checkpoint tcp_accepted;
    warpcoil::checkpoint websocket_accepted;
    warpcoil::checkpoint served;
    warpcoil::checkpoint tcp_connected;
    warpcoil::checkpoint websocket_connected;
    warpcoil::checkpoint received_response;

    ip::tcp::acceptor acceptor(io, ip::tcp::endpoint(ip::tcp::v6(), 0), true);
    acceptor.listen();
    ip::tcp::socket accepted_socket(io);
    warpcoil::impl_test_interface server_impl;
    acceptor.async_accept(
        accepted_socket, [&](boost::system::error_code ec)
        {
            tcp_accepted.enter();
            websocket_connected.enable();
            Si::throw_if_error(ec);
            typedef beast::websocket::stream<ip::tcp::socket &> websocket;
            auto session = std::make_shared<warpcoil::beast::async_stream_adaptor<websocket>>(
                websocket(accepted_socket), beast::streambuf());
            session->next_layer().async_accept(
                [session, &server_impl, &websocket_accepted, &served, &received_response](boost::system::error_code ec)
                {
                    websocket_accepted.enter();
                    received_response.enable();
                    Si::throw_if_error(ec);
                    auto splitter = std::make_shared<warpcoil::cpp::message_splitter<decltype(*session)>>(*session);
                    auto writer = std::make_shared<warpcoil::cpp::buffered_writer<decltype(*session)>>(*session);
                    auto server = std::make_shared<
                        async_test_interface_server<decltype(server_impl), decltype(*session), decltype(*session)>>(
                        server_impl, *splitter, *writer);
                    server->serve_one_request([server, session, splitter, writer, &served](boost::system::error_code ec)
                                              {
                                                  served.enter();
                                                  Si::throw_if_error(ec);
                                              });
                });
        });

    ip::tcp::socket connecting_socket(io);
    connecting_socket.async_connect(
        ip::tcp::endpoint(ip::address_v4::loopback(), acceptor.local_endpoint().port()),
        [&](boost::system::error_code ec)
        {
            tcp_connected.enter();
            websocket_accepted.enable();
            Si::throw_if_error(ec);
            typedef beast::websocket::stream<ip::tcp::socket &> websocket;
            auto session = std::make_shared<warpcoil::beast::async_stream_adaptor<websocket>>(
                websocket(connecting_socket), beast::streambuf());
            session->next_layer().async_handshake(
                "localhost", "/",
                [session, &websocket_connected, &received_response, &served](boost::system::error_code ec)
                {
                    websocket_connected.enter();
                    served.enable();
                    Si::throw_if_error(ec);
                    auto splitter = std::make_shared<warpcoil::cpp::message_splitter<decltype(*session)>>(*session);
                    auto writer = std::make_shared<warpcoil::cpp::buffered_writer<decltype(*session)>>(*session);
                    auto client = std::make_shared<async_test_interface_client<decltype(*session), decltype(*session)>>(
                        *writer, *splitter);
                    client->utf8("Alice", [client, writer, splitter, session,
                                           &received_response](Si::error_or<std::string> result)
                                 {
                                     received_response.enter();
                                     BOOST_CHECK_EQUAL("Alice123", result.get());
                                 });
                });
        });

    tcp_accepted.enable();
    tcp_connected.enable();
    io.run();
}
#endif
<|endoftext|>


<commit_before>#include "game_manager.h"
#include "../hmi/hmi_manager.h"

#include "poweroff_screen.h"
#include "wait_players_screen.h"
#include "test_hardware_screen.h"
#include "playing_screen.h"
#include "scores_screen.h"

GameManager game;

static struct {
	PoweroffScreen poweroff;
	WaitPlayersScreen wait_players;
	TestHardwareScreen test_hardware;
	PlayingScreen playing;
	ScoresScreen scores;
} screens;

static GameScreen *scr = 0;

GameManager::GameManager() : state(GameState_WAIT_PLAYERS) {
	scr = &screens.poweroff;
	sleeptimer.set_duration(1000.f * 60 * 5);
	sleeptimer.start();
}

void GameManager::init() {
	scr = &screens.poweroff;
	scr->init();
}

void GameManager::animate() {
	scr->animate();
	if (hmi.btn_power.slpressed())
		init();
	if (hmi.btn1.touched(true) || hmi.btn2.touched(true))
		sleeptimer.start(); // Restart
	sleeptimer.animate();
	if (sleeptimer.get_value() == 1)
		hmi.alim.poweroff();
}

void GameManager::restart_game() {
	data.p1score = 0;
	data.p2score = 0;
	play();
}

void GameManager::play() {
	scr = &screens.playing;
	scr->init();
}

void GameManager::initscreen() {
	scr = &screens.wait_players;
	scr->init();
}

void GameManager::show_scores() {
	scr = &screens.scores;
	scr->init();
}

void GameManager::test_hardware() {
	scr = &screens.test_hardware;
	scr->init();
}
<commit_msg>Retour à l'écran d'attente si aucune action en 1 minute<commit_after>#include "game_manager.h"
#include "../hmi/hmi_manager.h"

#include "poweroff_screen.h"
#include "wait_players_screen.h"
#include "test_hardware_screen.h"
#include "playing_screen.h"
#include "scores_screen.h"

GameManager game;

static struct {
	PoweroffScreen poweroff;
	WaitPlayersScreen wait_players;
	TestHardwareScreen test_hardware;
	PlayingScreen playing;
	ScoresScreen scores;
} screens;

static GameScreen *scr = 0;

GameManager::GameManager() : state(GameState_WAIT_PLAYERS) {
	scr = &screens.poweroff;
	sleeptimer.set_duration(1000.f * 60);
	sleeptimer.start();
}

void GameManager::init() {
	scr = &screens.poweroff;
	scr->init();
}

void GameManager::animate() {
	scr->animate();
	if (hmi.btn_power.slpressed())
		init();
	if (hmi.btn1.touched(true) || hmi.btn2.touched(true))
		sleeptimer.start(); // Restart
	sleeptimer.animate();
	if (sleeptimer.get_value() == 1 && scr != &screens.wait_players)
		initscreen();
}

void GameManager::restart_game() {
	data.p1score = 0;
	data.p2score = 0;
	play();
}

void GameManager::play() {
	scr = &screens.playing;
	scr->init();
}

void GameManager::initscreen() {
	scr = &screens.wait_players;
	scr->init();
}

void GameManager::show_scores() {
	scr = &screens.scores;
	scr->init();
}

void GameManager::test_hardware() {
	scr = &screens.test_hardware;
	scr->init();
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//  suffix_tree.hpp
//
// Suffix tree implementation including Ukkonen's linear time construction algorithm
//

#ifndef structures_suffix_tree_hpp
#define structures_suffix_tree_hpp

#include <unordered_map>
#include <list>
#include <vector>
#include <cstdint>

namespace structures {

using namespace std;

/**
 * An implementation of a suffix tree with linear time and space complexity for construction.
 */
class SuffixTree {

public:
    /// Linear time constructor.
    ///
    /// Note: string cannot have null characters, but this is not checked.
    SuffixTree(string::const_iterator begin, string::const_iterator end);
    ~SuffixTree() = default;

    /// Returns the length of the longest prefix of str that exactly matches
    /// a suffix of the string used to construct the suffix tree.
    ///
    /// Note: string cannot have null characters, but this is not checked.
    size_t longest_overlap(const string& str);

    /// Same semantics as previous
    size_t longest_overlap(string::const_iterator begin, string::const_iterator end);

    /// Retuns a vector of all of the indices where a string occurs as a substring
    /// of the string used to construct the suffix tree. Indices are ordered arbitrarily.
    ///
    /// Note: string cannot have null characters, but this is not checked.
    vector<size_t> substring_locations(const string& str);
    vector<size_t> substring_locations(string::const_iterator begin, string::const_iterator end);

    /// Beginning of string used to make tree
    const string::const_iterator begin;

    /// End of string used to make tree
    const string::const_iterator end;

private:
    struct STNode;

    /// All nodes in the tree (in a list to avoid difficulties with pointers and reallocations)
    list<STNode> nodes;

    /// The edges from the root node
    unordered_map<char, STNode*> root;

    /// Returns a char of the string or null char at past-the-last index
    inline char get_char(size_t i);
};

/**
 * A node of a suffix tree corresponding a substring of the string
 */
struct SuffixTree::STNode {
    /// Constructor
    STNode(int64_t first, int64_t last);
    ~STNode() = default;

    /// Edges down the tree
    unordered_map<char, STNode*> children;

    /// First index of string on this node
    int64_t first;
    /// Last index of string on this node, inclusive (-1 indicates end sentinel during consruction)
    int64_t last;

    /// The length of the the node during a phase of construction
    inline int64_t length(int64_t phase) {
        return last >= 0 ? last - first + 1 : phase - first + 1;
    }

    /// The last index contained on the this node during a phase of construction
    inline int64_t final_index(int64_t phase) {
        return last >= 0 ? last - first : phase - first;
    }
};

inline char SuffixTree::get_char(size_t i) {
    return i == end - begin ? '\0' : *(begin + i);
}

}

#endif /* structures_suffix_tree_hpp */
<commit_msg>Add an include that Clang reqires<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//  suffix_tree.hpp
//
// Suffix tree implementation including Ukkonen's linear time construction algorithm
//

#ifndef structures_suffix_tree_hpp
#define structures_suffix_tree_hpp

#include <unordered_map>
#include <list>
#include <vector>
#include <cstdint>
#include <string>

namespace structures {

using namespace std;

/**
 * An implementation of a suffix tree with linear time and space complexity for construction.
 */
class SuffixTree {

public:
    /// Linear time constructor.
    ///
    /// Note: string cannot have null characters, but this is not checked.
    SuffixTree(string::const_iterator begin, string::const_iterator end);
    ~SuffixTree() = default;

    /// Returns the length of the longest prefix of str that exactly matches
    /// a suffix of the string used to construct the suffix tree.
    ///
    /// Note: string cannot have null characters, but this is not checked.
    size_t longest_overlap(const string& str);

    /// Same semantics as previous
    size_t longest_overlap(string::const_iterator begin, string::const_iterator end);

    /// Retuns a vector of all of the indices where a string occurs as a substring
    /// of the string used to construct the suffix tree. Indices are ordered arbitrarily.
    ///
    /// Note: string cannot have null characters, but this is not checked.
    vector<size_t> substring_locations(const string& str);
    vector<size_t> substring_locations(string::const_iterator begin, string::const_iterator end);

    /// Beginning of string used to make tree
    const string::const_iterator begin;

    /// End of string used to make tree
    const string::const_iterator end;

private:
    struct STNode;

    /// All nodes in the tree (in a list to avoid difficulties with pointers and reallocations)
    list<STNode> nodes;

    /// The edges from the root node
    unordered_map<char, STNode*> root;

    /// Returns a char of the string or null char at past-the-last index
    inline char get_char(size_t i);
};

/**
 * A node of a suffix tree corresponding a substring of the string
 */
struct SuffixTree::STNode {
    /// Constructor
    STNode(int64_t first, int64_t last);
    ~STNode() = default;

    /// Edges down the tree
    unordered_map<char, STNode*> children;

    /// First index of string on this node
    int64_t first;
    /// Last index of string on this node, inclusive (-1 indicates end sentinel during consruction)
    int64_t last;

    /// The length of the the node during a phase of construction
    inline int64_t length(int64_t phase) {
        return last >= 0 ? last - first + 1 : phase - first + 1;
    }

    /// The last index contained on the this node during a phase of construction
    inline int64_t final_index(int64_t phase) {
        return last >= 0 ? last - first : phase - first;
    }
};

inline char SuffixTree::get_char(size_t i) {
    return i == end - begin ? '\0' : *(begin + i);
}

}

#endif /* structures_suffix_tree_hpp */
<|endoftext|>