<commit_before>
#include "ksp_plugin/plugin.hpp"

#include <cmath>
#include <map>
#include <memory>

#include "geometry/permutation.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "physics/mock_n_body_system.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/death_message.hpp"
#include "testing_utilities/numerics.hpp"
#include "testing_utilities/solar_system.hpp"

using principia::geometry::Bivector;
using principia::geometry::Permutation;
using principia::physics::MockNBodySystem;
using principia::quantities::Abs;
using principia::quantities::Sqrt;
using principia::si::Day;
using principia::si::Radian;
using principia::si::AstronomicalUnit;
using principia::testing_utilities::AbsoluteError;
using principia::testing_utilities::RelativeError;
using principia::testing_utilities::AlmostEquals;
using principia::testing_utilities::DeathMessage;
using principia::testing_utilities::ICRFJ2000Ecliptic;
using principia::testing_utilities::SolarSystem;
using testing::AllOf;
using testing::Eq;
using testing::Ge;
using testing::Gt;
using testing::InSequence;
using testing::Lt;
using testing::Ref;
using testing::SizeIs;
using testing::StrictMock;
using testing::_;

namespace principia {
namespace ksp_plugin {

namespace {

// Appends a |DegreesOfFreedom| equal to the last one at the given |time| to
// each |Trajectory| in the |k|th parameter of the expected call.
// |T| must be |NBodySystem<>::Trajectories|, |time| must be an |Instant|.
ACTION_TEMPLATE(AppendTimeToTrajectories,
                HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
                AND_1_VALUE_PARAMS(time)) {
  for (auto* trajectory : T(std::tr1::get<k>(args))) {
    trajectory->Append(time,
                       {trajectory->last_position(),
                        trajectory->last_velocity()});
  }
}

}  // namespace

class TestablePlugin : public Plugin {
 public:
  // Takes ownership of |n_body_system|.
  // TODO(phl): We'd like to pass a |unique_ptr<>| but that seems to confuse
  // gMock.
  TestablePlugin(Instant const& initial_time,
                 Index const sun_index,
                 GravitationalParameter const& sun_gravitational_parameter,
                 Angle const& planetarium_rotation,
                 MockNBodySystem<Barycentre>* n_body_system)
      : Plugin(initial_time,
               sun_index,
               sun_gravitational_parameter,
               planetarium_rotation) {
    n_body_system_.reset(n_body_system);
  }

  Time const& Δt() const {
    return Δt_;
  }

  SPRKIntegrator<Length, Speed> const& prolongation_integrator() const {
    return prolongation_integrator_;
  }

  SPRKIntegrator<Length, Speed> const& history_integrator() const {
    return history_integrator_;
  }
};

class PluginTest : public testing::Test {
 protected:
  PluginTest()
      : looking_glass_(Permutation<ICRFJ2000Ecliptic, AliceSun>::XZY),
        solar_system_(SolarSystem::AtСпутник1Launch(
            SolarSystem::Accuracy::kMajorBodiesOnly)),
        bodies_(solar_system_->massive_bodies()),
        initial_time_(solar_system_->trajectories().front()->last_time()),
        sun_gravitational_parameter_(
            bodies_[SolarSystem::kSun]->gravitational_parameter()),
        planetarium_rotation_(1 * Radian) {
  satellite_initial_displacement_ =
      Displacement<AliceSun>({3111.0 * Kilo(Metre),
                              4400.0 * Kilo(Metre),
                              3810.0 * Kilo(Metre)});
  auto const tangent =
      satellite_initial_displacement_ * Bivector<double, AliceSun>({1, 2, 3});
  Vector<double, AliceSun> unit_tangent = tangent / tangent.Norm();
  EXPECT_THAT(
      InnerProduct(unit_tangent,
                   satellite_initial_displacement_ /
                       satellite_initial_displacement_.Norm()),
      Eq(0));
  // This yields a circular orbit.
  satellite_initial_velocity_ =
      Sqrt(bodies_[SolarSystem::kEarth]->gravitational_parameter() /
               satellite_initial_displacement_.Norm()) * unit_tangent;

    n_body_system_ = new MockNBodySystem<Barycentre>();
    plugin_ = std::make_unique<StrictMock<TestablePlugin>>(
                  initial_time_,
                  SolarSystem::kSun,
                  sun_gravitational_parameter_,
                  planetarium_rotation_,
                  n_body_system_);
  }

  void InsertAllSolarSystemBodies() {
    for (std::size_t index = SolarSystem::kSun + 1;
         index < bodies_.size();
         ++index) {
      Index const parent_index = SolarSystem::parent(index);
      Displacement<AliceSun> const from_parent_position = looking_glass_(
          solar_system_->trajectories()[index]->last_position() -
          solar_system_->trajectories()[parent_index]->last_position());
      Velocity<AliceSun> const from_parent_velocity = looking_glass_(
          solar_system_->trajectories()[index]->last_velocity() -
          solar_system_->trajectories()[parent_index]->last_velocity());
      plugin_->InsertCelestial(index,
                               bodies_[index]->gravitational_parameter(),
                               parent_index,
                               from_parent_position,
                               from_parent_velocity);
    }
  }

  Permutation<ICRFJ2000Ecliptic, AliceSun> looking_glass_;
  MockNBodySystem<Barycentre>* n_body_system_;  // Not owned.
  std::unique_ptr<SolarSystem> solar_system_;
  SolarSystem::Bodies bodies_;
  Instant initial_time_;
  GravitationalParameter sun_gravitational_parameter_;
  Angle planetarium_rotation_;

  std::unique_ptr<StrictMock<TestablePlugin>> plugin_;

  // These initial conditions will yield a low circular orbit around Earth.
  Displacement<AliceSun> satellite_initial_displacement_;
  Velocity<AliceSun> satellite_initial_velocity_;
};

TEST_F(PluginTest, Initialization) {
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  for (std::size_t index = SolarSystem::kSun + 1;
       index < bodies_.size();
       ++index) {
    Index const parent_index = SolarSystem::parent(index);
    EXPECT_THAT(solar_system_->trajectories()[index]->last_position() -
                solar_system_->trajectories()[parent_index]->last_position(),
                AlmostEquals(looking_glass_.Inverse()(
                    plugin_->CelestialDisplacementFromParent(index)),
                    250000));
    EXPECT_THAT(solar_system_->trajectories()[index]->last_velocity() -
                solar_system_->trajectories()[parent_index]->last_velocity(),
                AlmostEquals(looking_glass_.Inverse()(
                    plugin_->CelestialParentRelativeVelocity(index)),
                    1000));
  }
}

TEST_F(PluginTest, InsertCelestialError) {
  Displacement<AliceSun> const from_parent_position = looking_glass_(
      solar_system_->trajectories().front()->last_position() -
      solar_system_->trajectories().front()->last_position());
  Velocity<AliceSun> const from_parent_velocity = looking_glass_(
      solar_system_->trajectories().front()->last_velocity() -
      solar_system_->trajectories().front()->last_velocity());
  EXPECT_DEATH({
    InsertAllSolarSystemBodies();
    plugin_->EndInitialization();
    plugin_->InsertCelestial(42,
                             bodies_.front()->gravitational_parameter(),
                             SolarSystem::kSun,
                             from_parent_position,
                             from_parent_velocity);
  }, DeathMessage("before the end of initialization"));
  EXPECT_DEATH({
    InsertAllSolarSystemBodies();
    plugin_->InsertCelestial(42,
                             bodies_.front()->gravitational_parameter(),
                             1729,
                             from_parent_position,
                             from_parent_velocity);
  }, DeathMessage("No body at index"));
  EXPECT_DEATH({
    InsertAllSolarSystemBodies();
    plugin_->InsertCelestial(SolarSystem::kEarth,
                             bodies_.front()->gravitational_parameter(),
                             SolarSystem::kSun,
                             from_parent_position,
                             from_parent_velocity);
  }, DeathMessage("Body already exists"));
}

TEST_F(PluginTest, VesselInsertionAtInitialization) {
  GUID const guid = "Test Satellite";
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  bool const inserted = plugin_->InsertOrKeepVessel(guid,
                                                    SolarSystem::kEarth);
  EXPECT_TRUE(inserted);
  plugin_->SetVesselStateOffset(guid,
                                satellite_initial_displacement_,
                                satellite_initial_velocity_);
  EXPECT_THAT(
      AbsoluteError(plugin_->VesselDisplacementFromParent(guid),
                    satellite_initial_displacement_),
      Lt(DBL_EPSILON * AstronomicalUnit));
  EXPECT_THAT(plugin_->VesselParentRelativeVelocity(guid),
              AlmostEquals(satellite_initial_velocity_));
}

// Checks that the plugin correctly uses its 10-second-step history even when
// advanced with smaller timesteps.
TEST_F(PluginTest, AdvanceTimeWithCelestialsOnly) {
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  Time const δt = 0.02 * Second;
  Angle const planetarium_rotation = 42 * Radian;
  auto history_step = [this](int const i) {
    return initial_time_ + i * plugin_->Δt();
  };
  for (int i = 0; i < 10; ++i) {
    for (Instant t = history_step(i) + δt; t <= history_step(i + 1); t += δt) {
      EXPECT_CALL(*n_body_system_,
                  Integrate(Ref(plugin_->prolongation_integrator()), t,
                            plugin_->Δt(), 0, true, SizeIs(bodies_.size())))
          .RetiresOnSaturation();
      plugin_->AdvanceTime(t, planetarium_rotation);
    }
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->history_integrator()),
                          history_step(i + 1) + δt,
                          plugin_->Δt(), 0, false,
                          SizeIs(bodies_.size())))
        .WillOnce(
             AppendTimeToTrajectories<5, NBodySystem<Barycentre>::Trajectories>(
                 history_step(i + 1)))
        .RetiresOnSaturation();
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->prolongation_integrator()),
                          history_step(i + 1) + δt, plugin_->Δt(), 0, true,
                          SizeIs(bodies_.size())))
        .RetiresOnSaturation();
    plugin_->AdvanceTime(history_step(i + 1) + δt, planetarium_rotation);
  }
}

