<commit_before>#pragma once

#include <cmath>
#include <string>

#include "base/macros.hpp"

namespace principia {
namespace quantities {

template<int64_t LengthExponent, int64_t MassExponent, int64_t TimeExponent,
         int64_t CurrentExponent, int64_t TemperatureExponent,
         int64_t AmountExponent, int64_t LuminousIntensityExponent,
         int64_t WindingExponent, int64_t AngleExponent,
         int64_t SolidAngleExponent>
struct Dimensions {
  enum {
    Length            = LengthExponent,
    Mass              = MassExponent,
    Time              = TimeExponent,
    Current           = CurrentExponent,
    Temperature       = TemperatureExponent,
    Amount            = AmountExponent,
    LuminousIntensity = LuminousIntensityExponent,
    Winding           = WindingExponent,
    Angle             = AngleExponent,
    SolidAngle        = SolidAngleExponent
  };

  static int const kMinExponent = -16;
  static int const kMaxExponent = 15;
  static int const kExponentBits = 5;
  static int const kExponentMask = 0x1F;

  static_assert(LengthExponent >= kMinExponent &&
                LengthExponent <= kMaxExponent,
                "Invalid length exponent");
  static_assert(MassExponent >= kMinExponent &&
                MassExponent <= kMaxExponent,
                "Invalid mass exponent");
  static_assert(TimeExponent >= kMinExponent &&
                TimeExponent <= kMaxExponent,
                "Invalid time exponent");
  static_assert(CurrentExponent >= kMinExponent &&
                CurrentExponent <= kMaxExponent,
                "Invalid current exponent");
  static_assert(TemperatureExponent >= kMinExponent &&
                TemperatureExponent <= kMaxExponent,
                "Invalid temperature exponent");
  static_assert(AmountExponent >= kMinExponent &&
                AmountExponent <= kMaxExponent,
                "Invalid amount exponent");
  static_assert(LuminousIntensityExponent >= kMinExponent &&
                LuminousIntensityExponent <= kMaxExponent,
                "Invalid luminous intensity exponent");
  static_assert(AngleExponent >= kMinExponent &&
                AngleExponent <= kMaxExponent,
                "Invalid angle exponent");
  static_assert(SolidAngleExponent >= kMinExponent &&
                SolidAngleExponent <= kMaxExponent,
                "Invalid solid angle exponent");
  static_assert(WindingExponent >= kMinExponent &&
                WindingExponent <= kMaxExponent,
                "Invalid winding exponent");