// Checks that the plugin correctly advances the history of newly inserted
// vessels with the prolongation integrator (using small steps), then switches
// to the history integrator.
TEST_F(PluginTest, AdvanceTimeWithVessels) {
  // Inserted at |initial_time|.
  GUID const enterprise = "NCC-1701";
  // Inserted after |initial_time|, but before the histories are first advanced.
  GUID const enterprise_d = "NCC-1701-D";
  // Inserted after the histories are first advanced, at a timestep where the
  // histories are not advanced further.
  GUID const stargazer = "NCC-2893";
  // Inserted just after the histories are advanced.
  GUID const constantinople = "NCC-43622";
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  Time const δt = 0.02 * Second;
  Angle const planetarium_rotation = 42 * Radian;
  std::size_t expected_number_of_new_vessels = 0U;
  auto history_step = [this](int const i) {
    return initial_time_ + i * plugin_->Δt();
  };
  auto insert_vessel =
      [this, &expected_number_of_new_vessels](GUID const guid) {
        bool const inserted = plugin_->InsertOrKeepVessel(guid,
                                                          SolarSystem::kEarth);
        EXPECT_TRUE(inserted);
        plugin_->SetVesselStateOffset(guid,
                                      satellite_initial_displacement_,
                                      satellite_initial_velocity_);
        ++expected_number_of_new_vessels;
      };
  insert_vessel(enterprise);
  for (int i = 0; i < 10; ++i) {
    for (Instant t = history_step(i) + δt; t <= history_step(i + 1); t += δt) {
      EXPECT_CALL(*n_body_system_,
                  Integrate(Ref(plugin_->prolongation_integrator()), t,
                            plugin_->Δt(), 0, true, SizeIs(bodies_.size())))
          .RetiresOnSaturation();
      plugin_->AdvanceTime(t, planetarium_rotation);
    }
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->history_integrator()),
                          history_step(i + 1) + δt,
                          plugin_->Δt(), 0, false,
                          SizeIs(bodies_.size())))
        .WillOnce(
             AppendTimeToTrajectories<5, NBodySystem<Barycentre>::Trajectories>(
                 history_step(i + 1)))
        .RetiresOnSaturation();
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->prolongation_integrator()),
                          history_step(i + 1) + δt, plugin_->Δt(), 0, true,
                          SizeIs(bodies_.size())))
        .RetiresOnSaturation();
    plugin_->AdvanceTime(history_step(i + 1) + δt, planetarium_rotation);
  }
}

}  // namespace ksp_plugin
}  // namespace principia
<commit_msg>The old vessels and the new<commit_after>
#include "ksp_plugin/plugin.hpp"

#include <cmath>
#include <map>
#include <memory>

#include "geometry/permutation.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "physics/mock_n_body_system.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/death_message.hpp"
#include "testing_utilities/numerics.hpp"
#include "testing_utilities/solar_system.hpp"

using principia::geometry::Bivector;
using principia::geometry::Permutation;
using principia::physics::MockNBodySystem;
using principia::quantities::Abs;
using principia::quantities::Sqrt;
using principia::si::Day;
using principia::si::Radian;
using principia::si::AstronomicalUnit;
using principia::testing_utilities::AbsoluteError;
using principia::testing_utilities::RelativeError;
using principia::testing_utilities::AlmostEquals;
using principia::testing_utilities::DeathMessage;
using principia::testing_utilities::ICRFJ2000Ecliptic;
using principia::testing_utilities::SolarSystem;
using testing::AllOf;
using testing::Eq;
using testing::Ge;
using testing::Gt;
using testing::InSequence;
using testing::Lt;
using testing::Ref;
using testing::SizeIs;
using testing::StrictMock;
using testing::_;

namespace principia {
namespace ksp_plugin {

namespace {

// Appends a |DegreesOfFreedom| equal to the last one at the given |time| to
// each |Trajectory| in the |k|th parameter of the expected call.
// This parameter must be an |NBodySystem<Barycentre>::Trajectories|, |time|
// must be an |Instant|.
ACTION_TEMPLATE(AppendTimeToTrajectories,
                HAS_1_TEMPLATE_PARAMS(int, k),
                AND_1_VALUE_PARAMS(time)) {
  for (auto* trajectory :static_cast<NBodySystem<Barycentre>::Trajectories>(
                             std::tr1::get<k>(args))) {
    trajectory->Append(time,
                       {trajectory->last_position(),
                        trajectory->last_velocity()});
  }
}

}  // namespace

class TestablePlugin : public Plugin {
 public:
  // Takes ownership of |n_body_system|.
  // TODO(phl): We'd like to pass a |unique_ptr<>| but that seems to confuse
  // gMock.
  TestablePlugin(Instant const& initial_time,
                 Index const sun_index,
                 GravitationalParameter const& sun_gravitational_parameter,
                 Angle const& planetarium_rotation,
                 MockNBodySystem<Barycentre>* n_body_system)
      : Plugin(initial_time,
               sun_index,
               sun_gravitational_parameter,
               planetarium_rotation) {
    n_body_system_.reset(n_body_system);
  }

  Time const& Δt() const {
    return Δt_;
  }

  SPRKIntegrator<Length, Speed> const& prolongation_integrator() const {
    return prolongation_integrator_;
  }

  SPRKIntegrator<Length, Speed> const& history_integrator() const {
    return history_integrator_;
  }
};

class PluginTest : public testing::Test {
 protected:
  PluginTest()
      : looking_glass_(Permutation<ICRFJ2000Ecliptic, AliceSun>::XZY),
        solar_system_(SolarSystem::AtСпутник1Launch(
            SolarSystem::Accuracy::kMajorBodiesOnly)),
        bodies_(solar_system_->massive_bodies()),
        initial_time_(solar_system_->trajectories().front()->last_time()),
        sun_gravitational_parameter_(
            bodies_[SolarSystem::kSun]->gravitational_parameter()),
        planetarium_rotation_(1 * Radian) {
  satellite_initial_displacement_ =
      Displacement<AliceSun>({3111.0 * Kilo(Metre),
                              4400.0 * Kilo(Metre),
                              3810.0 * Kilo(Metre)});
  auto const tangent =
      satellite_initial_displacement_ * Bivector<double, AliceSun>({1, 2, 3});
  Vector<double, AliceSun> unit_tangent = tangent / tangent.Norm();
  EXPECT_THAT(
      InnerProduct(unit_tangent,
                   satellite_initial_displacement_ /
                       satellite_initial_displacement_.Norm()),
      Eq(0));
  // This yields a circular orbit.
  satellite_initial_velocity_ =
      Sqrt(bodies_[SolarSystem::kEarth]->gravitational_parameter() /
               satellite_initial_displacement_.Norm()) * unit_tangent;

    n_body_system_ = new MockNBodySystem<Barycentre>();
    plugin_ = std::make_unique<StrictMock<TestablePlugin>>(
                  initial_time_,
                  SolarSystem::kSun,
                  sun_gravitational_parameter_,
                  planetarium_rotation_,
                  n_body_system_);
  }

  void InsertAllSolarSystemBodies() {
    for (std::size_t index = SolarSystem::kSun + 1;
         index < bodies_.size();
         ++index) {
      Index const parent_index = SolarSystem::parent(index);
      Displacement<AliceSun> const from_parent_position = looking_glass_(
          solar_system_->trajectories()[index]->last_position() -
          solar_system_->trajectories()[parent_index]->last_position());
      Velocity<AliceSun> const from_parent_velocity = looking_glass_(
          solar_system_->trajectories()[index]->last_velocity() -
          solar_system_->trajectories()[parent_index]->last_velocity());
      plugin_->InsertCelestial(index,
                               bodies_[index]->gravitational_parameter(),
                               parent_index,
                               from_parent_position,
                               from_parent_velocity);
    }
  }

  Permutation<ICRFJ2000Ecliptic, AliceSun> looking_glass_;
  MockNBodySystem<Barycentre>* n_body_system_;  // Not owned.
  std::unique_ptr<SolarSystem> solar_system_;
  SolarSystem::Bodies bodies_;
  Instant initial_time_;
  GravitationalParameter sun_gravitational_parameter_;
  Angle planetarium_rotation_;

  std::unique_ptr<StrictMock<TestablePlugin>> plugin_;

  // These initial conditions will yield a low circular orbit around Earth.
  Displacement<AliceSun> satellite_initial_displacement_;
  Velocity<AliceSun> satellite_initial_velocity_;
};

TEST_F(PluginTest, Initialization) {
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  for (std::size_t index = SolarSystem::kSun + 1;
       index < bodies_.size();
       ++index) {
    Index const parent_index = SolarSystem::parent(index);
    EXPECT_THAT(solar_system_->trajectories()[index]->last_position() -
                solar_system_->trajectories()[parent_index]->last_position(),
                AlmostEquals(looking_glass_.Inverse()(
                    plugin_->CelestialDisplacementFromParent(index)),
                    250000));
    EXPECT_THAT(solar_system_->trajectories()[index]->last_velocity() -
                solar_system_->trajectories()[parent_index]->last_velocity(),
                AlmostEquals(looking_glass_.Inverse()(
                    plugin_->CelestialParentRelativeVelocity(index)),
                    1000));
  }
}

TEST_F(PluginTest, InsertCelestialError) {
  Displacement<AliceSun> const from_parent_position = looking_glass_(
      solar_system_->trajectories().front()->last_position() -
      solar_system_->trajectories().front()->last_position());
  Velocity<AliceSun> const from_parent_velocity = looking_glass_(
      solar_system_->trajectories().front()->last_velocity() -
      solar_system_->trajectories().front()->last_velocity());
  EXPECT_DEATH({
    InsertAllSolarSystemBodies();
    plugin_->EndInitialization();
    plugin_->InsertCelestial(42,
                             bodies_.front()->gravitational_parameter(),
                             SolarSystem::kSun,
                             from_parent_position,
                             from_parent_velocity);
  }, DeathMessage("before the end of initialization"));
  EXPECT_DEATH({
    InsertAllSolarSystemBodies();
    plugin_->InsertCelestial(42,
                             bodies_.front()->gravitational_parameter(),
                             1729,
                             from_parent_position,
                             from_parent_velocity);
  }, DeathMessage("No body at index"));
  EXPECT_DEATH({
    InsertAllSolarSystemBodies();
    plugin_->InsertCelestial(SolarSystem::kEarth,
                             bodies_.front()->gravitational_parameter(),
                             SolarSystem::kSun,
                             from_parent_position,
                             from_parent_velocity);
  }, DeathMessage("Body already exists"));
}

TEST_F(PluginTest, VesselInsertionAtInitialization) {
  GUID const guid = "Test Satellite";
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  bool const inserted = plugin_->InsertOrKeepVessel(guid,
                                                    SolarSystem::kEarth);
  EXPECT_TRUE(inserted);
  plugin_->SetVesselStateOffset(guid,
                                satellite_initial_displacement_,
                                satellite_initial_velocity_);
  EXPECT_THAT(
      AbsoluteError(plugin_->VesselDisplacementFromParent(guid),
                    satellite_initial_displacement_),
      Lt(DBL_EPSILON * AstronomicalUnit));
  EXPECT_THAT(plugin_->VesselParentRelativeVelocity(guid),
              AlmostEquals(satellite_initial_velocity_));
}

// Checks that the plugin correctly uses its 10-second-step history even when
// advanced with smaller timesteps.
TEST_F(PluginTest, AdvanceTimeWithCelestialsOnly) {
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  Time const δt = 0.02 * Second;
  Angle const planetarium_rotation = 42 * Radian;
  auto history_step = [this](int const i) {
    return initial_time_ + i * plugin_->Δt();
  };
  for (int i = 0; i < 10; ++i) {
    for (Instant t = history_step(i) + δt; t <= history_step(i + 1); t += δt) {
      // Called to compute the prolongations.
      EXPECT_CALL(*n_body_system_,
                  Integrate(Ref(plugin_->prolongation_integrator()), t,
                            plugin_->Δt(), 0, true, SizeIs(bodies_.size())))
          .RetiresOnSaturation();
      plugin_->AdvanceTime(t, planetarium_rotation);
    }
    // Called to advance the synchronized histories.
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->history_integrator()),
                          history_step(i + 1) + δt,
                          plugin_->Δt(), 0, false,
                          SizeIs(bodies_.size())))
        .WillOnce(
             AppendTimeToTrajectories<5>(history_step(i + 1)))
        .RetiresOnSaturation();
    // Called to compute the prolongations.
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->prolongation_integrator()),
                          history_step(i + 1) + δt, plugin_->Δt(), 0, true,
                          SizeIs(bodies_.size())))
        .RetiresOnSaturation();
    plugin_->AdvanceTime(history_step(i + 1) + δt, planetarium_rotation);
  }
}

// Checks that the plugin correctly advances the history of newly inserted
// vessels with the prolongation integrator (using small steps), then switches
// to the history integrator.
TEST_F(PluginTest, AdvanceTimeWithVessels) {
  // Inserted at |initial_time|.
  GUID const enterprise = "NCC-1701";;
  // Inserted after |initial_time|, but before the histories are first advanced.
  GUID const enterprise_d = "NCC-1701-D";
  // Inserted after the histories are first advanced, at a timestep where the
  // histories are not advanced further.
  GUID const stargazer = "NCC-2893";
  // Inserted just after the histories are advanced.
  GUID const constantinople = "NCC-43622";
  InsertAllSolarSystemBodies();
  plugin_->EndInitialization();
  Time const δt = 0.02 * Second;
  Angle const planetarium_rotation = 42 * Radian;
  std::size_t expected_number_of_new_vessels = 0U;
  std::size_t expected_number_of_old_vessels = 0U;
  auto history_step = [this](int const i) {
    return initial_time_ + i * plugin_->Δt();
  };
  auto insert_vessel =
      [this, &expected_number_of_new_vessels](GUID const guid) {
        bool const inserted = plugin_->InsertOrKeepVessel(guid,
                                                          SolarSystem::kEarth);
        EXPECT_TRUE(inserted) << guid;
        plugin_->SetVesselStateOffset(guid,
                                      satellite_initial_displacement_,
                                      satellite_initial_velocity_);
        ++expected_number_of_new_vessels;
      };
  auto keep_vessel = [this](GUID const guid) {
    bool const inserted = plugin_->InsertOrKeepVessel(guid,
                                                      SolarSystem::kEarth);
    EXPECT_FALSE(inserted) << guid;
  };
  insert_vessel(enterprise);
  for (int i = 0; i < 10; ++i) {
    for (Instant t = history_step(i) + δt; t <= history_step(i + 1); t += δt) {
      // Keep our vessels.  Make sure we're not inserting new ones.
      keep_vessel(enterprise);
      if (t > history_step(0) + 10.1 * δt) {
        keep_vessel(enterprise_d);
      }
      if (t > history_step(1) + 10.1 * δt) {
        keep_vessel(stargazer);
      }
      if (i > 2) {
        keep_vessel(constantinople);
      }
      // Called to compute the prolongations and advance the unsynchronized
      // histories.
      EXPECT_CALL(*n_body_system_,
                  Integrate(Ref(plugin_->prolongation_integrator()), t,
                            plugin_->Δt(), 0, true,
                            SizeIs(bodies_.size() +
                                       expected_number_of_old_vessels +
                                       expected_number_of_new_vessels)))
          .RetiresOnSaturation();
      plugin_->AdvanceTime(t, planetarium_rotation);
      if(AbsoluteError(10, (t - history_step(0)) / δt) < 0.1) {
        insert_vessel(enterprise_d);
      } else if (AbsoluteError(10, (t - history_step(1)) / δt) < 0.1) {
        insert_vessel(stargazer);
      }
    }
    // Keep the vessels for the history-advancing step.
    keep_vessel(enterprise);
    keep_vessel(enterprise_d);
    if (i >= 1) {
      keep_vessel(stargazer);
    }
    if (i > 2) {
      keep_vessel(constantinople);
    }
    // Called to advance the synchronized histories.
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->history_integrator()),
                          history_step(i + 1) + δt,
                          plugin_->Δt(), 0, false,
                          SizeIs(bodies_.size() +
                                     expected_number_of_old_vessels)))
        .WillOnce(AppendTimeToTrajectories<5>(history_step(i + 1)))
        .RetiresOnSaturation();
    if (expected_number_of_new_vessels > 0) {
      // Called to synchronize the new histories.
      EXPECT_CALL(*n_body_system_,
                  Integrate(Ref(plugin_->prolongation_integrator()),
                            history_step(i + 1),
                            plugin_->Δt(), 0, true,
                            SizeIs(bodies_.size() +
                                       expected_number_of_new_vessels)))
          .WillOnce(AppendTimeToTrajectories<5>(history_step(i + 1)))
          .RetiresOnSaturation();
    }
    // Called to compute the prolongations.
    EXPECT_CALL(*n_body_system_,
                Integrate(Ref(plugin_->prolongation_integrator()),
                          history_step(i + 1) + δt, plugin_->Δt(), 0, true,
                          SizeIs(bodies_.size() +
                                     expected_number_of_old_vessels +
                                     expected_number_of_new_vessels)))
        .RetiresOnSaturation();
    plugin_->AdvanceTime(history_step(i + 1) + δt, planetarium_rotation);
    expected_number_of_old_vessels += expected_number_of_new_vessels;
    expected_number_of_new_vessels = 0U;
    if (i == 2) {
      insert_vessel(constantinople);
    }
  }
}

}  // namespace ksp_plugin
}  // namespace principia
<|endoftext|>