  // The NOLINT are because glint is confused by the binary and.  I kid you not.
  static int64_t const representation =
      (LengthExponent & kExponentMask)                                 |  // NOLINT
      (MassExponent & kExponentMask)              << 1 * kExponentBits |  // NOLINT
      (TimeExponent & kExponentMask)              << 2 * kExponentBits |  // NOLINT
      (CurrentExponent & kExponentMask)           << 3 * kExponentBits |  // NOLINT
      (TemperatureExponent & kExponentMask)       << 4 * kExponentBits |  // NOLINT
      (AmountExponent & kExponentMask)            << 5 * kExponentBits |  // NOLINT
      (LuminousIntensityExponent & kExponentMask) << 6 * kExponentBits |  // NOLINT
      (AngleExponent & kExponentMask)             << 7 * kExponentBits |  // NOLINT
      (SolidAngleExponent & kExponentMask)        << 8 * kExponentBits |  // NOLINT
      (WindingExponent & kExponentMask)           << 9 * kExponentBits;   // NOLINT
};

namespace internal {
template<typename Q>
struct Collapse { using Type = Q; };
template<>
struct Collapse<Quantity<NoDimensions>> { using Type = double; };
template<typename Left, typename Right>
struct ProductGenerator {
  enum {
    Length            = Left::Dimensions::Length + Right::Dimensions::Length,
    Mass              = Left::Dimensions::Mass + Right::Dimensions::Mass,
    Time              = Left::Dimensions::Time + Right::Dimensions::Time,
    Current           = Left::Dimensions::Current + Right::Dimensions::Current,
    Temperature       = Left::Dimensions::Temperature +
                        Right::Dimensions::Temperature,
    Amount            = Left::Dimensions::Amount + Right::Dimensions::Amount,
    LuminousIntensity = Left::Dimensions::LuminousIntensity +
                        Right:: Dimensions::LuminousIntensity,
    Winding           = Left::Dimensions::Winding + Right::Dimensions::Winding,
    Angle             = Left::Dimensions::Angle + Right::Dimensions::Angle,
    SolidAngle        = Left::Dimensions::SolidAngle +
                        Right::Dimensions::SolidAngle
  };
  using Type = typename Collapse<
      Quantity<Dimensions<Length, Mass, Time, Current, Temperature, Amount,
                          LuminousIntensity, Winding, Angle,
                          SolidAngle>>>::Type;
};
template<typename Left>
struct ProductGenerator<Left, double> { using Type = Left; };
template<typename Right>
struct ProductGenerator<double, Right> { using Type = Right; };
template<>
struct ProductGenerator<double, double> {
  using Type = double;
};
template<typename Left, typename Right>
struct QuotientGenerator {
  enum {
    Length            = Left::Dimensions::Length - Right::Dimensions::Length,
    Mass              = Left::Dimensions::Mass - Right::Dimensions::Mass,
    Time              = Left::Dimensions::Time - Right::Dimensions::Time,
    Current           = Left::Dimensions::Current - Right::Dimensions::Current,
    Temperature       = Left::Dimensions::Temperature -
                        Right::Dimensions::Temperature,
    Amount            = Left::Dimensions::Amount - Right::Dimensions::Amount,
    LuminousIntensity = Left::Dimensions::LuminousIntensity -
                        Right:: Dimensions::LuminousIntensity,
    Winding           = Left::Dimensions::Winding - Right::Dimensions::Winding,
    Angle             = Left::Dimensions::Angle - Right::Dimensions::Angle,
    SolidAngle        = Left::Dimensions::SolidAngle -
                        Right::Dimensions::SolidAngle
  };
  using Type = typename Collapse<
      Quantity<Dimensions<Length, Mass, Time, Current, Temperature, Amount,
                          LuminousIntensity, Winding, Angle,
                          SolidAngle>>>::Type;
};
template<typename Left>
struct QuotientGenerator<Left, double> { using Type = Left; };
template<>
struct QuotientGenerator<double, double> {
  using Type = double;
};
template<typename Right>
struct QuotientGenerator<double, Right> {
  enum {
    Length            = -Right::Dimensions::Length,
    Mass              = -Right::Dimensions::Mass,
    Time              = -Right::Dimensions::Time,
    Current           = -Right::Dimensions::Current,
    Temperature       = -Right::Dimensions::Temperature,
    Amount            = -Right::Dimensions::Amount,
    LuminousIntensity = -Right::Dimensions::LuminousIntensity,
    Winding           = -Right::Dimensions::Winding,
    Angle             = -Right::Dimensions::Angle,
    SolidAngle        = -Right::Dimensions::SolidAngle
  };
  using Type = Quantity<
      Dimensions<Length, Mass, Time, Current, Temperature, Amount,
                 LuminousIntensity, Winding, Angle, SolidAngle>>;
};

template<typename T, int exponent>
struct ExponentiationGenerator<T, exponent, std::enable_if_t<(exponent > 1)>> {
  using Type = Product<typename ExponentiationGenerator<T, exponent - 1>::Type,
                       T>;
};

template<typename T, int exponent>
struct ExponentiationGenerator<T, exponent, std::enable_if_t<(exponent < 1)>>{
  using Type = Quotient<typename ExponentiationGenerator<T, exponent + 1>::Type,
                        T>;
};

template<typename T, int exponent>
struct ExponentiationGenerator<T, exponent, std::enable_if_t<(exponent == 1)>>{
  using Type = T;
};

}  // namespace internal

template<typename D>
inline Quantity<D>::Quantity() : magnitude_(0) {}

template<typename D>
inline Quantity<D>::Quantity(double const magnitude) : magnitude_(magnitude) {}

template<typename D>
inline Quantity<D>& Quantity<D>::operator+=(Quantity const& right) {
  magnitude_ += right.magnitude_;
  return *this;
}

template<typename D>
inline Quantity<D>& Quantity<D>::operator-=(Quantity const& right) {
  magnitude_ -= right.magnitude_;
  return *this;
}

template<typename D>
inline Quantity<D>& Quantity<D>::operator*=(double const right) {
  magnitude_ *= right;
  return *this;
}

template<typename D>
inline Quantity<D>& Quantity<D>::operator/=(double const right) {
  magnitude_ /= right;
  return *this;
}

// Additive group

template<typename D>
inline Quantity<D> Quantity<D>::operator+() const {
  return *this;
}

template<typename D>
inline Quantity<D> Quantity<D>::operator-() const {
  return Quantity(-magnitude_);
}

template<typename D>
inline Quantity<D> Quantity<D>::operator+(Quantity const& right) const {
  return Quantity(magnitude_ + right.magnitude_);
}

template<typename D>
inline Quantity<D> Quantity<D>::operator-(Quantity const& right) const {
  return Quantity(magnitude_ - right.magnitude_);
}

// Comparison operators

template<typename D>
inline bool Quantity<D>::operator>(Quantity const& right) const {
  return magnitude_ > right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator<(Quantity const& right) const {
  return magnitude_ < right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator>=(Quantity const& right) const {
  return magnitude_ >= right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator<=(Quantity const& right) const {
  return magnitude_ <= right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator==(Quantity const& right) const {
  return magnitude_ == right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator!=(Quantity const& right) const {
  return magnitude_ != right.magnitude_;
}

template<typename D>
void Quantity<D>::WriteToMessage(
    not_null<serialization::Quantity*> const message) const {
  message->set_dimensions(D::representation);
  message->set_magnitude(magnitude_);
}

template<typename D>
Quantity<D> Quantity<D>::ReadFromMessage(
    serialization::Quantity const& message) {
  CHECK_EQ(D::representation, message.dimensions());
  return Quantity(message.magnitude());
}

// Multiplicative group

template<typename D>
inline Quantity<D> Quantity<D>::operator/(double const right) const {
  return Quantity(magnitude_ / right);
}

template<typename D>
inline Quantity<D> Quantity<D>::operator*(double const right) const {
  return Quantity(magnitude_ * right);
}

template<typename LDimensions, typename RDimensions>
inline internal::Product<Quantity<LDimensions>, Quantity<RDimensions>>
operator*(Quantity<LDimensions> const& left,
          Quantity<RDimensions> const& right) {
  return Product<Quantity<LDimensions>,
                 Quantity<RDimensions>>(left.magnitude_ * right.magnitude_);
}

template<typename LDimensions, typename RDimensions>
inline internal::Quotient<Quantity<LDimensions>, Quantity<RDimensions>>
operator/(Quantity<LDimensions> const& left,
          Quantity<RDimensions> const& right) {
  return Quotient<Quantity<LDimensions>,
                  Quantity<RDimensions>>(left.magnitude_ / right.magnitude_);
}

template<typename RDimensions>
FORCE_INLINE Quantity<RDimensions> operator*(
    double const left,
    Quantity<RDimensions> const& right) {
  return Quantity<RDimensions>(left * right.magnitude_);
}

template<typename RDimensions>
inline typename Quantity<RDimensions>::Inverse operator/(
    double const left,
    Quantity<RDimensions> const& right) {
  return typename Quantity<RDimensions>::Inverse(left / right.magnitude_);
}

template<int exponent>
inline double Pow(double x) {
  return std::pow(x, exponent);
}

// Static specializations for frequently-used exponents, so that this gets
// turned into multiplications at compile time.

template<>
inline double Pow<-3>(double x) {
  return 1 / (x * x * x);
}

template<>
inline double Pow<-2>(double x) {
  return 1 / (x * x);
}

template<>
inline double Pow<-1>(double x) {
  return 1 / x;
}

template<>
inline double Pow<0>(double x) {
  return 1;
}

template<>
inline double Pow<1>(double x) {
  return x;
}

template<>
inline double Pow<2>(double x) {
  return x * x;
}

template<>
inline double Pow<3>(double x) {
  return x * x * x;
}

template<int exponent, typename D>
Exponentiation<Quantity<D>, exponent> Pow(
    Quantity<D> const& x) {
  return Exponentiation<Quantity<D>, exponent>(
      Pow<exponent>(x.magnitude_));
}

inline double Abs(double const x) {
  return std::abs(x);
}

template<typename D>
Quantity<D> Abs(Quantity<D> const& quantity) {
  return Quantity<D>(std::abs(quantity.magnitude_));
}

template<typename Q>
inline Q SIUnit() {
  return Q(1);
}

template<>
inline double SIUnit<double>() {
  return 1;
}

inline std::string FormatUnit(std::string const& name, int const exponent) {
  switch (exponent) {
    case 0:
      return "";
      break;
    case 1:
      return " " + name;
    default:
      return " " + name + "^" + std::to_string(exponent);
  }
}

inline std::string DebugString(double const number, int const precision) {
  char result[50];
#if OS_WIN
  unsigned int old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
  int const size = sprintf_s(result,
                             ("%+." + std::to_string(precision) + "e").c_str(),
                             number);
  _set_output_format(old_exponent_format);
#else
  int const size = snprintf(result, sizeof(result),
                            ("%+." + std::to_string(precision) + "e").c_str(),
                            number);
#endif
  CHECK_LE(0, size);
  return std::string(result, size);
}

template<typename D>
std::string DebugString(Quantity<D> const& quantity, int const precision) {
  return DebugString(quantity.magnitude_, precision) +
      FormatUnit("m", D::Length) + FormatUnit("kg", D::Mass) +
      FormatUnit("s", D::Time) + FormatUnit("A", D::Current) +
      FormatUnit("K", D::Temperature) + FormatUnit("mol", D::Amount) +
      FormatUnit("cd", D::LuminousIntensity) + FormatUnit("cycle", D::Winding) +
      FormatUnit("rad", D::Angle) + FormatUnit("sr", D::SolidAngle);
}

template<typename D>
std::ostream& operator<<(std::ostream& out, Quantity<D> const& quantity) {
  return out << DebugString(quantity);
}

}  // namespace quantities
}  // namespace principia
<commit_msg>Include.<commit_after>#pragma once

#include <cmath>
#include <cstdio>
#include <string>

#include "base/macros.hpp"

namespace principia {
namespace quantities {

template<int64_t LengthExponent, int64_t MassExponent, int64_t TimeExponent,
         int64_t CurrentExponent, int64_t TemperatureExponent,
         int64_t AmountExponent, int64_t LuminousIntensityExponent,
         int64_t WindingExponent, int64_t AngleExponent,
         int64_t SolidAngleExponent>
struct Dimensions {
  enum {
    Length            = LengthExponent,
    Mass              = MassExponent,
    Time              = TimeExponent,
    Current           = CurrentExponent,
    Temperature       = TemperatureExponent,
    Amount            = AmountExponent,
    LuminousIntensity = LuminousIntensityExponent,
    Winding           = WindingExponent,
    Angle             = AngleExponent,
    SolidAngle        = SolidAngleExponent
  };

  static int const kMinExponent = -16;
  static int const kMaxExponent = 15;
  static int const kExponentBits = 5;
  static int const kExponentMask = 0x1F;

  static_assert(LengthExponent >= kMinExponent &&
                LengthExponent <= kMaxExponent,
                "Invalid length exponent");
  static_assert(MassExponent >= kMinExponent &&
                MassExponent <= kMaxExponent,
                "Invalid mass exponent");
  static_assert(TimeExponent >= kMinExponent &&
                TimeExponent <= kMaxExponent,
                "Invalid time exponent");
  static_assert(CurrentExponent >= kMinExponent &&
                CurrentExponent <= kMaxExponent,
                "Invalid current exponent");
  static_assert(TemperatureExponent >= kMinExponent &&
                TemperatureExponent <= kMaxExponent,
                "Invalid temperature exponent");
  static_assert(AmountExponent >= kMinExponent &&
                AmountExponent <= kMaxExponent,
                "Invalid amount exponent");
  static_assert(LuminousIntensityExponent >= kMinExponent &&
                LuminousIntensityExponent <= kMaxExponent,
                "Invalid luminous intensity exponent");
  static_assert(AngleExponent >= kMinExponent &&
                AngleExponent <= kMaxExponent,
                "Invalid angle exponent");
  static_assert(SolidAngleExponent >= kMinExponent &&
                SolidAngleExponent <= kMaxExponent,
                "Invalid solid angle exponent");
  static_assert(WindingExponent >= kMinExponent &&
                WindingExponent <= kMaxExponent,
                "Invalid winding exponent");

  // The NOLINT are because glint is confused by the binary and.  I kid you not.
  static int64_t const representation =
      (LengthExponent & kExponentMask)                                 |  // NOLINT
      (MassExponent & kExponentMask)              << 1 * kExponentBits |  // NOLINT
      (TimeExponent & kExponentMask)              << 2 * kExponentBits |  // NOLINT
      (CurrentExponent & kExponentMask)           << 3 * kExponentBits |  // NOLINT
      (TemperatureExponent & kExponentMask)       << 4 * kExponentBits |  // NOLINT
      (AmountExponent & kExponentMask)            << 5 * kExponentBits |  // NOLINT
      (LuminousIntensityExponent & kExponentMask) << 6 * kExponentBits |  // NOLINT
      (AngleExponent & kExponentMask)             << 7 * kExponentBits |  // NOLINT
      (SolidAngleExponent & kExponentMask)        << 8 * kExponentBits |  // NOLINT
      (WindingExponent & kExponentMask)           << 9 * kExponentBits;   // NOLINT
};

namespace internal {
template<typename Q>
struct Collapse { using Type = Q; };
template<>
struct Collapse<Quantity<NoDimensions>> { using Type = double; };
template<typename Left, typename Right>
struct ProductGenerator {
  enum {
    Length            = Left::Dimensions::Length + Right::Dimensions::Length,
    Mass              = Left::Dimensions::Mass + Right::Dimensions::Mass,
    Time              = Left::Dimensions::Time + Right::Dimensions::Time,
    Current           = Left::Dimensions::Current + Right::Dimensions::Current,
    Temperature       = Left::Dimensions::Temperature +
                        Right::Dimensions::Temperature,
    Amount            = Left::Dimensions::Amount + Right::Dimensions::Amount,
    LuminousIntensity = Left::Dimensions::LuminousIntensity +
                        Right:: Dimensions::LuminousIntensity,
    Winding           = Left::Dimensions::Winding + Right::Dimensions::Winding,
    Angle             = Left::Dimensions::Angle + Right::Dimensions::Angle,
    SolidAngle        = Left::Dimensions::SolidAngle +
                        Right::Dimensions::SolidAngle
  };
  using Type = typename Collapse<
      Quantity<Dimensions<Length, Mass, Time, Current, Temperature, Amount,
                          LuminousIntensity, Winding, Angle,
                          SolidAngle>>>::Type;
};
template<typename Left>
struct ProductGenerator<Left, double> { using Type = Left; };
template<typename Right>
struct ProductGenerator<double, Right> { using Type = Right; };
template<>
struct ProductGenerator<double, double> {
  using Type = double;
};
template<typename Left, typename Right>
struct QuotientGenerator {
  enum {
    Length            = Left::Dimensions::Length - Right::Dimensions::Length,
    Mass              = Left::Dimensions::Mass - Right::Dimensions::Mass,
    Time              = Left::Dimensions::Time - Right::Dimensions::Time,
    Current           = Left::Dimensions::Current - Right::Dimensions::Current,
    Temperature       = Left::Dimensions::Temperature -
                        Right::Dimensions::Temperature,
    Amount            = Left::Dimensions::Amount - Right::Dimensions::Amount,
    LuminousIntensity = Left::Dimensions::LuminousIntensity -
                        Right:: Dimensions::LuminousIntensity,
    Winding           = Left::Dimensions::Winding - Right::Dimensions::Winding,
    Angle             = Left::Dimensions::Angle - Right::Dimensions::Angle,
    SolidAngle        = Left::Dimensions::SolidAngle -
                        Right::Dimensions::SolidAngle
  };
  using Type = typename Collapse<
      Quantity<Dimensions<Length, Mass, Time, Current, Temperature, Amount,
                          LuminousIntensity, Winding, Angle,
                          SolidAngle>>>::Type;
};
template<typename Left>
struct QuotientGenerator<Left, double> { using Type = Left; };
template<>
struct QuotientGenerator<double, double> {
  using Type = double;
};
template<typename Right>
struct QuotientGenerator<double, Right> {
  enum {
    Length            = -Right::Dimensions::Length,
    Mass              = -Right::Dimensions::Mass,
    Time              = -Right::Dimensions::Time,
    Current           = -Right::Dimensions::Current,
    Temperature       = -Right::Dimensions::Temperature,
    Amount            = -Right::Dimensions::Amount,
    LuminousIntensity = -Right::Dimensions::LuminousIntensity,
    Winding           = -Right::Dimensions::Winding,
    Angle             = -Right::Dimensions::Angle,
    SolidAngle        = -Right::Dimensions::SolidAngle
  };
  using Type = Quantity<
      Dimensions<Length, Mass, Time, Current, Temperature, Amount,
                 LuminousIntensity, Winding, Angle, SolidAngle>>;
};

template<typename T, int exponent>
struct ExponentiationGenerator<T, exponent, std::enable_if_t<(exponent > 1)>> {
  using Type = Product<typename ExponentiationGenerator<T, exponent - 1>::Type,
                       T>;
};

template<typename T, int exponent>
struct ExponentiationGenerator<T, exponent, std::enable_if_t<(exponent < 1)>>{
  using Type = Quotient<typename ExponentiationGenerator<T, exponent + 1>::Type,
                        T>;
};

template<typename T, int exponent>
struct ExponentiationGenerator<T, exponent, std::enable_if_t<(exponent == 1)>>{
  using Type = T;
};

}  // namespace internal

template<typename D>
inline Quantity<D>::Quantity() : magnitude_(0) {}

template<typename D>
inline Quantity<D>::Quantity(double const magnitude) : magnitude_(magnitude) {}

template<typename D>
inline Quantity<D>& Quantity<D>::operator+=(Quantity const& right) {
  magnitude_ += right.magnitude_;
  return *this;
}

template<typename D>
inline Quantity<D>& Quantity<D>::operator-=(Quantity const& right) {
  magnitude_ -= right.magnitude_;
  return *this;
}

template<typename D>
inline Quantity<D>& Quantity<D>::operator*=(double const right) {
  magnitude_ *= right;
  return *this;
}

template<typename D>
inline Quantity<D>& Quantity<D>::operator/=(double const right) {
  magnitude_ /= right;
  return *this;
}

// Additive group

template<typename D>
inline Quantity<D> Quantity<D>::operator+() const {
  return *this;
}

template<typename D>
inline Quantity<D> Quantity<D>::operator-() const {
  return Quantity(-magnitude_);
}

template<typename D>
inline Quantity<D> Quantity<D>::operator+(Quantity const& right) const {
  return Quantity(magnitude_ + right.magnitude_);
}

template<typename D>
inline Quantity<D> Quantity<D>::operator-(Quantity const& right) const {
  return Quantity(magnitude_ - right.magnitude_);
}

// Comparison operators

template<typename D>
inline bool Quantity<D>::operator>(Quantity const& right) const {
  return magnitude_ > right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator<(Quantity const& right) const {
  return magnitude_ < right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator>=(Quantity const& right) const {
  return magnitude_ >= right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator<=(Quantity const& right) const {
  return magnitude_ <= right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator==(Quantity const& right) const {
  return magnitude_ == right.magnitude_;
}

template<typename D>
inline bool Quantity<D>::operator!=(Quantity const& right) const {
  return magnitude_ != right.magnitude_;
}

template<typename D>
void Quantity<D>::WriteToMessage(
    not_null<serialization::Quantity*> const message) const {
  message->set_dimensions(D::representation);
  message->set_magnitude(magnitude_);
}

template<typename D>
Quantity<D> Quantity<D>::ReadFromMessage(
    serialization::Quantity const& message) {
  CHECK_EQ(D::representation, message.dimensions());
  return Quantity(message.magnitude());
}

// Multiplicative group

template<typename D>
inline Quantity<D> Quantity<D>::operator/(double const right) const {
  return Quantity(magnitude_ / right);
}

template<typename D>
inline Quantity<D> Quantity<D>::operator*(double const right) const {
  return Quantity(magnitude_ * right);
}

template<typename LDimensions, typename RDimensions>
inline internal::Product<Quantity<LDimensions>, Quantity<RDimensions>>
operator*(Quantity<LDimensions> const& left,
          Quantity<RDimensions> const& right) {
  return Product<Quantity<LDimensions>,
                 Quantity<RDimensions>>(left.magnitude_ * right.magnitude_);
}

template<typename LDimensions, typename RDimensions>
inline internal::Quotient<Quantity<LDimensions>, Quantity<RDimensions>>
operator/(Quantity<LDimensions> const& left,
          Quantity<RDimensions> const& right) {
  return Quotient<Quantity<LDimensions>,
                  Quantity<RDimensions>>(left.magnitude_ / right.magnitude_);
}

template<typename RDimensions>
FORCE_INLINE Quantity<RDimensions> operator*(
    double const left,
    Quantity<RDimensions> const& right) {
  return Quantity<RDimensions>(left * right.magnitude_);
}

template<typename RDimensions>
inline typename Quantity<RDimensions>::Inverse operator/(
    double const left,
    Quantity<RDimensions> const& right) {
  return typename Quantity<RDimensions>::Inverse(left / right.magnitude_);
}

template<int exponent>
inline double Pow(double x) {
  return std::pow(x, exponent);
}

// Static specializations for frequently-used exponents, so that this gets
// turned into multiplications at compile time.

template<>
inline double Pow<-3>(double x) {
  return 1 / (x * x * x);
}

template<>
inline double Pow<-2>(double x) {
  return 1 / (x * x);
}

template<>
inline double Pow<-1>(double x) {
  return 1 / x;
}

template<>
inline double Pow<0>(double x) {
  return 1;
}

template<>
inline double Pow<1>(double x) {
  return x;
}

template<>
inline double Pow<2>(double x) {
  return x * x;
}

template<>
inline double Pow<3>(double x) {
  return x * x * x;
}

template<int exponent, typename D>
Exponentiation<Quantity<D>, exponent> Pow(
    Quantity<D> const& x) {
  return Exponentiation<Quantity<D>, exponent>(
      Pow<exponent>(x.magnitude_));
}

inline double Abs(double const x) {
  return std::abs(x);
}

template<typename D>
Quantity<D> Abs(Quantity<D> const& quantity) {
  return Quantity<D>(std::abs(quantity.magnitude_));
}

template<typename Q>
inline Q SIUnit() {
  return Q(1);
}

template<>
inline double SIUnit<double>() {
  return 1;
}

inline std::string FormatUnit(std::string const& name, int const exponent) {
  switch (exponent) {
    case 0:
      return "";
      break;
    case 1:
      return " " + name;
    default:
      return " " + name + "^" + std::to_string(exponent);
  }
}

inline std::string DebugString(double const number, int const precision) {
  char result[50];
#if OS_WIN
  unsigned int old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT);
  int const size = sprintf_s(result,
                             ("%+." + std::to_string(precision) + "e").c_str(),
                             number);
  _set_output_format(old_exponent_format);
#else
  int const size = snprintf(result, sizeof(result),
                            ("%+." + std::to_string(precision) + "e").c_str(),
                            number);
#endif
  CHECK_LE(0, size);
  return std::string(result, size);
}

template<typename D>
std::string DebugString(Quantity<D> const& quantity, int const precision) {
  return DebugString(quantity.magnitude_, precision) +
      FormatUnit("m", D::Length) + FormatUnit("kg", D::Mass) +
      FormatUnit("s", D::Time) + FormatUnit("A", D::Current) +
      FormatUnit("K", D::Temperature) + FormatUnit("mol", D::Amount) +
      FormatUnit("cd", D::LuminousIntensity) + FormatUnit("cycle", D::Winding) +
      FormatUnit("rad", D::Angle) + FormatUnit("sr", D::SolidAngle);
}

template<typename D>
std::ostream& operator<<(std::ostream& out, Quantity<D> const& quantity) {
  return out << DebugString(quantity);
}

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


<commit_before>
#include <string>

#include "glog/logging.h"
#include "gtest/gtest.h"
#include "quantities/astronomy.hpp"
#include "quantities/BIPM.hpp"
#include "quantities/constants.hpp"
#include "quantities/dimensionless.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "quantities/uk.hpp"
#include "testing_utilities/algebra.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/explicit_operators.hpp"
#include "testing_utilities/numerics.hpp"

using principia::astronomy::EarthMass;
using principia::astronomy::JulianYear;
using principia::astronomy::JupiterMass;
using principia::astronomy::LightYear;
using principia::astronomy::LunarDistance;
using principia::astronomy::Parsec;
using principia::astronomy::SolarMass;
using principia::constants::ElectronMass;
using principia::constants::GravitationalConstant;
using principia::constants::SpeedOfLight;
using principia::constants::StandardGravity;
using principia::constants::VacuumPermeability;
using principia::constants::VacuumPermittivity;
using principia::quantities::Abs;
using principia::quantities::Cos;
using principia::quantities::Dimensionless;
using principia::quantities::Exp;
using principia::quantities::Log;
using principia::quantities::Log10;
using principia::quantities::Log2;
using principia::quantities::Mass;
using principia::quantities::Product;
using principia::quantities::Sin;
using principia::quantities::Speed;
using principia::quantities::Sqrt;
using principia::si::Ampere;
using principia::si::AstronomicalUnit;
using principia::si::Candela;
using principia::si::Cycle;
using principia::si::Day;
using principia::si::Degree;
using principia::si::Hour;
using principia::si::Kelvin;
using principia::si::Kilogram;
using principia::si::Mega;
using principia::si::Metre;
using principia::si::Mole;
using principia::si::Radian;
using principia::si::Second;
using principia::si::Steradian;
using principia::testing_utilities::AbsoluteError;
using principia::testing_utilities::AlmostEquals;
using principia::testing_utilities::RelativeError;
using principia::testing_utilities::Times;
using principia::uk::Foot;
using principia::uk::Furlong;
using principia::uk::Mile;
using principia::uk::Rood;
using testing::Lt;

namespace principia {
namespace geometry {

class QuantitiesTest : public testing::Test {
 protected:
};

TEST_F(QuantitiesTest, AbsoluteValue) {
  EXPECT_EQ(Abs(-1729), Dimensionless(1729));
  EXPECT_EQ(Abs(1729), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionlessComparisons) {
  testing_utilities::TestOrder(Dimensionless(0), Dimensionless(1));
  testing_utilities::TestOrder(Dimensionless(-1), Dimensionless(0));
  testing_utilities::TestOrder(-e, e);
  testing_utilities::TestOrder(Dimensionless(3), π);
  testing_utilities::TestOrder(Dimensionless(42), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionfulComparisons) {
  testing_utilities::TestOrder(EarthMass, JupiterMass);
  testing_utilities::TestOrder(LightYear, Parsec);
  testing_utilities::TestOrder(-SpeedOfLight, SpeedOfLight);
  testing_utilities::TestOrder(SpeedOfLight * Day, LightYear);
}

TEST_F(QuantitiesTest, DimensionlessOperations) {
  Dimensionless const zero    = 0;
  Dimensionless const one     = 1;
  Dimensionless const taxi    = 1729;
  Dimensionless const answer  = 42;
  Dimensionless const heegner = 163;
  testing_utilities::TestField(
      zero, one, taxi, 4 * π / 3, heegner, answer, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlfulOperations) {
  Dimensionless const zero = 0;
  Dimensionless const one = 1;
  Dimensionless const taxi = 1729;
  testing_utilities::TestVectorSpace(
      0 * Metre / Second, SpeedOfLight, 88 * Mile / Hour,
      -340.29 * Metre / Second, zero, one, -2 * π, taxi, 2);
  // Dimensionful multiplication is a tensor product, see [Tao 2012].
  testing_utilities::TestBilinearMap(
      Times<Product<Mass, Speed>, Mass, Speed>, SolarMass,
      ElectronMass, SpeedOfLight, 1 * Furlong / JulianYear, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlessExponentiation) {
  Dimensionless const number   = π - 42;
  Dimensionless positivePowers = 1;
  Dimensionless negativePowers = 1;
  EXPECT_EQ(Dimensionless(1), number.Pow<0>());
  for (int i = 1; i < 10; ++i) {
    positivePowers *= number;
    negativePowers /= number;
    EXPECT_THAT(number.Pow(i), AlmostEquals(positivePowers, i));
    EXPECT_THAT(number.Pow(-i), AlmostEquals(negativePowers, i));
  }
}

// The Greek letters cause a warning when stringified by the macros, because
// apparently Visual Studio doesn't encode strings in UTF-8 by default.
#pragma warning(disable: 4566)

TEST_F(QuantitiesTest, Formatting) {
  auto const allTheUnits = 1 * Metre * Kilogram * Second * Ampere * Kelvin /
                            (Mole * Candela * Cycle * Radian * Steradian);
  std::string const expected = std::string("1e+000 m kg s A K mol^-1") +
                                " cd^-1 cycle^-1 rad^-1 sr^-1";
  std::string const actual = ToString(allTheUnits, 0);
  EXPECT_EQ(expected, actual);
  std::string π16 = "3.1415926535897931e+000";
  EXPECT_EQ(ToString(π), π16);
}

TEST_F(QuantitiesTest, PhysicalConstants) {
  // By definition.
  EXPECT_THAT(1 / SpeedOfLight.Pow<2>(),
              AlmostEquals(VacuumPermittivity * VacuumPermeability, 2));
  // The Keplerian approximation for the mass of the Sun
  // is fairly accurate.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * AstronomicalUnit.Pow<3>() /
                      (GravitationalConstant * JulianYear.Pow<2>()),
                  SolarMass),
              Lt(4E-5));
  EXPECT_THAT(RelativeError(1 * Parsec, 3.26156 * LightYear), Lt(2E-6));
  // The Keplerian approximation for the mass of the Earth
  // is pretty bad, but the error is still only 1%.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * LunarDistance.Pow<3>() /
                      (GravitationalConstant * (27.321582 * Day).Pow<2>()),
                  EarthMass),
              Lt(1E-2));
  EXPECT_THAT(RelativeError(1 * SolarMass, 1047 * JupiterMass), Lt(4E-4));
  // Delambre & Méchain.
  EXPECT_THAT(RelativeError(
                  GravitationalConstant * EarthMass /
                      (40 * Mega(Metre) / (2 * π)).Pow<2>(),
                  StandardGravity),
              Lt(4E-3));
  // Talleyrand.
  EXPECT_THAT(RelativeError(π * Sqrt(1 * Metre / StandardGravity), 1 * Second),
              Lt(4E-3));
}

#pragma warning(default: 4566)

TEST_F(QuantitiesTest, TrigonometricFunctions) {
  EXPECT_EQ(Cos(0 * Degree), 1);
  EXPECT_EQ(Sin(0 * Degree), 0);
  EXPECT_THAT(AbsoluteError(Cos(90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(90 * Degree), 1);
  EXPECT_EQ(Cos(180 * Degree), -1);
  EXPECT_THAT(AbsoluteError(Sin(180 * Degree), 0), Lt(1E-15));
  EXPECT_THAT(AbsoluteError(Cos(-90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(-90 * Degree), -1);
  for (int k = 1; k < 360; ++k) {
    // Don't test for multiples of 90 degrees as zeros lead to horrible
    // conditioning.
    if (k % 90 != 0) {
      EXPECT_THAT(Cos((90 - k) * Degree),
                  AlmostEquals(Sin(k * Degree), 50));
      EXPECT_THAT(Sin(k * Degree) / Cos(k * Degree),
                  AlmostEquals(Tan(k * Degree), 2));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree), Cos(k * Degree)), 80));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree) * AstronomicalUnit,
                                      Cos(k * Degree) * AstronomicalUnit), 80));
      EXPECT_THAT(Cos(ArcCos(Cos(k * Degree))),
                  AlmostEquals(Cos(k * Degree), 10));
      EXPECT_THAT(Sin(ArcSin(Sin(k * Degree))),
                  AlmostEquals(Sin(k * Degree), 1));
    }
  }
  // Horribly conditioned near 0, so not in the loop above.
  EXPECT_EQ(Tan(ArcTan(Tan(-42 * Degree))), Tan(-42 * Degree));
}

TEST_F(QuantitiesTest, HyperbolicFunctions) {
  EXPECT_EQ(Sinh(0 * Radian), 0);
  EXPECT_EQ(Cosh(0 * Radian), 1);
  EXPECT_EQ(Tanh(0 * Radian), 0);
  // Limits:
  EXPECT_EQ(Sinh(20 * Radian), Cosh(20 * Radian));
  EXPECT_EQ(Tanh(20 * Radian), 1);
  EXPECT_EQ(Sinh(-20 * Radian), -Cosh(-20 * Radian));
  EXPECT_EQ(Tanh(-20 * Radian), -1);

  EXPECT_EQ(Sinh(2 * Radian) / Cosh(2 * Radian), Tanh(2 * Radian));
  EXPECT_THAT(ArcSinh(Sinh(-10 * Degree)), AlmostEquals(-10 * Degree, 2));
  EXPECT_THAT(ArcCosh(Cosh(-10 * Degree)), AlmostEquals(10 * Degree, 20));
  EXPECT_THAT(ArcTanh(Tanh(-10 * Degree)), AlmostEquals(-10 * Degree, 1));
}

TEST_F(QuantitiesTest, ExpLogAndSqrt) {
  EXPECT_EQ(Exp(1), e);
  EXPECT_THAT(Exp(Log(4.2) + Log(1.729)), AlmostEquals(4.2 * 1.729, 1));
  EXPECT_EQ(Exp(Log(2) * Log2(1.729)), 1.729);
  EXPECT_EQ(Exp(Log(10) * Log10(1.729)), 1.729);
  EXPECT_THAT(Exp(Log(2) / 2), AlmostEquals(Sqrt(2), 1));
  EXPECT_EQ(Exp(Log(Rood / Foot.Pow<2>()) / 2) * Foot, Sqrt(Rood));
}

}  // namespace geometry
}  // namespace principia
<commit_msg>Unneeded Dimensionless<commit_after>
#include <string>

#include "glog/logging.h"
#include "gtest/gtest.h"
#include "quantities/astronomy.hpp"
#include "quantities/BIPM.hpp"
#include "quantities/constants.hpp"
#include "quantities/dimensionless.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "quantities/uk.hpp"
#include "testing_utilities/algebra.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/explicit_operators.hpp"
#include "testing_utilities/numerics.hpp"

using principia::astronomy::EarthMass;
using principia::astronomy::JulianYear;
using principia::astronomy::JupiterMass;
using principia::astronomy::LightYear;
using principia::astronomy::LunarDistance;
using principia::astronomy::Parsec;
using principia::astronomy::SolarMass;
using principia::constants::ElectronMass;
using principia::constants::GravitationalConstant;
using principia::constants::SpeedOfLight;
using principia::constants::StandardGravity;
using principia::constants::VacuumPermeability;
using principia::constants::VacuumPermittivity;
using principia::quantities::Abs;
using principia::quantities::Cos;
using principia::quantities::Dimensionless;
using principia::quantities::Exp;
using principia::quantities::Log;
using principia::quantities::Log10;
using principia::quantities::Log2;
using principia::quantities::Mass;
using principia::quantities::Product;
using principia::quantities::Sin;
using principia::quantities::Speed;
using principia::quantities::Sqrt;
using principia::si::Ampere;
using principia::si::AstronomicalUnit;
using principia::si::Candela;
using principia::si::Cycle;
using principia::si::Day;
using principia::si::Degree;
using principia::si::Hour;
using principia::si::Kelvin;
using principia::si::Kilogram;
using principia::si::Mega;
using principia::si::Metre;
using principia::si::Mole;
using principia::si::Radian;
using principia::si::Second;
using principia::si::Steradian;
using principia::testing_utilities::AbsoluteError;
using principia::testing_utilities::AlmostEquals;
using principia::testing_utilities::RelativeError;
using principia::testing_utilities::Times;
using principia::uk::Foot;
using principia::uk::Furlong;
using principia::uk::Mile;
using principia::uk::Rood;
using testing::Lt;

namespace principia {
namespace geometry {

class QuantitiesTest : public testing::Test {
 protected:
};

TEST_F(QuantitiesTest, AbsoluteValue) {
  EXPECT_EQ(Abs(-1729), 1729);
  EXPECT_EQ(Abs(1729), 1729);
}

TEST_F(QuantitiesTest, DimensionlessComparisons) {
  testing_utilities::TestOrder(Dimensionless(0), Dimensionless(1));
  testing_utilities::TestOrder(Dimensionless(-1), Dimensionless(0));
  testing_utilities::TestOrder(-e, e);
  testing_utilities::TestOrder(Dimensionless(3), π);
  testing_utilities::TestOrder(Dimensionless(42), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionfulComparisons) {
  testing_utilities::TestOrder(EarthMass, JupiterMass);
  testing_utilities::TestOrder(LightYear, Parsec);
  testing_utilities::TestOrder(-SpeedOfLight, SpeedOfLight);
  testing_utilities::TestOrder(SpeedOfLight * Day, LightYear);
}

TEST_F(QuantitiesTest, DimensionlessOperations) {
  Dimensionless const zero    = 0;
  Dimensionless const one     = 1;
  Dimensionless const taxi    = 1729;
  Dimensionless const answer  = 42;
  Dimensionless const heegner = 163;
  testing_utilities::TestField(
      zero, one, taxi, 4 * π / 3, heegner, answer, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlfulOperations) {
  Dimensionless const zero = 0;
  Dimensionless const one = 1;
  Dimensionless const taxi = 1729;
  testing_utilities::TestVectorSpace(
      0 * Metre / Second, SpeedOfLight, 88 * Mile / Hour,
      -340.29 * Metre / Second, zero, one, -2 * π, taxi, 2);
  // Dimensionful multiplication is a tensor product, see [Tao 2012].
  testing_utilities::TestBilinearMap(
      Times<Product<Mass, Speed>, Mass, Speed>, SolarMass,
      ElectronMass, SpeedOfLight, 1 * Furlong / JulianYear, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlessExponentiation) {
  Dimensionless const number   = π - 42;
  Dimensionless positivePowers = 1;
  Dimensionless negativePowers = 1;
  EXPECT_EQ(1, number.Pow<0>());
  for (int i = 1; i < 10; ++i) {
    positivePowers *= number;
    negativePowers /= number;
    EXPECT_THAT(number.Pow(i), AlmostEquals(positivePowers, i));
    EXPECT_THAT(number.Pow(-i), AlmostEquals(negativePowers, i));
  }
}

// The Greek letters cause a warning when stringified by the macros, because
// apparently Visual Studio doesn't encode strings in UTF-8 by default.
#pragma warning(disable: 4566)

TEST_F(QuantitiesTest, Formatting) {
  auto const allTheUnits = 1 * Metre * Kilogram * Second * Ampere * Kelvin /
                            (Mole * Candela * Cycle * Radian * Steradian);
  std::string const expected = std::string("1e+000 m kg s A K mol^-1") +
                                " cd^-1 cycle^-1 rad^-1 sr^-1";
  std::string const actual = ToString(allTheUnits, 0);
  EXPECT_EQ(expected, actual);
  std::string π16 = "3.1415926535897931e+000";
  EXPECT_EQ(ToString(π), π16);
}

TEST_F(QuantitiesTest, PhysicalConstants) {
  // By definition.
  EXPECT_THAT(1 / SpeedOfLight.Pow<2>(),
              AlmostEquals(VacuumPermittivity * VacuumPermeability, 2));
  // The Keplerian approximation for the mass of the Sun
  // is fairly accurate.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * AstronomicalUnit.Pow<3>() /
                      (GravitationalConstant * JulianYear.Pow<2>()),
                  SolarMass),
              Lt(4E-5));
  EXPECT_THAT(RelativeError(1 * Parsec, 3.26156 * LightYear), Lt(2E-6));
  // The Keplerian approximation for the mass of the Earth
  // is pretty bad, but the error is still only 1%.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * LunarDistance.Pow<3>() /
                      (GravitationalConstant * (27.321582 * Day).Pow<2>()),
                  EarthMass),
              Lt(1E-2));
  EXPECT_THAT(RelativeError(1 * SolarMass, 1047 * JupiterMass), Lt(4E-4));
  // Delambre & Méchain.
  EXPECT_THAT(RelativeError(
                  GravitationalConstant * EarthMass /
                      (40 * Mega(Metre) / (2 * π)).Pow<2>(),
                  StandardGravity),
              Lt(4E-3));
  // Talleyrand.
  EXPECT_THAT(RelativeError(π * Sqrt(1 * Metre / StandardGravity), 1 * Second),
              Lt(4E-3));
}

#pragma warning(default: 4566)

TEST_F(QuantitiesTest, TrigonometricFunctions) {
  EXPECT_EQ(Cos(0 * Degree), 1);
  EXPECT_EQ(Sin(0 * Degree), 0);
  EXPECT_THAT(AbsoluteError(Cos(90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(90 * Degree), 1);
  EXPECT_EQ(Cos(180 * Degree), -1);
  EXPECT_THAT(AbsoluteError(Sin(180 * Degree), 0), Lt(1E-15));
  EXPECT_THAT(AbsoluteError(Cos(-90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(-90 * Degree), -1);
  for (int k = 1; k < 360; ++k) {
    // Don't test for multiples of 90 degrees as zeros lead to horrible
    // conditioning.
    if (k % 90 != 0) {
      EXPECT_THAT(Cos((90 - k) * Degree),
                  AlmostEquals(Sin(k * Degree), 50));
      EXPECT_THAT(Sin(k * Degree) / Cos(k * Degree),
                  AlmostEquals(Tan(k * Degree), 2));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree), Cos(k * Degree)), 80));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree) * AstronomicalUnit,
                                      Cos(k * Degree) * AstronomicalUnit), 80));
      EXPECT_THAT(Cos(ArcCos(Cos(k * Degree))),
                  AlmostEquals(Cos(k * Degree), 10));
      EXPECT_THAT(Sin(ArcSin(Sin(k * Degree))),
                  AlmostEquals(Sin(k * Degree), 1));
    }
  }
  // Horribly conditioned near 0, so not in the loop above.
  EXPECT_EQ(Tan(ArcTan(Tan(-42 * Degree))), Tan(-42 * Degree));
}

TEST_F(QuantitiesTest, HyperbolicFunctions) {
  EXPECT_EQ(Sinh(0 * Radian), 0);
  EXPECT_EQ(Cosh(0 * Radian), 1);
  EXPECT_EQ(Tanh(0 * Radian), 0);
  // Limits:
  EXPECT_EQ(Sinh(20 * Radian), Cosh(20 * Radian));
  EXPECT_EQ(Tanh(20 * Radian), 1);
  EXPECT_EQ(Sinh(-20 * Radian), -Cosh(-20 * Radian));
  EXPECT_EQ(Tanh(-20 * Radian), -1);

  EXPECT_EQ(Sinh(2 * Radian) / Cosh(2 * Radian), Tanh(2 * Radian));
  EXPECT_THAT(ArcSinh(Sinh(-10 * Degree)), AlmostEquals(-10 * Degree, 2));
  EXPECT_THAT(ArcCosh(Cosh(-10 * Degree)), AlmostEquals(10 * Degree, 20));
  EXPECT_THAT(ArcTanh(Tanh(-10 * Degree)), AlmostEquals(-10 * Degree, 1));
}

TEST_F(QuantitiesTest, ExpLogAndSqrt) {
  EXPECT_EQ(Exp(1), e);
  EXPECT_THAT(Exp(Log(4.2) + Log(1.729)), AlmostEquals(4.2 * 1.729, 1));
  EXPECT_EQ(Exp(Log(2) * Log2(1.729)), 1.729);
  EXPECT_EQ(Exp(Log(10) * Log10(1.729)), 1.729);
  EXPECT_THAT(Exp(Log(2) / 2), AlmostEquals(Sqrt(2), 1));
  EXPECT_EQ(Exp(Log(Rood / Foot.Pow<2>()) / 2) * Foot, Sqrt(Rood));
}

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


<commit_before>#include <string>

#include "glog/logging.h"
#include "gtest/gtest.h"
#include "quantities/astronomy.hpp"
#include "quantities/BIPM.hpp"
#include "quantities/constants.hpp"
#include "quantities/dimensionless.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "quantities/uk.hpp"
#include "testing_utilities/algebra.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/explicit_operators.hpp"
#include "testing_utilities/numerics.hpp"

using principia::astronomy::EarthMass;
using principia::astronomy::JulianYear;
using principia::astronomy::JupiterMass;
using principia::astronomy::LightYear;
using principia::astronomy::LunarDistance;
using principia::astronomy::Parsec;
using principia::astronomy::SolarMass;
using principia::constants::ElectronMass;
using principia::constants::GravitationalConstant;
using principia::constants::SpeedOfLight;
using principia::constants::StandardGravity;
using principia::constants::VacuumPermeability;
using principia::constants::VacuumPermittivity;
using principia::quantities::Abs;
using principia::quantities::Cos;
using principia::quantities::Dimensionless;
using principia::quantities::Exp;
using principia::quantities::Log;
using principia::quantities::Log10;
using principia::quantities::Log2;
using principia::quantities::Mass;
using principia::quantities::Product;
using principia::quantities::Sin;
using principia::quantities::Speed;
using principia::quantities::Sqrt;
using principia::si::Ampere;
using principia::si::AstronomicalUnit;
using principia::si::Candela;
using principia::si::Cycle;
using principia::si::Day;
using principia::si::Degree;
using principia::si::Hour;
using principia::si::Kelvin;
using principia::si::Kilogram;
using principia::si::Mega;
using principia::si::Metre;
using principia::si::Mole;
using principia::si::Radian;
using principia::si::Second;
using principia::si::Steradian;
using principia::testing_utilities::AbsoluteError;
using principia::testing_utilities::AlmostEquals;
using principia::testing_utilities::RelativeError;
using principia::testing_utilities::Times;
using principia::uk::Foot;
using principia::uk::Furlong;
using principia::uk::Mile;
using principia::uk::Rood;
using testing::Lt;

namespace principia {
namespace geometry {

class QuantitiesTest : public testing::Test {
 protected:
};

TEST_F(QuantitiesTest, AbsoluteValue) {
  EXPECT_EQ(Abs(-1729), Dimensionless(1729));
  EXPECT_EQ(Abs(1729), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionlessComparisons) {
  testing_utilities::TestOrder(Dimensionless(0), Dimensionless(1));
  testing_utilities::TestOrder(Dimensionless(-1), Dimensionless(0));
  testing_utilities::TestOrder(-e, e);
  testing_utilities::TestOrder(Dimensionless(3), π);
  testing_utilities::TestOrder(Dimensionless(42), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionfulComparisons) {
  testing_utilities::TestOrder(EarthMass, JupiterMass);
  testing_utilities::TestOrder(LightYear, Parsec);
  testing_utilities::TestOrder(-SpeedOfLight, SpeedOfLight);
  testing_utilities::TestOrder(SpeedOfLight * Day, LightYear);
}

TEST_F(QuantitiesTest, DimensionlessOperations) {
  Dimensionless const zero    = 0;
  Dimensionless const one     = 1;
  Dimensionless const taxi    = 1729;
  Dimensionless const answer  = 42;
  Dimensionless const heegner = 163;
  testing_utilities::TestField(
      zero, one, taxi, 4 * π / 3, heegner, answer, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlfulOperations) {
  Dimensionless const zero = 0;
  Dimensionless const one = 1;
  Dimensionless const taxi = 1729;
  testing_utilities::TestVectorSpace(
      0 * Metre / Second, SpeedOfLight, 88 * Mile / Hour,
      -340.29 * Metre / Second, zero, one, -2 * π, taxi, 2);
  // Dimensionful multiplication is a tensor product, see [Tao 2012].
  testing_utilities::TestBilinearMap(
      Times<Product<Mass, Speed>, Mass, Speed>, SolarMass,
      ElectronMass, SpeedOfLight, 1 * Furlong / JulianYear, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlessExponentiation) {
  Dimensionless const number   = π - 42;
  Dimensionless positivePowers = 1;
  Dimensionless negativePowers = 1;
  EXPECT_EQ(Dimensionless(1), number.Pow<0>());
  for (int i = 1; i < 10; ++i) {
    positivePowers *= number;
    negativePowers /= number;
    EXPECT_THAT(number.Pow(i), AlmostEquals(positivePowers, i));
    EXPECT_THAT(number.Pow(-i), AlmostEquals(negativePowers, i));
  }
}

// The Greek letters cause a warning when stringified by the macros, because
// apparently Visual Studio doesn't encode strings in UTF-8 by default.
#pragma warning(disable: 4566)

TEST_F(QuantitiesTest, Formatting) {
  auto const allTheUnits = 1 * Metre * Kilogram * Second * Ampere * Kelvin /
                            (Mole * Candela * Cycle * Radian * Steradian);
  std::string const expected = std::string("1e+000 m kg s A K mol^-1") +
                                " cd^-1 cycle^-1 rad^-1 sr^-1";
  std::string const actual = ToString(allTheUnits, 0);
  EXPECT_EQ(expected, actual);
  std::string π16 = "3.1415926535897931e+000";
  EXPECT_EQ(ToString(π), π16);
}

TEST_F(QuantitiesTest, PhysicalConstants) {
  // By definition.
  EXPECT_THAT(1 / SpeedOfLight.Pow<2>(),
              AlmostEquals(VacuumPermittivity * VacuumPermeability, 2));
  // The Keplerian approximation for the mass of the Sun
  // is fairly accurate.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * AstronomicalUnit.Pow<3>() /
                      (GravitationalConstant * JulianYear.Pow<2>()),
                  SolarMass),
              Lt(4E-5));
  EXPECT_THAT(RelativeError(1 * Parsec, 3.26156 * LightYear), Lt(2E-6));
  // The Keplerian approximation for the mass of the Earth
  // is pretty bad, but the error is still only 1%.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * LunarDistance.Pow<3>() /
                      (GravitationalConstant * (27.321582 * Day).Pow<2>()),
                  EarthMass),
              Lt(1E-2));
  EXPECT_THAT(RelativeError(1 * SolarMass, 1047 * JupiterMass), Lt(4E-4));
  // Delambre & Méchain.
  EXPECT_THAT(RelativeError(
                  GravitationalConstant * EarthMass /
                      (40 * Mega(Metre) / (2 * π)).Pow<2>(),
                  StandardGravity),
              Lt(4E-3));
  // Talleyrand.
  EXPECT_THAT(RelativeError(π * Sqrt(1 * Metre / StandardGravity), 1 * Second),
              Lt(4E-3));
}

#pragma warning(default: 4566)

TEST_F(QuantitiesTest, TrigonometricFunctions) {
  EXPECT_EQ(Cos(0 * Degree), 1);
  EXPECT_EQ(Sin(0 * Degree), 0);
  EXPECT_THAT(AbsoluteError(Cos(90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(90 * Degree), 1);
  EXPECT_EQ(Cos(180 * Degree), -1);
  EXPECT_THAT(AbsoluteError(Sin(180 * Degree), 0), Lt(1E-15));
  EXPECT_THAT(AbsoluteError(Cos(-90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(-90 * Degree), -1);
  for (int k = 1; k < 360; ++k) {
    // Don't test for multiples of 90 degrees as zeros lead to horrible
    // conditioning.
    if (k % 90 != 0) {
      EXPECT_THAT(Cos((90 - k) * Degree),
                  AlmostEquals(Sin(k * Degree), 50));
      EXPECT_THAT(Sin(k * Degree) / Cos(k * Degree),
                  AlmostEquals(Tan(k * Degree), 2));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree), Cos(k * Degree)), 80));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree) * AstronomicalUnit,
                                      Cos(k * Degree) * AstronomicalUnit), 80));
      EXPECT_THAT(Cos(ArcCos(Cos(k * Degree))),
                  AlmostEquals(Cos(k * Degree), 10));
      EXPECT_THAT(Sin(ArcSin(Sin(k * Degree))),
                  AlmostEquals(Sin(k * Degree), 1));
    }
  }
  // Horribly conditioned near 0, so not in the loop above.
  EXPECT_EQ(Tan(ArcTan(Tan(-42 * Degree))), Tan(-42 * Degree));
}

TEST_F(QuantitiesTest, HyperbolicFunctions) {
  EXPECT_EQ(Sinh(0 * Radian), 0);
  EXPECT_EQ(Cosh(0 * Radian), 1);
  EXPECT_EQ(Tanh(0 * Radian), 0);
  // Limits:
  EXPECT_EQ(Sinh(20 * Radian), Cosh(20 * Radian));
  EXPECT_EQ(Tanh(20 * Radian), 1);
  EXPECT_EQ(Sinh(-20 * Radian), -Cosh(-20 * Radian));
  EXPECT_EQ(Tanh(-20 * Radian), -1);

  EXPECT_EQ(Sinh(2 * Radian) / Cosh(2 * Radian), Tanh(2 * Radian));
  EXPECT_THAT(ArcSinh(Sinh(-10 * Degree)), AlmostEquals(-10 * Degree, 2));
  EXPECT_THAT(ArcCosh(Cosh(-10 * Degree)), AlmostEquals(10 * Degree, 20));
  EXPECT_THAT(ArcTanh(Tanh(-10 * Degree)), AlmostEquals(-10 * Degree, 1));
}

TEST_F(QuantitiesTest, ExpLogAndSqrt) {
  EXPECT_EQ(Exp(1), e);
  EXPECT_THAT(Exp(Log(4.2) + Log(1.729)), AlmostEquals(4.2 * 1.729, 1));
  EXPECT_EQ(Exp(Log(2) * Log2(1.729)), 1.729);
  EXPECT_EQ(Exp(Log(10) * Log10(1.729)), 1.729);
  EXPECT_THAT(Exp(Log(2) / 2), AlmostEquals(Sqrt(2), 1));
  EXPECT_EQ(Exp(Log(Rood / Foot.Pow<2>()) / 2) * Foot, Sqrt(Rood));
}

}  // namespace geometry
}  // namespace principia
<commit_msg>See if an empty line at the beginning helps the linter<commit_after>
#include <string>