<commit_before>
#include "ksp_plugin/vessel.hpp"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "physics/ephemeris.hpp"
#include "physics/solar_system.hpp"

namespace principia {

using physics::Ephemeris;
using physics::SolarSystem;
using quantities::si::Kilogram;
using quantities::si::Metre;
using quantities::si::Second;

namespace ksp_plugin {

// TODO(egg): We would want to use a real ephemeris to properly exercise the
// limit cases.
class VesselTest : public testing::Test {
 protected:
  VesselTest()
      : adaptive_parameters_(
            DormandElMikkawyPrince1986RKN434FM<Position<Barycentric>>(),
            /*max_steps=*/1,
            /*length_integration_tolerance=*/1 * Metre,
            /*speed_integration_tolerance=*/1 * Metre / Second),
        ephemeris_fixed_parameters_(
            McLachlanAtela1992Order5Optimal<Position<Barycentric>>(),
            /*step=*/10 * Second),
        history_fixed_parameters_(
            McLachlanAtela1992Order5Optimal<Position<Barycentric>>(),
            /*step=*/1 * Second) {
    solar_system_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model.proto.txt",
        SOLUTION_DIR / "astronomy" /
            "initial_state_jd_2433282_500000000.proto.txt");
    t0_ = solar_system_.epoch();
    ephemeris_ = solar_system_.MakeEphemeris(
        /*fitting_tolerance=*/1 * Milli(Metre), ephemeris_fixed_parameters_);
    earth_ = std::make_unique<Celestial>(
        solar_system_.massive_body(*ephemeris_, "Earth"));
    vessel_ = std::make_unique<Vessel>(earth_.get(),
                                       ephemeris_.get(),
                                       adaptive_parameters_,
                                       history_fixed_parameters_);
  }

  SolarSystem<Barycentric> solar_system_;
  std::unique_ptr<Ephemeris<Barycentric>> ephemeris_;
  std::unique_ptr<Celestial> earth_;
  Ephemeris<Barycentric>::AdaptiveStepParameters const adaptive_parameters_;
  Ephemeris<Barycentric>::FixedStepParameters const ephemeris_fixed_parameters_;
  Ephemeris<Barycentric>::FixedStepParameters const history_fixed_parameters_;
  std::unique_ptr<Vessel> vessel_;
  DegreesOfFreedom<Barycentric> d1_ = {
      Barycentric::origin +
          Displacement<Barycentric>({1 * Metre, 2 * Metre, 3 * Metre}),
      Velocity<Barycentric>(
          {4 * Metre / Second, 5 * Metre / Second, 6 * Metre / Second})};
  DegreesOfFreedom<Barycentric> d2_ = {
      Barycentric::origin +
          Displacement<Barycentric>({11 * Metre, 12 * Metre, 13 * Metre}),
      Velocity<Barycentric>(
          {14 * Metre / Second, 15 * Metre / Second, 16 * Metre / Second})};
  Instant t0_;
  Instant const t1_ = kUniversalTimeEpoch;
  Instant const t2_ = kUniversalTimeEpoch + 42.3 * Second;
};

using VesselDeathTest = VesselTest;

TEST_F(VesselDeathTest, Uninitialized) {
  EXPECT_DEATH({
    vessel_->history();
  }, "is_initialized");
  EXPECT_DEATH({
    vessel_->prolongation();
  }, "is_initialized");
}

TEST_F(VesselTest, Initialization) {
  EXPECT_FALSE(vessel_->is_initialized());
  vessel_->CreateHistoryAndForkProlongation(t2_, d2_);
  EXPECT_TRUE(vessel_->is_initialized());
  auto const& prolongation = vessel_->prolongation();
  EXPECT_EQ(t2_, prolongation.last().time());
  auto const& history = vessel_->history();
  EXPECT_EQ(t2_, history.last().time());
  EXPECT_FALSE(vessel_->has_flight_plan());
  EXPECT_FALSE(vessel_->has_prediction());
}

TEST_F(VesselTest, Dirty) {
  EXPECT_FALSE(vessel_->is_dirty());
  vessel_->set_dirty();
  EXPECT_TRUE(vessel_->is_dirty());
}

TEST_F(VesselTest, Parent) {
  Celestial celestial(earth_->body());
  EXPECT_EQ(earth_.get(), vessel_->parent());
  vessel_->set_parent(&celestial);
  EXPECT_EQ(&celestial, vessel_->parent());
}

TEST_F(VesselTest, AdvanceTime) {
  vessel_->CreateHistoryAndForkProlongation(t1_, d1_);
  vessel_->AdvanceTimeNotInBubble(t2_);
  EXPECT_EQ(kUniversalTimeEpoch + 42 * Second,
            vessel_->history().last().time());
  EXPECT_EQ(t2_, vessel_->prolongation().last().time());
}

TEST_F(VesselDeathTest, SerializationError) {
  EXPECT_DEATH({
    serialization::Vessel message;
    vessel_->WriteToMessage(&message);
  }, "is_initialized");
  EXPECT_DEATH({
    serialization::Vessel message;
    Vessel::ReadFromMessage(message, ephemeris_.get(), earth_.get());
  }, "message.has_history");
}

TEST_F(VesselTest, SerializationSuccess) {
  serialization::Vessel message;
  EXPECT_FALSE(message.has_history());
  vessel_->CreateHistoryAndForkProlongation(t2_, d2_);
  vessel_->WriteToMessage(&message);
  EXPECT_TRUE(message.has_history());
  vessel_ = Vessel::ReadFromMessage(message, ephemeris_.get(), earth_.get());
  EXPECT_TRUE(vessel_->is_initialized());
}

}  // namespace ksp_plugin
}  // namespace principia
<commit_msg>AdvanceTime works.<commit_after>
#include "ksp_plugin/vessel.hpp"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "physics/ephemeris.hpp"
#include "physics/solar_system.hpp"

namespace principia {

using physics::Ephemeris;
using physics::SolarSystem;
using quantities::si::Kilo;
using quantities::si::Kilogram;
using quantities::si::Metre;
using quantities::si::Second;

namespace ksp_plugin {

// TODO(egg): We would want to use a real ephemeris to properly exercise the
// limit cases.
class VesselTest : public testing::Test {
 protected:
  VesselTest()
      : adaptive_parameters_(
            DormandElMikkawyPrince1986RKN434FM<Position<Barycentric>>(),
            /*max_steps=*/1,
            /*length_integration_tolerance=*/1 * Metre,
            /*speed_integration_tolerance=*/1 * Metre / Second),
        ephemeris_fixed_parameters_(
            McLachlanAtela1992Order5Optimal<Position<Barycentric>>(),
            /*step=*/10 * Second),
        history_fixed_parameters_(
            McLachlanAtela1992Order5Optimal<Position<Barycentric>>(),
            /*step=*/1 * Second) {
    solar_system_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model_two_bodies_test.proto.txt",
        SOLUTION_DIR / "astronomy" / "initial_state_two_bodies_test.proto.txt");
    ephemeris_ = solar_system_.MakeEphemeris(
        /*fitting_tolerance=*/1 * Metre, ephemeris_fixed_parameters_);
    earth_ = std::make_unique<Celestial>(
        solar_system_.massive_body(*ephemeris_, "Earth"));
    vessel_ = std::make_unique<Vessel>(earth_.get(),
                                       ephemeris_.get(),
                                       adaptive_parameters_,
                                       history_fixed_parameters_);
    t0_ = solar_system_.epoch();
    t1_ = t0_ + 11.1 * Second;
    t2_ = t1_ + 22.2 * Second;
  }

  SolarSystem<Barycentric> solar_system_;
  std::unique_ptr<Ephemeris<Barycentric>> ephemeris_;
  std::unique_ptr<Celestial> earth_;
  Ephemeris<Barycentric>::AdaptiveStepParameters const adaptive_parameters_;
  Ephemeris<Barycentric>::FixedStepParameters const ephemeris_fixed_parameters_;
  Ephemeris<Barycentric>::FixedStepParameters const history_fixed_parameters_;
  std::unique_ptr<Vessel> vessel_;
  DegreesOfFreedom<Barycentric> d1_ = {
      Barycentric::origin +
          Displacement<Barycentric>(
              {1 * Kilo(Metre), 2 * Kilo(Metre), 3 * Kilo(Metre)}),
      Velocity<Barycentric>({4 * Kilo(Metre) / Second,
                             5 * Kilo(Metre) / Second,
                             6 * Kilo(Metre) / Second})};
  DegreesOfFreedom<Barycentric> d2_ = {
      Barycentric::origin +
          Displacement<Barycentric>(
              {11 * Kilo(Metre), 12 * Kilo(Metre), 13 * Kilo(Metre)}),
      Velocity<Barycentric>({14 * Kilo(Metre) / Second,
                             15 * Kilo(Metre) / Second,
                             16 * Kilo(Metre) / Second})};
  Instant t0_;
  Instant t1_;
  Instant t2_;
};

using VesselDeathTest = VesselTest;

TEST_F(VesselDeathTest, Uninitialized) {
  EXPECT_DEATH({
    vessel_->history();
  }, "is_initialized");
  EXPECT_DEATH({
    vessel_->prolongation();
  }, "is_initialized");
}

TEST_F(VesselTest, Initialization) {
  EXPECT_FALSE(vessel_->is_initialized());
  vessel_->CreateHistoryAndForkProlongation(t2_, d2_);
  EXPECT_TRUE(vessel_->is_initialized());
  auto const& prolongation = vessel_->prolongation();
  EXPECT_EQ(t2_, prolongation.last().time());
  auto const& history = vessel_->history();
  EXPECT_EQ(t2_, history.last().time());
  EXPECT_FALSE(vessel_->has_flight_plan());
  EXPECT_FALSE(vessel_->has_prediction());
}

TEST_F(VesselTest, Dirty) {
  EXPECT_FALSE(vessel_->is_dirty());
  vessel_->set_dirty();
  EXPECT_TRUE(vessel_->is_dirty());
}

TEST_F(VesselTest, Parent) {
  Celestial celestial(earth_->body());
  EXPECT_EQ(earth_.get(), vessel_->parent());
  vessel_->set_parent(&celestial);
  EXPECT_EQ(&celestial, vessel_->parent());
}

TEST_F(VesselTest, AdvanceTime) {
  vessel_->CreateHistoryAndForkProlongation(t1_, d1_);
  vessel_->AdvanceTimeNotInBubble(t2_);
  EXPECT_EQ(t2_ - 0.2 * Second, vessel_->history().last().time());
  EXPECT_EQ(t2_, vessel_->prolongation().last().time());
}

TEST_F(VesselDeathTest, SerializationError) {
  EXPECT_DEATH({
    serialization::Vessel message;
    vessel_->WriteToMessage(&message);
  }, "is_initialized");
  EXPECT_DEATH({
    serialization::Vessel message;
    Vessel::ReadFromMessage(message, ephemeris_.get(), earth_.get());
  }, "message.has_history");
}

TEST_F(VesselTest, SerializationSuccess) {
  serialization::Vessel message;
  EXPECT_FALSE(message.has_history());
  vessel_->CreateHistoryAndForkProlongation(t2_, d2_);
  vessel_->WriteToMessage(&message);
  EXPECT_TRUE(message.has_history());
  vessel_ = Vessel::ReadFromMessage(message, ephemeris_.get(), earth_.get());
  EXPECT_TRUE(vessel_->is_initialized());
}

}  // namespace ksp_plugin
}  // namespace principia
<|endoftext|>


<commit_before>//
// Created by Ivan Shynkarenka on 27.07.2016
//

#include "catch.hpp"

#include "memory/allocator.h"
#include "memory/allocator_arena.h"
#include "memory/allocator_hybrid.h"
#include "memory/allocator_null.h"
#include "memory/allocator_stack.h"

#include <list>
#include <map>
#include <vector>
#include <unordered_map>

using namespace CppCommon;

TEST_CASE("Default allocator", "[CppCommon][Memory]")
{
    DefaultMemoryManager manger;
    DefaultAllocator<uint8_t> alloc(manger);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    alloc.deallocate(ptr, 10);
}

TEST_CASE("Null allocator", "[CppCommon][Memory]")
{
    NullMemoryManager manger;
    NullAllocator<uint8_t, true> alloc(manger);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr == nullptr);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr == nullptr);
    alloc.deallocate(ptr, 10);
}

TEST_CASE("Stack allocator", "[CppCommon][Memory]")
{
    StackMemoryManager<11, 1> manger;
    StackAllocator<uint8_t, 11, true, 1> alloc(manger);

    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 10);

    ptr = alloc.allocate(1);
    REQUIRE(ptr == nullptr);

    alloc.reset();
    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);
}

TEST_CASE("Arena allocator", "[CppCommon][Memory]")
{
    ArenaMemoryManager<1> manger(11);
    ArenaAllocator<uint8_t, true, 1> alloc(manger);

    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 10);

    ptr = alloc.allocate(1);
    REQUIRE(ptr == nullptr);

    alloc.reset();
    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);
}

TEST_CASE("Hybrid allocator", "[CppCommon][Memory]")
{
    DefaultMemoryManager auxiliary;
    HybridMemoryManager<DefaultMemoryManager, 1> manger(auxiliary, 11);
    HybridAllocator<uint8_t, DefaultMemoryManager, true, 1> alloc(manger);

    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 10);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 1);

    alloc.reset();
    REQUIRE(manger.capacity() == 12);
    REQUIRE(manger.size() == 0);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);
}

TEST_CASE("Hybrid allocator with stl containers", "[CppCommon][Memory]")
{
    DefaultMemoryManager auxiliary;
    HybridMemoryManager<DefaultMemoryManager> manger(auxiliary, 10);
    HybridAllocator<int, DefaultMemoryManager> alloc(manger);

    std::vector<int, decltype(alloc)> v(alloc);
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    v.clear();

    std::list<int, decltype(alloc)> l(alloc);
    l.push_back(0);
    l.push_back(1);
    l.push_back(2);
    l.clear();

    std::map<int, int, std::less<int>, decltype(alloc)> m(alloc);
    m[0] = 0;
    m[1] = 10;
    m[2] = 20;
    m.clear();

    std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, decltype(alloc)> u(alloc);
    u[0] = 0;
    u[1] = 10;
    u[2] = 20;
    u.clear();
}
<commit_msg>bugfixes<commit_after>//
// Created by Ivan Shynkarenka on 27.07.2016
//

#include "catch.hpp"

#include "memory/allocator.h"
#include "memory/allocator_arena.h"
#include "memory/allocator_hybrid.h"
#include "memory/allocator_null.h"
#include "memory/allocator_stack.h"

#include <list>
#include <map>
#include <vector>
#include <unordered_map>

using namespace CppCommon;

TEST_CASE("Default allocator", "[CppCommon][Memory]")
{
    DefaultMemoryManager manger;
    DefaultAllocator<uint8_t> alloc(manger);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    alloc.deallocate(ptr, 10);
}

TEST_CASE("Null allocator", "[CppCommon][Memory]")
{
    NullMemoryManager manger;
    NullAllocator<uint8_t, true> alloc(manger);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr == nullptr);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr == nullptr);
    alloc.deallocate(ptr, 10);
}

TEST_CASE("Stack allocator", "[CppCommon][Memory]")
{
    StackMemoryManager<11, 1> manger;
    StackAllocator<uint8_t, 11, true, 1> alloc(manger);

    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 10);

    ptr = alloc.allocate(1);
    REQUIRE(ptr == nullptr);

    alloc.reset();
    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);
}

TEST_CASE("Arena allocator", "[CppCommon][Memory]")
{
    ArenaMemoryManager<1> manger(11);
    ArenaAllocator<uint8_t, true, 1> alloc(manger);

    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 10);

    ptr = alloc.allocate(1);
    REQUIRE(ptr == nullptr);

    alloc.reset();
    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);
}