#include "glog/logging.h"
#include "gtest/gtest.h"
#include "quantities/astronomy.hpp"
#include "quantities/BIPM.hpp"
#include "quantities/constants.hpp"
#include "quantities/dimensionless.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "quantities/uk.hpp"
#include "testing_utilities/algebra.hpp"
#include "testing_utilities/almost_equals.hpp"
#include "testing_utilities/explicit_operators.hpp"
#include "testing_utilities/numerics.hpp"

using principia::astronomy::EarthMass;
using principia::astronomy::JulianYear;
using principia::astronomy::JupiterMass;
using principia::astronomy::LightYear;
using principia::astronomy::LunarDistance;
using principia::astronomy::Parsec;
using principia::astronomy::SolarMass;
using principia::constants::ElectronMass;
using principia::constants::GravitationalConstant;
using principia::constants::SpeedOfLight;
using principia::constants::StandardGravity;
using principia::constants::VacuumPermeability;
using principia::constants::VacuumPermittivity;
using principia::quantities::Abs;
using principia::quantities::Cos;
using principia::quantities::Dimensionless;
using principia::quantities::Exp;
using principia::quantities::Log;
using principia::quantities::Log10;
using principia::quantities::Log2;
using principia::quantities::Mass;
using principia::quantities::Product;
using principia::quantities::Sin;
using principia::quantities::Speed;
using principia::quantities::Sqrt;
using principia::si::Ampere;
using principia::si::AstronomicalUnit;
using principia::si::Candela;
using principia::si::Cycle;
using principia::si::Day;
using principia::si::Degree;
using principia::si::Hour;
using principia::si::Kelvin;
using principia::si::Kilogram;
using principia::si::Mega;
using principia::si::Metre;
using principia::si::Mole;
using principia::si::Radian;
using principia::si::Second;
using principia::si::Steradian;
using principia::testing_utilities::AbsoluteError;
using principia::testing_utilities::AlmostEquals;
using principia::testing_utilities::RelativeError;
using principia::testing_utilities::Times;
using principia::uk::Foot;
using principia::uk::Furlong;
using principia::uk::Mile;
using principia::uk::Rood;
using testing::Lt;