TEST_CASE("Hybrid allocator", "[CppCommon][Memory]")
{
    DefaultMemoryManager auxiliary;
    HybridMemoryManager<DefaultMemoryManager, 1> manger(auxiliary, 11);
    HybridAllocator<uint8_t, DefaultMemoryManager, true, 1> alloc(manger);

    REQUIRE(manger.capacity() == 11);
    REQUIRE(manger.size() == 0);

    uint8_t* ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);

    ptr = alloc.allocate(10);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 10);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 11);
    alloc.deallocate(ptr, 1);

    alloc.reset();
    REQUIRE(manger.capacity() == 12);
    REQUIRE(manger.size() == 0);

    ptr = alloc.allocate(1);
    REQUIRE(ptr != nullptr);
    REQUIRE(manger.size() == 1);
    alloc.deallocate(ptr, 1);
}

TEST_CASE("Hybrid allocator with stl direct containers", "[CppCommon][Memory]")
{
    DefaultMemoryManager auxiliary;
    HybridMemoryManager<DefaultMemoryManager> manger(auxiliary, 10);
    HybridAllocator<int, DefaultMemoryManager> alloc(manger);

    std::vector<int, decltype(alloc)> v(alloc);
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    v.clear();

    std::list<int, decltype(alloc)> l(alloc);
    l.push_back(0);
    l.push_back(1);
    l.push_back(2);
    l.clear();
}