namespace principia {
namespace geometry {

class QuantitiesTest : public testing::Test {
 protected:
};

TEST_F(QuantitiesTest, AbsoluteValue) {
  EXPECT_EQ(Abs(-1729), Dimensionless(1729));
  EXPECT_EQ(Abs(1729), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionlessComparisons) {
  testing_utilities::TestOrder(Dimensionless(0), Dimensionless(1));
  testing_utilities::TestOrder(Dimensionless(-1), Dimensionless(0));
  testing_utilities::TestOrder(-e, e);
  testing_utilities::TestOrder(Dimensionless(3), π);
  testing_utilities::TestOrder(Dimensionless(42), Dimensionless(1729));
}

TEST_F(QuantitiesTest, DimensionfulComparisons) {
  testing_utilities::TestOrder(EarthMass, JupiterMass);
  testing_utilities::TestOrder(LightYear, Parsec);
  testing_utilities::TestOrder(-SpeedOfLight, SpeedOfLight);
  testing_utilities::TestOrder(SpeedOfLight * Day, LightYear);
}

TEST_F(QuantitiesTest, DimensionlessOperations) {
  Dimensionless const zero    = 0;
  Dimensionless const one     = 1;
  Dimensionless const taxi    = 1729;
  Dimensionless const answer  = 42;
  Dimensionless const heegner = 163;
  testing_utilities::TestField(
      zero, one, taxi, 4 * π / 3, heegner, answer, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlfulOperations) {
  Dimensionless const zero = 0;
  Dimensionless const one = 1;
  Dimensionless const taxi = 1729;
  testing_utilities::TestVectorSpace(
      0 * Metre / Second, SpeedOfLight, 88 * Mile / Hour,
      -340.29 * Metre / Second, zero, one, -2 * π, taxi, 2);
  // Dimensionful multiplication is a tensor product, see [Tao 2012].
  testing_utilities::TestBilinearMap(
      Times<Product<Mass, Speed>, Mass, Speed>, SolarMass,
      ElectronMass, SpeedOfLight, 1 * Furlong / JulianYear, -e, 2);
}

TEST_F(QuantitiesTest, DimensionlessExponentiation) {
  Dimensionless const number   = π - 42;
  Dimensionless positivePowers = 1;
  Dimensionless negativePowers = 1;
  EXPECT_EQ(Dimensionless(1), number.Pow<0>());
  for (int i = 1; i < 10; ++i) {
    positivePowers *= number;
    negativePowers /= number;
    EXPECT_THAT(number.Pow(i), AlmostEquals(positivePowers, i));
    EXPECT_THAT(number.Pow(-i), AlmostEquals(negativePowers, i));
  }
}

// The Greek letters cause a warning when stringified by the macros, because
// apparently Visual Studio doesn't encode strings in UTF-8 by default.
#pragma warning(disable: 4566)

TEST_F(QuantitiesTest, Formatting) {
  auto const allTheUnits = 1 * Metre * Kilogram * Second * Ampere * Kelvin /
                            (Mole * Candela * Cycle * Radian * Steradian);
  std::string const expected = std::string("1e+000 m kg s A K mol^-1") +
                                " cd^-1 cycle^-1 rad^-1 sr^-1";
  std::string const actual = ToString(allTheUnits, 0);
  EXPECT_EQ(expected, actual);
  std::string π16 = "3.1415926535897931e+000";
  EXPECT_EQ(ToString(π), π16);
}

TEST_F(QuantitiesTest, PhysicalConstants) {
  // By definition.
  EXPECT_THAT(1 / SpeedOfLight.Pow<2>(),
              AlmostEquals(VacuumPermittivity * VacuumPermeability, 2));
  // The Keplerian approximation for the mass of the Sun
  // is fairly accurate.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * AstronomicalUnit.Pow<3>() /
                      (GravitationalConstant * JulianYear.Pow<2>()),
                  SolarMass),
              Lt(4E-5));
  EXPECT_THAT(RelativeError(1 * Parsec, 3.26156 * LightYear), Lt(2E-6));
  // The Keplerian approximation for the mass of the Earth
  // is pretty bad, but the error is still only 1%.
  EXPECT_THAT(RelativeError(
                  4 * π.Pow<2>() * LunarDistance.Pow<3>() /
                      (GravitationalConstant * (27.321582 * Day).Pow<2>()),
                  EarthMass),
              Lt(1E-2));
  EXPECT_THAT(RelativeError(1 * SolarMass, 1047 * JupiterMass), Lt(4E-4));
  // Delambre & Méchain.
  EXPECT_THAT(RelativeError(
                  GravitationalConstant * EarthMass /
                      (40 * Mega(Metre) / (2 * π)).Pow<2>(),
                  StandardGravity),
              Lt(4E-3));
  // Talleyrand.
  EXPECT_THAT(RelativeError(π * Sqrt(1 * Metre / StandardGravity), 1 * Second),
              Lt(4E-3));
}

#pragma warning(default: 4566)

TEST_F(QuantitiesTest, TrigonometricFunctions) {
  EXPECT_EQ(Cos(0 * Degree), 1);
  EXPECT_EQ(Sin(0 * Degree), 0);
  EXPECT_THAT(AbsoluteError(Cos(90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(90 * Degree), 1);
  EXPECT_EQ(Cos(180 * Degree), -1);
  EXPECT_THAT(AbsoluteError(Sin(180 * Degree), 0), Lt(1E-15));
  EXPECT_THAT(AbsoluteError(Cos(-90 * Degree), 0), Lt(1E-16));
  EXPECT_EQ(Sin(-90 * Degree), -1);
  for (int k = 1; k < 360; ++k) {
    // Don't test for multiples of 90 degrees as zeros lead to horrible
    // conditioning.
    if (k % 90 != 0) {
      EXPECT_THAT(Cos((90 - k) * Degree),
                  AlmostEquals(Sin(k * Degree), 50));
      EXPECT_THAT(Sin(k * Degree) / Cos(k * Degree),
                  AlmostEquals(Tan(k * Degree), 2));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree), Cos(k * Degree)), 80));
      EXPECT_THAT(((k + 179) % 360 - 179) * Degree,
                  AlmostEquals(ArcTan(Sin(k * Degree) * AstronomicalUnit,
                                      Cos(k * Degree) * AstronomicalUnit), 80));
      EXPECT_THAT(Cos(ArcCos(Cos(k * Degree))),
                  AlmostEquals(Cos(k * Degree), 10));
      EXPECT_THAT(Sin(ArcSin(Sin(k * Degree))),
                  AlmostEquals(Sin(k * Degree), 1));
    }
  }
  // Horribly conditioned near 0, so not in the loop above.
  EXPECT_EQ(Tan(ArcTan(Tan(-42 * Degree))), Tan(-42 * Degree));
}

TEST_F(QuantitiesTest, HyperbolicFunctions) {
  EXPECT_EQ(Sinh(0 * Radian), 0);
  EXPECT_EQ(Cosh(0 * Radian), 1);
  EXPECT_EQ(Tanh(0 * Radian), 0);
  // Limits:
  EXPECT_EQ(Sinh(20 * Radian), Cosh(20 * Radian));
  EXPECT_EQ(Tanh(20 * Radian), 1);
  EXPECT_EQ(Sinh(-20 * Radian), -Cosh(-20 * Radian));
  EXPECT_EQ(Tanh(-20 * Radian), -1);

  EXPECT_EQ(Sinh(2 * Radian) / Cosh(2 * Radian), Tanh(2 * Radian));
  EXPECT_THAT(ArcSinh(Sinh(-10 * Degree)), AlmostEquals(-10 * Degree, 2));
  EXPECT_THAT(ArcCosh(Cosh(-10 * Degree)), AlmostEquals(10 * Degree, 20));
  EXPECT_THAT(ArcTanh(Tanh(-10 * Degree)), AlmostEquals(-10 * Degree, 1));
}

TEST_F(QuantitiesTest, ExpLogAndSqrt) {
  EXPECT_EQ(Exp(1), e);
  EXPECT_THAT(Exp(Log(4.2) + Log(1.729)), AlmostEquals(4.2 * 1.729, 1));
  EXPECT_EQ(Exp(Log(2) * Log2(1.729)), 1.729);
  EXPECT_EQ(Exp(Log(10) * Log10(1.729)), 1.729);
  EXPECT_THAT(Exp(Log(2) / 2), AlmostEquals(Sqrt(2), 1));
  EXPECT_EQ(Exp(Log(Rood / Foot.Pow<2>()) / 2) * Foot, Sqrt(Rood));
}

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