TEST_CASE("Hybrid allocator with stl associative containers", "[CppCommon][Memory]")
{
    DefaultMemoryManager auxiliary;
    HybridMemoryManager<DefaultMemoryManager> manger(auxiliary, 10);
    HybridAllocator<std::pair<const int, int>, DefaultMemoryManager> alloc(manger);

    std::map<int, int, std::less<int>, decltype(alloc)> m(alloc);
    m[0] = 0;
    m[1] = 10;
    m[2] = 20;
    m.clear();

    std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, decltype(alloc)> u(alloc);
    u[0] = 0;
    u[1] = 10;
    u[2] = 20;
    u.clear();
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: unotest.cxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_testshl2.hxx"
#include "rtl/bootstrap.hxx"
#include <comphelper/processfactory.hxx>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <cppunit/simpleheader.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/xml/sax/XParser.hpp>

namespace css = com::sun::star;
namespace lang = css::lang;
namespace uno  = css::uno;
namespace sax = css::xml::sax;

// StringHelper
inline void operator <<= (rtl::OString& _rAsciiString, const rtl::OUString& _rUnicodeString)
{
    _rAsciiString = rtl::OUStringToOString(_rUnicodeString,RTL_TEXTENCODING_ASCII_US);
}

namespace unotest
{
//------------------------------------------------------------------------
// testing constructors
//------------------------------------------------------------------------

    class  ctor : public CppUnit::TestFixture
    {
    public:
        void ctor_001()
            {
                uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
                if (xFactory.is())
                {
                    // sample, get a xParser instance
                    uno::Reference< sax::XParser > xParser;
                    xParser = uno::Reference< sax::XParser > (
                        xFactory->createInstance(
                            ::rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser")), uno::UNO_QUERY);

                    CPPUNIT_ASSERT_MESSAGE("can't get sax::Parser", xParser.is());
                }
            }

        CPPUNIT_TEST_SUITE(ctor);
        CPPUNIT_TEST(ctor_001);
        CPPUNIT_TEST_SUITE_END();
    };

    // -----------------------------------------------------------------------------
    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(unotest::ctor, "unotest");
} // unotest

// -----------------------------------------------------------------------------

// this macro creates an empty function, which will called by the RegisterAllFunctions()
// to let the user the possibility to also register some functions by hand.

void RegisterAdditionalFunctions(FktRegFuncPtr _pFunc)
{
    (void) _pFunc;
    uno::Reference<lang::XMultiServiceFactory> xMS;

    try
    {
        uno::Reference< uno::XComponentContext > xComponentContext = cppu::defaultBootstrap_InitialComponentContext();
        xMS.set(xComponentContext->getServiceManager(), uno::UNO_QUERY);
        comphelper::setProcessServiceFactory(xMS);
    }
    catch (::com::sun::star::uno::Exception e )
    {
        rtl::OString aError;
        aError <<= e.Message;
        printf("Error: %s\n", aError.getStr());
    }
}
// NOADDITIONAL;
<commit_msg>INTEGRATION: CWS ause093 (1.5.6); FILE MERGED 2008/05/06 06:40:33 lla 1.5.6.1: #i88845# add a new test<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: unotest.cxx,v $
 * $Revision: 1.6 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_testshl2.hxx"
#include "rtl/bootstrap.hxx"
#include <comphelper/processfactory.hxx>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <cppunit/simpleheader.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/xml/sax/XParser.hpp>

namespace css = com::sun::star;
namespace lang = css::lang;
namespace uno  = css::uno;
namespace sax = css::xml::sax;

// StringHelper
inline void operator <<= (rtl::OString& _rAsciiString, const rtl::OUString& _rUnicodeString)
{
    _rAsciiString = rtl::OUStringToOString(_rUnicodeString,RTL_TEXTENCODING_ASCII_US);
}

namespace unotest
{
//------------------------------------------------------------------------
// testing constructors
//------------------------------------------------------------------------

    class  ctor : public CppUnit::TestFixture
    {
    public:
        void ctor_001()
            {
                uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
                if (xFactory.is())
                {
                    // sample, get a xParser instance
                    uno::Reference< sax::XParser > xParser;
                    xParser = uno::Reference< sax::XParser > (
                        xFactory->createInstance(
                            ::rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser")), uno::UNO_QUERY);

                    CPPUNIT_ASSERT_MESSAGE("can't get sax::Parser", xParser.is());
                }
            }
        void ctor_002()
            {
                CPPUNIT_ASSERT_MESSAGE("Simple testshl2 test, MUST fail.", sal_False);
            }

        CPPUNIT_TEST_SUITE(ctor);
        CPPUNIT_TEST(ctor_001);
        CPPUNIT_TEST(ctor_002);
        CPPUNIT_TEST_SUITE_END();
    };

    // -----------------------------------------------------------------------------
    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(unotest::ctor, "unotest");
} // unotest

// -----------------------------------------------------------------------------

// this macro creates an empty function, which will called by the RegisterAllFunctions()
// to let the user the possibility to also register some functions by hand.

void RegisterAdditionalFunctions(FktRegFuncPtr _pFunc)
{
    (void) _pFunc;
    uno::Reference<lang::XMultiServiceFactory> xMS;

    try
    {
        uno::Reference< uno::XComponentContext > xComponentContext = cppu::defaultBootstrap_InitialComponentContext();
        xMS.set(xComponentContext->getServiceManager(), uno::UNO_QUERY);
        comphelper::setProcessServiceFactory(xMS);
    }
    catch (::com::sun::star::uno::Exception e )
    {
        rtl::OString aError;
        aError <<= e.Message;
        printf("Error: %s\n", aError.getStr());
    }
}
// NOADDITIONAL;
<|endoftext|>


<commit_before>#pragma once
#include <cmath>

#include "global_config.hpp"

namespace mocc {

    namespace fp_utils {
        union float_int {
            float f;
            int32_t i;
        };

        union double_int {
            double f;
            int64_t i;
        };
    }

    /**
     * \brief Compare two floats using ULP.
     *
     * See
     * this page for more info about testing floating point equivalence.
     */
    inline bool fp_equiv_ulp(float v1, float v2) {
        fp_utils::float_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        fp_utils::float_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    /**
     * \brief Compare two doubles using ULP.
     *
     * \copydetails fp_equiv_ulp(float, float)
     */
    inline bool fp_equiv_ulp(double v1, double v2) {
        fp_utils::double_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        fp_utils::double_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    inline bool fp_equiv_rel(real_t v1, real_t v2) {
        return fabs(v1-v2)/fabs(v1) < FLOAT_EPS;
    }
    inline bool fp_equiv_abs(real_t v1, real_t v2) {
        return fabs(v1-v2) < FLOAT_EPS;
    }
}
<commit_msg>Add docs to fp_utils<commit_after>#pragma once
#include <cmath>

#include "global_config.hpp"

namespace mocc {

    namespace fp_utils {
        union float_int {
            float f;
            int32_t i;
        };

        union double_int {
            double f;
            int64_t i;
        };
    }

    /**
     * \brief Compare two floats using ULP.
     *
     * See
     * this page and
     * this page for more info about testing floating point equivalence.
     */
    inline bool fp_equiv_ulp(float v1, float v2) {
        fp_utils::float_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        fp_utils::float_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    /**
     * \brief Compare two doubles using ULP.
     *
     * \copydetails fp_equiv_ulp(float, float)
     */
    inline bool fp_equiv_ulp(double v1, double v2) {
        fp_utils::double_int i1;
        i1.f = v1;
        if (i1.i < 0) {
            i1.i = 0x80000000 - i1.i;
        }

        fp_utils::double_int i2;
        i2.f = v2;
        if (i2.i < 0) {
            i2.i = 0x80000000 - i2.i;
        }

        return std::abs(i1.i - i2.i) < 100;
    }

    inline bool fp_equiv_rel(real_t v1, real_t v2) {
        return fabs(v1-v2)/fabs(v1) < FLOAT_EPS;
    }
    inline bool fp_equiv_abs(real_t v1, real_t v2) {
        return fabs(v1-v2) < FLOAT_EPS;
    }
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief memory mapped files in posix
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Oreste Costa-Panaia
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "memory-map.h"

#ifdef TRI_HAVE_POSIX_MMAP

#include "Basics/logging.h"
#include "Basics/tri-strings.h"

#include <sys/mman.h>

////////////////////////////////////////////////////////////////////////////////
// @brief flush memory mapped file to disk
////////////////////////////////////////////////////////////////////////////////

int TRI_FlushMMFile (int fileDescriptor,
                     void* startingAddress,
                     size_t numOfBytesToFlush,
                     int flags) {

  // ...........................................................................
  // Possible flags to send are (based upon the Ubuntu Linux ASM include files:
  // #define MS_ASYNC        1             /* sync memory asynchronously */
  // #define MS_INVALIDATE   2               /* invalidate the caches */
  // #define MS_SYNC         4               /* synchronous memory sync */
  // Note: under windows all flushes are achieved synchronously
  // ...........................................................................

  int res = msync(startingAddress, numOfBytesToFlush, flags);

#ifdef __APPLE__
  if (res == 0) {
    res = fcntl(fileDescriptor, F_FULLFSYNC, 0);
  }
#endif

  if (res == 0) {
    // msync was successful
    return TRI_ERROR_NO_ERROR;
  }

  if (errno == ENOMEM) {
    // we have synced a region that was not mapped

    // set a special error. ENOMEM (out of memory) is not appropriate
    LOG_ERROR("msync failed for range %p - %p", startingAddress, (void*) (((char*) startingAddress) + numOfBytesToFlush));

    return TRI_ERROR_ARANGO_MSYNC_FAILED;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
// @brief memory map a file
////////////////////////////////////////////////////////////////////////////////

int TRI_MMFile (void* memoryAddress,
                size_t numOfBytesToInitialise,
                int memoryProtection,
                int flags,
                int fileDescriptor,
                void** mmHandle,
                int64_t offset,
                void** result) {

  off_t offsetRetyped = (off_t)(offset);

  *mmHandle = nullptr; // only useful for Windows

  *result = mmap(memoryAddress, numOfBytesToInitialise, memoryProtection, flags, fileDescriptor, offsetRetyped);

  if (*result != MAP_FAILED) {
    return TRI_ERROR_NO_ERROR;
  }

  if (errno == ENOMEM) {
    return TRI_ERROR_OUT_OF_MEMORY_MMAP;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
// @brief unmap a memory-mapped file
////////////////////////////////////////////////////////////////////////////////

int TRI_UNMMFile (void* memoryAddress,
                  size_t numOfBytesToUnMap,
                  int fileDescriptor,
                  void** mmHandle) {
  TRI_ASSERT(*mmHandle == nullptr); // only useful for Windows

  int res = munmap(memoryAddress, numOfBytesToUnMap);

  if (res == 0) {
    return TRI_ERROR_NO_ERROR;
  }

  if (errno == ENOSPC) {
    return TRI_ERROR_ARANGO_FILESYSTEM_FULL;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
// @brief protect a region in a memory-mapped file
////////////////////////////////////////////////////////////////////////////////

int TRI_ProtectMMFile (void* memoryAddress,
                       size_t numOfBytesToProtect,
                       int flags,
                       int fileDescriptor,
                       void** mmHandle) {
  TRI_ASSERT(*mmHandle == nullptr); // only useful for Windows

  int res = mprotect(memoryAddress, numOfBytesToProtect, flags);

  if (res == 0) {
    return TRI_ERROR_NO_ERROR;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief gives hints about upcoming sequential memory usage
////////////////////////////////////////////////////////////////////////////////

int TRI_MMFileAdvise (void* memoryAddress, size_t numOfBytes, int advice) {
#ifdef __linux__
  LOG_DEBUG("Doing madvise %d for %lu length %lu", advice,
            (uint64_t) memoryAddress, numOfBytes);
  char buffer[256];
  int res = madvise(memoryAddress, numOfBytes, advice);
  if (res == 0) {
    return TRI_ERROR_NO_ERROR;
  }
  else {
    char* p = strerror_r(errno, buffer, 256);
    LOG_INFO("madvise %d for %lu length %lu failed with: %s ",
             advice, (uint64_t) memoryAddress, numOfBytes, p);
    return TRI_ERROR_INTERNAL;
  }
#else
  return TRI_ERROR_NO_ERROR;
#endif
}

#endif

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>cppcheck<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief memory mapped files in posix
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Oreste Costa-Panaia
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "memory-map.h"

#ifdef TRI_HAVE_POSIX_MMAP

#include "Basics/logging.h"
#include "Basics/tri-strings.h"

#include <sys/mman.h>

////////////////////////////////////////////////////////////////////////////////
// @brief flush memory mapped file to disk
////////////////////////////////////////////////////////////////////////////////

int TRI_FlushMMFile (int fileDescriptor,
                     void* startingAddress,
                     size_t numOfBytesToFlush,
                     int flags) {

  // ...........................................................................
  // Possible flags to send are (based upon the Ubuntu Linux ASM include files:
  // #define MS_ASYNC        1             /* sync memory asynchronously */
  // #define MS_INVALIDATE   2               /* invalidate the caches */
  // #define MS_SYNC         4               /* synchronous memory sync */
  // Note: under windows all flushes are achieved synchronously
  // ...........................................................................

  int res = msync(startingAddress, numOfBytesToFlush, flags);

#ifdef __APPLE__
  if (res == 0) {
    res = fcntl(fileDescriptor, F_FULLFSYNC, 0);
  }
#endif

  if (res == 0) {
    // msync was successful
    return TRI_ERROR_NO_ERROR;
  }

  if (errno == ENOMEM) {
    // we have synced a region that was not mapped

    // set a special error. ENOMEM (out of memory) is not appropriate
    LOG_ERROR("msync failed for range %p - %p", startingAddress, (void*) (((char*) startingAddress) + numOfBytesToFlush));

    return TRI_ERROR_ARANGO_MSYNC_FAILED;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
// @brief memory map a file
////////////////////////////////////////////////////////////////////////////////

int TRI_MMFile (void* memoryAddress,
                size_t numOfBytesToInitialise,
                int memoryProtection,
                int flags,
                int fileDescriptor,
                void** mmHandle,
                int64_t offset,
                void** result) {

  off_t offsetRetyped = (off_t)(offset);

  *mmHandle = nullptr; // only useful for Windows

  *result = mmap(memoryAddress, numOfBytesToInitialise, memoryProtection, flags, fileDescriptor, offsetRetyped);

  if (*result != MAP_FAILED) {
    return TRI_ERROR_NO_ERROR;
  }

  if (errno == ENOMEM) {
    return TRI_ERROR_OUT_OF_MEMORY_MMAP;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
// @brief unmap a memory-mapped file
////////////////////////////////////////////////////////////////////////////////

int TRI_UNMMFile (void* memoryAddress,
                  size_t numOfBytesToUnMap,
                  int fileDescriptor,
                  void** mmHandle) {
  TRI_ASSERT(*mmHandle == nullptr); // only useful for Windows

  int res = munmap(memoryAddress, numOfBytesToUnMap);

  if (res == 0) {
    return TRI_ERROR_NO_ERROR;
  }

  if (errno == ENOSPC) {
    return TRI_ERROR_ARANGO_FILESYSTEM_FULL;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
// @brief protect a region in a memory-mapped file
////////////////////////////////////////////////////////////////////////////////

int TRI_ProtectMMFile (void* memoryAddress,
                       size_t numOfBytesToProtect,
                       int flags,
                       int fileDescriptor,
                       void** mmHandle) {
  TRI_ASSERT(*mmHandle == nullptr); // only useful for Windows

  int res = mprotect(memoryAddress, numOfBytesToProtect, flags);

  if (res == 0) {
    return TRI_ERROR_NO_ERROR;
  }

  return TRI_ERROR_SYS_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief gives hints about upcoming sequential memory usage
////////////////////////////////////////////////////////////////////////////////

int TRI_MMFileAdvise (void* memoryAddress, size_t numOfBytes, int advice) {
#ifdef __linux__
  LOG_DEBUG("Doing madvise %d for %lu length %lu", advice,
            (uint64_t) memoryAddress, numOfBytes);
  int res = madvise(memoryAddress, numOfBytes, advice);

  if (res == 0) {
    return TRI_ERROR_NO_ERROR;
  }
  else {
    char buffer[256];
    char* p = strerror_r(errno, buffer, 256);
    LOG_INFO("madvise %d for %lu length %lu failed with: %s ",
             advice, (uint64_t) memoryAddress, numOfBytes, p);
    return TRI_ERROR_INTERNAL;
  }
#else
  return TRI_ERROR_NO_ERROR;
#endif
}

#endif

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "CommonCommonPch.h"
#include "Common/Int64Math.h"

#if defined(_M_X64) && defined(_MSC_VER)
#pragma intrinsic(_mul128)
#endif

bool
Int64Math::Add(int64 left, int64 right, int64 *pResult)
{
    // Overflow occurs when the result has a different sign from both the left and right operands
    *pResult = left + right;
    return ((left ^ *pResult) & (right ^ *pResult)) < 0;
}

// Returns true if we overflowed, false if we didn't
bool
Int64Math::Mul(int64 left, int64 right, int64 *pResult)
{
// TODO: we should use an optimized version of mul128 in !windows too.
#if defined(_M_X64) && defined(_MSC_VER)
    int64 high;
    *pResult = _mul128(left, right, &high);
    return ((*pResult > 0) && high != 0) || ((*pResult < 0) && (high != -1));
#else
    *pResult = left * right;
    return (left != 0 && right != 0 && (*pResult / left) != right);
#endif
}

bool
Int64Math::Shl(int64 left, int64 right, int64 *pResult)
{
    *pResult = left << (right & 63);
    return (left != (int64)((uint64)*pResult >> right));
}

bool
Int64Math::Sub(int64 left, int64 right, int64 *pResult)
{
    // Overflow occurs when the result has a different sign from the left operand, and the result has the same sign as the
    // right operand
    *pResult = left - right;
    return ((left ^ *pResult) & ~(right ^ *pResult)) < 0;
}

bool
Int64Math::Div(int64 left, int64 right, int64 *pResult)
{
    AssertMsg(right != 0, "Divide by zero...");

    if (right == -1 && left == INT64_MIN)
    {
        //Special check for INT64_MIN/-1
        return true;
    }

    *pResult = left / right;
    return false;
}

bool
Int64Math::Mod(int64 left, int64 right, int64 *pResult)
{
    AssertMsg(right != 0, "Mod by zero...");
    if (right == -1 && left == INT64_MIN)
    {
        //Special check for INT64_MIN/-1
        return true;
    }
    *pResult = left % right;
    return false;
}

bool
Int64Math::Shr(int64 left, int64 right, int64 *pResult)
{
    *pResult = left >> (right & 63);
    return false;
}

bool
Int64Math::ShrU(int64 left, int64 right, int64 *pResult)
{
    uint64 uResult = ((uint64)left) >> (right & 63);
    *pResult = uResult;
    return false;
}

bool
Int64Math::And(int64 left, int64 right, int64 *pResult)
{
    *pResult = left & right;
    return false;
}

bool
Int64Math::Or(int64 left, int64 right, int64 *pResult)
{
    *pResult = left | right;
    return false;
}

bool
Int64Math::Xor(int64 left, int64 right, int64 *pResult)
{
    *pResult = left ^ right;
    return false;
}

bool
Int64Math::Neg(int64 val, int64 *pResult)
{
    *pResult = -val;
    return *pResult == INT64_MIN;
}

bool
Int64Math::Not(int64 val, int64 *pResult)
{
    *pResult = ~val;
    return false;
}

bool
Int64Math::Inc(int64 val, int64 *pResult)
{
    *pResult = val + 1;
    // Overflow if result ends up less than input
    return *pResult <= val;
}

bool
Int64Math::Dec(int64 val, int64 *pResult)
{
    *pResult = val - 1;
    // Overflow if result ends up greater than input
    return *pResult >= val;
}

uint64
Int64Math::Log2(int64 val)
{
    uint64 uval = (uint64)val;
    uint64 ret;
    for (ret = 0; uval >>= 1; ret++);
    return ret;
}

int64
Int64Math::NearestInRangeTo(const int64 value, const int64 minimum, const int64 maximum) // inclusive
{
    Assert(minimum <= maximum);
    return minimum >= value ? minimum : maximum <= value ? maximum : value;
}
<commit_msg>cross platform: Implement _mul128<commit_after>//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "CommonCommonPch.h"
#include "Common/Int64Math.h"

#if defined(_M_X64)
#if defined(_MSC_VER)
    #pragma intrinsic(_mul128)
#else
    static int64 _mul128(const int64 left, const int64 right, int64 *high) noexcept
    {
        int64 low;
        __asm__
        (
            "imulq %[right]\n"
            // (I)MUL (Q/64) R[D/A]X <- RAX * r/m64
            : "=d"(*high), "=a"(low)
            : [right]"rm"(right), "1"(left)
        );

        return low;
    }
#endif
#endif

bool
Int64Math::Add(int64 left, int64 right, int64 *pResult)
{
    // Overflow occurs when the result has a different sign from both the left and right operands
    *pResult = left + right;
    return ((left ^ *pResult) & (right ^ *pResult)) < 0;
}

// Returns true if we overflowed, false if we didn't
bool
Int64Math::Mul(int64 left, int64 right, int64 *pResult)
{
#if defined(_M_X64)
    int64 high;
    *pResult = _mul128(left, right, &high);
    return ((*pResult > 0) && high != 0) || ((*pResult < 0) && (high != -1));
#else
    *pResult = left * right;
    return (left != 0 && right != 0 && (*pResult / left) != right);
#endif
}

bool
Int64Math::Shl(int64 left, int64 right, int64 *pResult)
{
    *pResult = left << (right & 63);
    return (left != (int64)((uint64)*pResult >> right));
}

bool
Int64Math::Sub(int64 left, int64 right, int64 *pResult)
{
    // Overflow occurs when the result has a different sign from the left operand, and the result has the same sign as the
    // right operand
    *pResult = left - right;
    return ((left ^ *pResult) & ~(right ^ *pResult)) < 0;
}

bool
Int64Math::Div(int64 left, int64 right, int64 *pResult)
{
    AssertMsg(right != 0, "Divide by zero...");

    if (right == -1 && left == INT64_MIN)
    {
        //Special check for INT64_MIN/-1
        return true;
    }

    *pResult = left / right;
    return false;
}

bool
Int64Math::Mod(int64 left, int64 right, int64 *pResult)
{
    AssertMsg(right != 0, "Mod by zero...");
    if (right == -1 && left == INT64_MIN)
    {
        //Special check for INT64_MIN/-1
        return true;
    }
    *pResult = left % right;
    return false;
}

bool
Int64Math::Shr(int64 left, int64 right, int64 *pResult)
{
    *pResult = left >> (right & 63);
    return false;
}

bool
Int64Math::ShrU(int64 left, int64 right, int64 *pResult)
{
    uint64 uResult = ((uint64)left) >> (right & 63);
    *pResult = uResult;
    return false;
}

bool
Int64Math::And(int64 left, int64 right, int64 *pResult)
{
    *pResult = left & right;
    return false;
}

bool
Int64Math::Or(int64 left, int64 right, int64 *pResult)
{
    *pResult = left | right;
    return false;
}

bool
Int64Math::Xor(int64 left, int64 right, int64 *pResult)
{
    *pResult = left ^ right;
    return false;
}

bool
Int64Math::Neg(int64 val, int64 *pResult)
{
    *pResult = -val;
    return *pResult == INT64_MIN;
}

bool
Int64Math::Not(int64 val, int64 *pResult)
{
    *pResult = ~val;
    return false;
}

bool
Int64Math::Inc(int64 val, int64 *pResult)
{
    *pResult = val + 1;
    // Overflow if result ends up less than input
    return *pResult <= val;
}

bool
Int64Math::Dec(int64 val, int64 *pResult)
{
    *pResult = val - 1;
    // Overflow if result ends up greater than input
    return *pResult >= val;
}

uint64
Int64Math::Log2(int64 val)
{
    uint64 uval = (uint64)val;
    uint64 ret;
    for (ret = 0; uval >>= 1; ret++);
    return ret;
}

int64
Int64Math::NearestInRangeTo(const int64 value, const int64 minimum, const int64 maximum) // inclusive
{
    Assert(minimum <= maximum);
    return minimum >= value ? minimum : maximum <= value ? maximum : value;
}
<|endoftext|>