<commit_before>// bslmt_threadutil.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bslmt_threadutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bslmt_threadutil_cpp,"$Id$ $CSID$")

#include <bslma_allocator.h>
#include <bslma_default.h>
#include <bslma_managedptr.h>

#include <bsls_platform.h>

#include <bsl_cmath.h>

#include <bsl_c_limits.h>

namespace {
namespace u {

using namespace BloombergLP;

struct NamedFuncPtrRecord {
    // This 'struct' stores the information necessary to call the 'extern "C"'
    // function 'd_threadFunction' passing it 'void *' 'd_userData' after
    // a thread is created and named 'd_threadName'.

    // DATA
    bslmt_ThreadFunction  d_threadFunction;    // extern "C" func ptr
    void                 *d_userData;          // 'void *' to be passed to func
    bsl::string           d_threadName;        // thread name

  public:
    // CREATOR
    NamedFuncPtrRecord(bslmt_ThreadFunction      threadFunction,
                       void                     *userData,
                       const bslstl::StringRef&  threadName,
                       bslma::Allocator         *allocator)
    : d_threadFunction(threadFunction)
    , d_userData(userData)
    , d_threadName(threadName, allocator)
        // Create a 'NamedFuncPtrRecord' containing the specified
        // 'threadFunction', 'userData', and 'threadName', and using the
        // specified 'allocator' to supply memory.
    {
    }
};

}  // close namespace u
}  // close unnamed namespace

namespace BloombergLP {

extern "C"
void *bslmt_threadutil_namedFuncPtrThunk(void *arg)
    // C-linkage routine that allows us to call a C-style function and name the
    // thread, using information in the specified 'arg', which points to a
    // 'u::NamedFuncPtrRecord' that must be freed by this function.  The
    // behavior is undefined if the thread name is empty.
{
    u::NamedFuncPtrRecord *nfpr_p = static_cast<u::NamedFuncPtrRecord *>(arg);
    bslma::ManagedPtr<u::NamedFuncPtrRecord> guard(
                             nfpr_p,
                             nfpr_p->d_threadName.get_allocator().mechanism());

    BSLS_ASSERT(0 == nfpr_p->d_threadName.empty());     // This function should
                                                        // never be called
                                                        // unless the thread is
                                                        // named.
    bslmt::ThreadUtil::setThreadName(nfpr_p->d_threadName);

    return (*nfpr_p->d_threadFunction)(nfpr_p->d_userData);
}

                            // -----------------
                            // struct ThreadUtil
                            // -----------------

// CLASS METHODS
int bslmt::ThreadUtil::convertToSchedulingPriority(
               ThreadAttributes::SchedulingPolicy policy,
               double                             normalizedSchedulingPriority)
{
    BSLS_ASSERT_OPT((int) policy >= ThreadAttributes::e_SCHED_MIN);
    BSLS_ASSERT_OPT((int) policy <= ThreadAttributes::e_SCHED_MAX);

    BSLS_ASSERT_OPT(normalizedSchedulingPriority >= 0.0);
    BSLS_ASSERT_OPT(normalizedSchedulingPriority <= 1.0);

    const int minPri = getMinSchedulingPriority(policy);
    const int maxPri = getMaxSchedulingPriority(policy);

    if (minPri == ThreadAttributes::e_UNSET_PRIORITY ||
        maxPri == ThreadAttributes::e_UNSET_PRIORITY) {
        return ThreadAttributes::e_UNSET_PRIORITY;                    // RETURN
    }

#if !defined(BSLS_PLATFORM_OS_CYGWIN)
    double ret = (maxPri - minPri) * normalizedSchedulingPriority +
                                                                  minPri + 0.5;
#else
    // On Cygwin, a lower numerical value implies a higher thread priority:
    //   minSchedPriority = 15, maxSchedPriority = -14

    double ret = - ((minPri - maxPri) * normalizedSchedulingPriority - minPri)
                                                                         + 0.5;
#endif

    return static_cast<int>(bsl::floor(ret));
}

int bslmt::ThreadUtil::create(Handle                  *handle,
                              const ThreadAttributes&  attributes,
                              ThreadFunction           function,
                              void                    *userData)
{
    BSLS_ASSERT(handle);

    if (false == attributes.threadName().isEmpty()) {
        // Named thread.  Only 'createWithAllocator' can name threads.

        return createWithAllocator(handle,
                                   attributes,
                                   function,
                                   userData,
                                   bslma::Default::globalAllocator());// RETURN
    }

    // Unnamed thread.

    return Imp::create(handle, attributes, function, userData);
}

int bslmt::ThreadUtil::createWithAllocator(Handle                  *handle,
                                           const ThreadAttributes&  attributes,
                                           ThreadFunction           function,
                                           void                    *userData,
                                           bslma::Allocator        *allocator)
{
    BSLS_ASSERT(handle);
    BSLS_ASSERT_OPT(allocator);

    if (false == attributes.threadName().isEmpty()) {
        // Named thread.

        bslma::ManagedPtr<u::NamedFuncPtrRecord> nfpr_m(
                new (*allocator) u::NamedFuncPtrRecord(function,
                                                       userData,
                                                       attributes.threadName(),
                                                       allocator),
                allocator);

        int rc = Imp::create(handle,
                             attributes,
                             bslmt_threadutil_namedFuncPtrThunk,
                             nfpr_m.ptr());
        if (0 == rc) {
            nfpr_m.release();
        }

        return rc;                                                    // RETURN
    }

    // Unnamed thread.

    return Imp::create(handle, attributes, function, userData);
}

}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// 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.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>bslmt_threadutil: doc tweak<commit_after>// bslmt_threadutil.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bslmt_threadutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bslmt_threadutil_cpp,"$Id$ $CSID$")

#include <bslma_allocator.h>
#include <bslma_default.h>
#include <bslma_managedptr.h>

#include <bsls_platform.h>

#include <bsl_cmath.h>

#include <bsl_c_limits.h>

namespace {
namespace u {

// We can't just package a 'bslmt_ThreadFunction' and 'userData' into a simple
// functor and pass that to one of the inline 'createWithAllocator' template
// functions because the contract for threads created by calling with a
// "C"-style function requires the function to be able to return a 'void *'
// which the calling thread can access via 'join'.  The signature of the
// functor passed to the inline 'createWithAllocator' template functions,
// however, does not provide a way to return a value.

using namespace BloombergLP;

struct NamedFuncPtrRecord {
    // This 'struct' stores the information necessary to call the 'extern "C"'
    // function 'd_threadFunction' passing it 'void *' 'd_userData' after
    // a thread is created and named 'd_threadName'.

    // DATA
    bslmt_ThreadFunction  d_threadFunction;    // extern "C" func ptr
    void                 *d_userData;          // 'void *' to be passed to func
    bsl::string           d_threadName;        // thread name

  public:
    // CREATOR
    NamedFuncPtrRecord(bslmt_ThreadFunction      threadFunction,
                       void                     *userData,
                       const bslstl::StringRef&  threadName,
                       bslma::Allocator         *allocator)
    : d_threadFunction(threadFunction)
    , d_userData(userData)
    , d_threadName(threadName, allocator)
        // Create a 'NamedFuncPtrRecord' containing the specified
        // 'threadFunction', 'userData', and 'threadName', and using the
        // specified 'allocator' to supply memory.
    {
    }
};

}  // close namespace u
}  // close unnamed namespace

namespace BloombergLP {

extern "C"
void *bslmt_threadutil_namedFuncPtrThunk(void *arg)
    // C-linkage routine that allows us to call a C-style function and name the
    // thread, using information in the specified 'arg', which points to a
    // 'u::NamedFuncPtrRecord' that must be freed by this function.  The
    // behavior is undefined if the thread name is empty.
{
    u::NamedFuncPtrRecord *nfpr_p = static_cast<u::NamedFuncPtrRecord *>(arg);
    bslma::ManagedPtr<u::NamedFuncPtrRecord> guard(
                             nfpr_p,
                             nfpr_p->d_threadName.get_allocator().mechanism());

    BSLS_ASSERT(0 == nfpr_p->d_threadName.empty());     // This function should
                                                        // never be called
                                                        // unless the thread is
                                                        // named.
    bslmt::ThreadUtil::setThreadName(nfpr_p->d_threadName);

    return (*nfpr_p->d_threadFunction)(nfpr_p->d_userData);
}

                            // -----------------
                            // struct ThreadUtil
                            // -----------------

// CLASS METHODS
int bslmt::ThreadUtil::convertToSchedulingPriority(
               ThreadAttributes::SchedulingPolicy policy,
               double                             normalizedSchedulingPriority)
{
    BSLS_ASSERT_OPT((int) policy >= ThreadAttributes::e_SCHED_MIN);
    BSLS_ASSERT_OPT((int) policy <= ThreadAttributes::e_SCHED_MAX);

    BSLS_ASSERT_OPT(normalizedSchedulingPriority >= 0.0);
    BSLS_ASSERT_OPT(normalizedSchedulingPriority <= 1.0);

    const int minPri = getMinSchedulingPriority(policy);
    const int maxPri = getMaxSchedulingPriority(policy);

    if (minPri == ThreadAttributes::e_UNSET_PRIORITY ||
        maxPri == ThreadAttributes::e_UNSET_PRIORITY) {
        return ThreadAttributes::e_UNSET_PRIORITY;                    // RETURN
    }

#if !defined(BSLS_PLATFORM_OS_CYGWIN)
    double ret = (maxPri - minPri) * normalizedSchedulingPriority +
                                                                  minPri + 0.5;
#else
    // On Cygwin, a lower numerical value implies a higher thread priority:
    //   minSchedPriority = 15, maxSchedPriority = -14

    double ret = - ((minPri - maxPri) * normalizedSchedulingPriority - minPri)
                                                                         + 0.5;
#endif

    return static_cast<int>(bsl::floor(ret));
}

int bslmt::ThreadUtil::create(Handle                  *handle,
                              const ThreadAttributes&  attributes,
                              ThreadFunction           function,
                              void                    *userData)
{
    BSLS_ASSERT(handle);

    if (false == attributes.threadName().isEmpty()) {
        // Named thread.  Only 'createWithAllocator' can name threads.

        return createWithAllocator(handle,
                                   attributes,
                                   function,
                                   userData,
                                   bslma::Default::globalAllocator());// RETURN
    }

    // Unnamed thread.

    return Imp::create(handle, attributes, function, userData);
}

int bslmt::ThreadUtil::createWithAllocator(Handle                  *handle,
                                           const ThreadAttributes&  attributes,
                                           ThreadFunction           function,
                                           void                    *userData,
                                           bslma::Allocator        *allocator)
{
    BSLS_ASSERT(handle);
    BSLS_ASSERT_OPT(allocator);

    if (false == attributes.threadName().isEmpty()) {
        // Named thread.

        bslma::ManagedPtr<u::NamedFuncPtrRecord> nfpr_m(
                new (*allocator) u::NamedFuncPtrRecord(function,
                                                       userData,
                                                       attributes.threadName(),
                                                       allocator),
                allocator);

        int rc = Imp::create(handle,
                             attributes,
                             bslmt_threadutil_namedFuncPtrThunk,
                             nfpr_m.ptr());
        if (0 == rc) {
            nfpr_m.release();
        }

        return rc;                                                    // RETURN
    }

    // Unnamed thread.

    return Imp::create(handle, attributes, function, userData);
}

}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// 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.
// ----------------------------- END-OF-FILE ----------------------------------
<|endoftext|>


<commit_before>// set of classes to compare the performance of STL vector versus
// native Root TClonesArray.
// See main program bench.cxx

#include "TRandom.h"
#include "TFile.h"
#include "TTree.h"
#include "TClass.h"
//the next include must be the last one on systems like Windows/NT
#include "TBench.h"

THit hit;
char *demofile = "/tmp/bench.root";

//-------------------------------------------------------------
ClassImp(THit)
//-------------------------------------------------------------
THit::THit() {
  fPulses = 0;
}
THit::THit(const THit &hit) {
  fX = hit.fX;
  fY = hit.fY;
  fZ = hit.fZ;
  for (Int_t i=0;i<10;i++) fTime[i] = hit.fTime[i];
  fPulses = 0;
  fNpulses = hit.fNpulses;
  if (fNpulses == 0) return;
  if (hit.fPulses == 0) return;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = hit.fPulses[j];
}

THit::THit(int t) {
  fPulses = 0;
  Set(t);
}

THit::~THit() {
   if (fPulses) delete [] fPulses;
   fPulses = 0;
}

void THit::Set(int t) {
  fX = gRandom->Gaus(0,1);
  fY = gRandom->Gaus(0,1);
  fZ = gRandom->Gaus(0,10);
  if (fPulses && fNpulses > 0) delete [] fPulses;
  fNpulses = t%20 + 1;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = j+1;
  for (int i=0; i<10; i++) fTime[i] = t+i;
}

TBuffer &operator>>(TBuffer &buf, const THit *&obj)
{
   obj =  new THit();
   ((THit*)obj)->Streamer(buf);
   return buf;
}

TBuffer &operator<<(TBuffer &buf, const THit *obj)
{
   ((THit*)obj)->Streamer(buf);
   return buf;
}

//-------------------------------------------------------------
ClassImp(TObjHit)
//-------------------------------------------------------------

TObjHit::TObjHit() :THit() {}
TObjHit::TObjHit(int t) :THit(t) {}

//-------------------------------------------------------------
ClassImp(TSTLhit)
//-------------------------------------------------------------
TSTLhit::TSTLhit()
{
}

TSTLhit::TSTLhit(Int_t nmax)
{
   fNhits = nmax;
   fList1.reserve(nmax);
}

TSTLhit::~TSTLhit() {
}

void TSTLhit::Clear(Option_t *)
{
   fList1.erase(fList1.begin(),fList1.end());
}

void TSTLhit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      hit.Set(j);
      fList1.push_back(hit);
   }
}

Int_t TSTLhit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhit::ReadTree()
{
  TSTLhit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TSTLhitStar)
//-------------------------------------------------------------
TSTLhitStar::TSTLhitStar()
{
}

TSTLhitStar::TSTLhitStar(Int_t nmax)
{
   fNhits = nmax;
   fList2.reserve(nmax);
}

TSTLhitStar::~TSTLhitStar() {
}

void TSTLhitStar::Clear(Option_t *)
{
   for (vector<THit*>::iterator it = fList2.begin(); it<fList2.end(); it++) {
      delete (*it);
   }
   fList2.erase(fList2.begin(),fList2.end());
}

void TSTLhitStar::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      fList2.push_back(new THit(j));
   }
}

Int_t TSTLhitStar::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhitStar *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhitStar",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhitStar",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhitStar::ReadTree()
{
  TSTLhitStar *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TCloneshit)
//-------------------------------------------------------------
TCloneshit::TCloneshit()
{
   fList3 = new TClonesArray("TObjHit");
}

TCloneshit::TCloneshit(Int_t nmax)
{
   fNhits = nmax;
   fList3 = new TClonesArray("TObjHit",nmax);
   TObjHit::Class()->IgnoreTObjectStreamer();
}

TCloneshit::~TCloneshit() {
}

void TCloneshit::Clear(Option_t *)
{
   fList3->Delete();
   //fList3->Clear();
}

void TCloneshit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      new((*fList3)[j]) TObjHit(j);
   }
}

Int_t TCloneshit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TCloneshit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","Cloneshit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TCloneshit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TCloneshit::ReadTree()
{
  TCloneshit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
  }
  delete f;
  return nbytes;
}

<commit_msg>Declare const char* variable demofile<commit_after>// set of classes to compare the performance of STL vector versus
// native Root TClonesArray.
// See main program bench.cxx

#include "TRandom.h"
#include "TFile.h"
#include "TTree.h"
#include "TClass.h"
//the next include must be the last one on systems like Windows/NT
#include "TBench.h"

THit hit;
const char *demofile = "/tmp/bench.root";

//-------------------------------------------------------------
ClassImp(THit)
//-------------------------------------------------------------
THit::THit() {
  fPulses = 0;
}
THit::THit(const THit &hit) {
  fX = hit.fX;
  fY = hit.fY;
  fZ = hit.fZ;
  for (Int_t i=0;i<10;i++) fTime[i] = hit.fTime[i];
  fPulses = 0;
  fNpulses = hit.fNpulses;
  if (fNpulses == 0) return;
  if (hit.fPulses == 0) return;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = hit.fPulses[j];
}

THit::THit(int t) {
  fPulses = 0;
  Set(t);
}

THit::~THit() {
   if (fPulses) delete [] fPulses;
   fPulses = 0;
}

void THit::Set(int t) {
  fX = gRandom->Gaus(0,1);
  fY = gRandom->Gaus(0,1);
  fZ = gRandom->Gaus(0,10);
  if (fPulses && fNpulses > 0) delete [] fPulses;
  fNpulses = t%20 + 1;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = j+1;
  for (int i=0; i<10; i++) fTime[i] = t+i;
}

TBuffer &operator>>(TBuffer &buf, const THit *&obj)
{
   obj =  new THit();
   ((THit*)obj)->Streamer(buf);
   return buf;
}

TBuffer &operator<<(TBuffer &buf, const THit *obj)
{
   ((THit*)obj)->Streamer(buf);
   return buf;
}

//-------------------------------------------------------------
ClassImp(TObjHit)
//-------------------------------------------------------------

TObjHit::TObjHit() :THit() {}
TObjHit::TObjHit(int t) :THit(t) {}

//-------------------------------------------------------------
ClassImp(TSTLhit)
//-------------------------------------------------------------
TSTLhit::TSTLhit()
{
}

TSTLhit::TSTLhit(Int_t nmax)
{
   fNhits = nmax;
   fList1.reserve(nmax);
}

TSTLhit::~TSTLhit() {
}

void TSTLhit::Clear(Option_t *)
{
   fList1.erase(fList1.begin(),fList1.end());
}

void TSTLhit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      hit.Set(j);
      fList1.push_back(hit);
   }
}

Int_t TSTLhit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhit::ReadTree()
{
  TSTLhit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TSTLhitStar)
//-------------------------------------------------------------
TSTLhitStar::TSTLhitStar()
{
}

TSTLhitStar::TSTLhitStar(Int_t nmax)
{
   fNhits = nmax;
   fList2.reserve(nmax);
}

TSTLhitStar::~TSTLhitStar() {
}

void TSTLhitStar::Clear(Option_t *)
{
   for (vector<THit*>::iterator it = fList2.begin(); it<fList2.end(); it++) {
      delete (*it);
   }
   fList2.erase(fList2.begin(),fList2.end());
}

void TSTLhitStar::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      fList2.push_back(new THit(j));
   }
}

Int_t TSTLhitStar::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhitStar *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhitStar",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhitStar",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhitStar::ReadTree()
{
  TSTLhitStar *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TCloneshit)
//-------------------------------------------------------------
TCloneshit::TCloneshit()
{
   fList3 = new TClonesArray("TObjHit");
}

TCloneshit::TCloneshit(Int_t nmax)
{
   fNhits = nmax;
   fList3 = new TClonesArray("TObjHit",nmax);
   TObjHit::Class()->IgnoreTObjectStreamer();
}

TCloneshit::~TCloneshit() {
}

void TCloneshit::Clear(Option_t *)
{
   fList3->Delete();
   //fList3->Clear();
}

void TCloneshit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      new((*fList3)[j]) TObjHit(j);
   }
}

Int_t TCloneshit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TCloneshit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","Cloneshit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TCloneshit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TCloneshit::ReadTree()
{
  TCloneshit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
  }
  delete f;
  return nbytes;
}

<|endoftext|>