2020-10-02 11:06:06 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2019 Lawrence Livermore National Laboratory
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
|
* published by the Free Software Foundation;
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
*
|
|
|
|
|
* Author: Mathew Bielejeski <bielejeski1@llnl.gov>
|
|
|
|
|
*/
|
|
|
|
|
|
2021-12-21 17:06:57 +00:00
|
|
|
#include "ns3/length.h"
|
2020-10-02 11:06:06 -07:00
|
|
|
|
|
|
|
|
#include "ns3/log.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cctype>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <ratio>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \file
|
|
|
|
|
* \ingroup length
|
|
|
|
|
* ns3::Length implementation
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \ingroup length
|
|
|
|
|
* Unnamed namespace
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
namespace
|
|
|
|
|
{
|
2020-10-02 11:06:06 -07:00
|
|
|
/**
|
|
|
|
|
* Helper function to scale an input value by a given ratio
|
|
|
|
|
*
|
|
|
|
|
* \tparam R a std::ratio
|
|
|
|
|
*
|
|
|
|
|
* \param value Input value to scale by R
|
|
|
|
|
*
|
|
|
|
|
* \return The result of value * R::num / R::den
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
template <class R>
|
|
|
|
|
double
|
|
|
|
|
ScaleValue(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return (value * R::num) / static_cast<double>(R::den);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a value in feet to the equivalent value in meters
|
|
|
|
|
*
|
|
|
|
|
* \param value Input value in feet
|
|
|
|
|
*
|
|
|
|
|
* \return Equivalent value in meters
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
double
|
|
|
|
|
FootToMeter(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return value * 0.3048;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a value in meters to the equivalent value in feet
|
|
|
|
|
*
|
|
|
|
|
* \param value Input value in meters
|
|
|
|
|
*
|
|
|
|
|
* \return Equivalent value in feet
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
double
|
|
|
|
|
MeterToFoot(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return value * 3.28084;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a value from a US Customary unit (inches, feet, yards etc.) to meters
|
|
|
|
|
*
|
|
|
|
|
* Value is scaled to feet then converted to meters
|
|
|
|
|
*
|
|
|
|
|
* \tparam R std::ratio needed to convert value to feet
|
|
|
|
|
*
|
|
|
|
|
* \param value Input value in some US Customary unit
|
|
|
|
|
*
|
|
|
|
|
* \return Equivalent value in meters
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
template <class R>
|
|
|
|
|
double
|
|
|
|
|
USToMeter(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return FootToMeter(ScaleValue<R>(value));
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a value from meters to a US Customary unit (inches, feet, yards etc.)
|
|
|
|
|
*
|
|
|
|
|
* Value is converted to feet then scaled to the desired US Customary unit
|
|
|
|
|
*
|
|
|
|
|
* \tparam R std::ratio needed to convert feet to desired US customary unit
|
|
|
|
|
*
|
|
|
|
|
* \param value Input value in meters
|
|
|
|
|
*
|
|
|
|
|
* \return Equivalent value in a US customary unit
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
template <class R>
|
|
|
|
|
double
|
|
|
|
|
MeterToUS(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return ScaleValue<R>(MeterToFoot(value));
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a value in one unit to the equivalent value in another unit
|
|
|
|
|
*
|
|
|
|
|
* \param value Length value in \p fromUnit units
|
|
|
|
|
* \param fromUnit Unit of \p value
|
|
|
|
|
* \param toUnit Target unit
|
|
|
|
|
*
|
|
|
|
|
* \return Result of converting value from \p fromUnit to \p toUnit
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
double
|
|
|
|
|
Convert(double value, ns3::Length::Unit fromUnit, ns3::Length::Unit toUnit)
|
|
|
|
|
{
|
|
|
|
|
using Unit = ns3::Length::Unit;
|
|
|
|
|
using Key = std::pair<Unit, Unit>;
|
|
|
|
|
using Conversion = std::function<double(double)>;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Helper to generate hash values from pairs of Length::Units
|
|
|
|
|
*/
|
|
|
|
|
struct KeyHash
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
std::size_t operator()(const Key& key) const noexcept
|
|
|
|
|
{
|
|
|
|
|
static_assert(sizeof(Unit) < sizeof(std::size_t),
|
|
|
|
|
"sizeof(Length::Unit) changed, it must be less than "
|
|
|
|
|
"sizeof(std::size_t)");
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
int shift = sizeof(Unit) * 8;
|
|
|
|
|
return static_cast<std::size_t>(key.first) << shift |
|
|
|
|
|
static_cast<std::size_t>(key.second);
|
|
|
|
|
}
|
|
|
|
|
};
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
using ConversionTable = std::unordered_map<Key, Conversion, KeyHash>;
|
|
|
|
|
|
|
|
|
|
static ConversionTable CONVERSIONS{
|
|
|
|
|
{{Unit::Nanometer, Unit::Meter}, ScaleValue<std::nano>},
|
|
|
|
|
{{Unit::Meter, Unit::Nanometer}, ScaleValue<std::giga>},
|
|
|
|
|
{{Unit::Micrometer, Unit::Meter}, ScaleValue<std::micro>},
|
|
|
|
|
{{Unit::Meter, Unit::Micrometer}, ScaleValue<std::mega>},
|
|
|
|
|
{{Unit::Millimeter, Unit::Meter}, ScaleValue<std::milli>},
|
|
|
|
|
{{Unit::Meter, Unit::Millimeter}, ScaleValue<std::kilo>},
|
|
|
|
|
{{Unit::Centimeter, Unit::Meter}, ScaleValue<std::centi>},
|
|
|
|
|
{{Unit::Meter, Unit::Centimeter}, ScaleValue<std::hecto>},
|
|
|
|
|
{{Unit::Meter, Unit::Meter}, ScaleValue<std::ratio<1, 1>>},
|
|
|
|
|
{{Unit::Kilometer, Unit::Meter}, ScaleValue<std::kilo>},
|
|
|
|
|
{{Unit::Meter, Unit::Kilometer}, ScaleValue<std::milli>},
|
|
|
|
|
{{Unit::NauticalMile, Unit::Meter}, ScaleValue<std::ratio<1852, 1>>},
|
|
|
|
|
{{Unit::Meter, Unit::NauticalMile}, ScaleValue<std::ratio<1, 1852>>},
|
|
|
|
|
{{Unit::Inch, Unit::Meter}, USToMeter<std::ratio<1, 12>>},
|
|
|
|
|
{{Unit::Meter, Unit::Inch}, MeterToUS<std::ratio<12, 1>>},
|
|
|
|
|
{{Unit::Foot, Unit::Meter}, FootToMeter},
|
|
|
|
|
{{Unit::Meter, Unit::Foot}, MeterToFoot},
|
|
|
|
|
{{Unit::Yard, Unit::Meter}, USToMeter<std::ratio<3, 1>>},
|
|
|
|
|
{{Unit::Meter, Unit::Yard}, MeterToUS<std::ratio<1, 3>>},
|
|
|
|
|
{{Unit::Mile, Unit::Meter}, USToMeter<std::ratio<5280, 1>>},
|
2022-11-03 17:53:20 +00:00
|
|
|
{{Unit::Meter, Unit::Mile}, MeterToUS<std::ratio<1, 5280>>},
|
|
|
|
|
};
|
2022-10-07 20:08:35 +00:00
|
|
|
|
|
|
|
|
auto iter = CONVERSIONS.find(Key{fromUnit, toUnit});
|
|
|
|
|
|
|
|
|
|
if (iter == CONVERSIONS.end())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("No conversion defined for " << fromUnit << " -> " << toUnit);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return iter->second(value);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert a Length::Quantity to the equivalent value in another unit
|
|
|
|
|
*
|
|
|
|
|
* \param from Quantity with the current value and unit
|
|
|
|
|
* \param toUnit Target unit
|
|
|
|
|
*
|
|
|
|
|
* \return Result of converting the quantity value to the requested units
|
|
|
|
|
*/
|
2022-10-07 20:08:35 +00:00
|
|
|
double
|
|
|
|
|
Convert(const ns3::Length::Quantity& from, ns3::Length::Unit toUnit)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Convert(from.Value(), from.Unit(), toUnit);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Functor for hashing Length::Unit values
|
|
|
|
|
*
|
|
|
|
|
* This classes exists as a work around for a C++11 defect. c++11 doesn't provide
|
|
|
|
|
* a std::hash implementation for enums
|
|
|
|
|
*/
|
|
|
|
|
class EnumHash
|
|
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Produce a hash value for a Length::Unit
|
|
|
|
|
*
|
|
|
|
|
* \param u Length::Unit to hash
|
|
|
|
|
*
|
|
|
|
|
* \return Hash value for the Length::Unit
|
|
|
|
|
*/
|
|
|
|
|
std::size_t operator()(ns3::Length::Unit u) const noexcept
|
|
|
|
|
{
|
|
|
|
|
return static_cast<std::size_t>(u);
|
|
|
|
|
}
|
2020-10-02 11:06:06 -07:00
|
|
|
};
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
} // unnamed namespace
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
namespace ns3
|
|
|
|
|
{
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_COMPONENT_DEFINE("Length");
|
2020-10-02 11:06:06 -07:00
|
|
|
|
|
|
|
|
// Implement the attribute helper
|
2022-10-07 20:08:35 +00:00
|
|
|
ATTRIBUTE_HELPER_CPP(Length);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-05-14 08:45:04 -07:00
|
|
|
std::optional<Length>
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::TryParse(double value, const std::string& unitString)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(value << unitString);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
auto unit = FromString(unitString);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (unit.has_value())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, *unit);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return std::nullopt;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::Length()
|
|
|
|
|
: m_value(0)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::Length(const std::string& input)
|
|
|
|
|
: m_value(0)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << input);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
std::istringstream stream(input);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
stream >> *this;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::Length(double value, const std::string& unitString)
|
|
|
|
|
: m_value(0)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << value << unitString);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
auto unit = FromString(unitString);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (!unit.has_value())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("A Length object could not be constructed from the unit "
|
|
|
|
|
"string '"
|
|
|
|
|
<< unitString
|
|
|
|
|
<< "', because the string is not associated "
|
|
|
|
|
"with a Length::Unit entry");
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
m_value = Convert(value, *unit, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::Length(double value, Length::Unit unit)
|
|
|
|
|
: m_value(0)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << value << unit);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
m_value = Convert(value, unit, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::Length(Quantity quantity)
|
|
|
|
|
: Length(quantity.Value(), quantity.Unit())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << quantity);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length&
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::operator=(const Length::Quantity& q)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << q);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
m_value = Convert(q, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return *this;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::IsEqual(const Length& other, double tolerance /*=DEFAULT_TOLERANCE*/) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << m_value << other.m_value << tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (m_value == other.m_value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return true;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
auto diff = std::abs(m_value - other.m_value);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return diff <= tolerance;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::IsNotEqual(const Length& other, double tolerance /*=DEFAULT_TOLERANCE*/) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << m_value << other.m_value << tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return !IsEqual(other, tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::IsLess(const Length& other, double tolerance /*=DEFAULT_TOLERANCE*/) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << m_value << other.m_value << tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return m_value < other.m_value && IsNotEqual(other, tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::IsLessOrEqual(const Length& other, double tolerance /*=DEFAULT_TOLERANCE*/) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << m_value << other.m_value << tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return m_value < other.m_value || IsEqual(other, tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::IsGreater(const Length& other, double tolerance /*=DEFAULT_TOLERANCE*/) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << m_value << other.m_value << tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return !IsLessOrEqual(other, tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::IsGreaterOrEqual(const Length& other, double tolerance /*=DEFAULT_TOLERANCE*/) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << m_value << other.m_value << tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return !IsLess(other, tolerance);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::swap(Length& other)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
using std::swap;
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
swap(m_value, other.m_value);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::GetDouble() const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return m_value;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length::Quantity
|
2022-10-07 20:08:35 +00:00
|
|
|
Length::As(Length::Unit unit) const
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(this << unit);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
double value = Convert(m_value, Length::Unit::Meter, unit);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return Quantity(value, unit);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
operator==(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return left.GetDouble() == right.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
operator!=(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return left.GetDouble() != right.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
operator<(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return left.GetDouble() < right.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
operator<=(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return left.GetDouble() <= right.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
operator>(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return left.GetDouble() > right.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2022-10-07 20:08:35 +00:00
|
|
|
operator>=(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return left.GetDouble() >= right.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
operator+(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
double value = left.GetDouble() + right.GetDouble();
|
|
|
|
|
return Length(value, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
operator-(const Length& left, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
double value = left.GetDouble() - right.GetDouble();
|
|
|
|
|
return Length(value, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
operator*(const Length& left, double scalar)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
double value = left.GetDouble() * scalar;
|
|
|
|
|
return Length(value, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
operator*(double scalar, const Length& right)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return right * scalar;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
operator/(const Length& left, double scalar)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
if (scalar == 0)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("Attempted to divide Length by 0");
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return left * (1.0 / scalar);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
2022-10-07 20:08:35 +00:00
|
|
|
operator/(const Length& numerator, const Length& denominator)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
if (denominator.GetDouble() == 0)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return std::numeric_limits<double>::quiet_NaN();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return numerator.GetDouble() / denominator.GetDouble();
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t
|
2022-10-07 20:08:35 +00:00
|
|
|
Div(const Length& numerator, const Length& denominator, Length* remainder)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
double value = numerator / denominator;
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (std::isnan(value))
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("numerator / denominator return NaN");
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (remainder)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
double rem = std::fmod(numerator.GetDouble(), denominator.GetDouble());
|
|
|
|
|
*remainder = Length(rem, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return static_cast<int64_t>(std::trunc(value));
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
Mod(const Length& numerator, const Length& denominator)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
double rem = std::fmod(numerator.GetDouble(), denominator.GetDouble());
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (std::isnan(rem))
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("numerator / denominator return NaN");
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(rem, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2022-10-07 20:08:35 +00:00
|
|
|
ToSymbol(Length::Unit unit)
|
|
|
|
|
{
|
|
|
|
|
using StringTable = std::unordered_map<Length::Unit, std::string, EnumHash>;
|
|
|
|
|
|
2022-11-03 17:53:20 +00:00
|
|
|
static const StringTable STRINGS{
|
|
|
|
|
{Length::Unit::Nanometer, "nm"},
|
|
|
|
|
{Length::Unit::Micrometer, "um"},
|
|
|
|
|
{Length::Unit::Millimeter, "mm"},
|
|
|
|
|
{Length::Unit::Centimeter, "cm"},
|
|
|
|
|
{Length::Unit::Meter, "m"},
|
|
|
|
|
{Length::Unit::Kilometer, "km"},
|
|
|
|
|
{Length::Unit::NauticalMile, "nmi"},
|
|
|
|
|
{Length::Unit::Inch, "in"},
|
|
|
|
|
{Length::Unit::Foot, "ft"},
|
|
|
|
|
{Length::Unit::Yard, "yd"},
|
|
|
|
|
{Length::Unit::Mile, "mi"},
|
|
|
|
|
};
|
2022-10-07 20:08:35 +00:00
|
|
|
|
|
|
|
|
auto iter = STRINGS.find(unit);
|
|
|
|
|
|
|
|
|
|
if (iter == STRINGS.end())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("A symbol could not be found for Length::Unit with value "
|
|
|
|
|
<< EnumHash()(unit));
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return iter->second;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2022-10-07 20:08:35 +00:00
|
|
|
ToName(Length::Unit unit, bool plural /*=false*/)
|
|
|
|
|
{
|
|
|
|
|
using Entry = std::tuple<std::string, std::string>;
|
|
|
|
|
using StringTable = std::unordered_map<Length::Unit, Entry, EnumHash>;
|
|
|
|
|
|
|
|
|
|
static const StringTable STRINGS{
|
|
|
|
|
{Length::Unit::Nanometer, Entry{"nanometer", "nanometers"}},
|
|
|
|
|
{Length::Unit::Micrometer, Entry{"micrometer", "micrometer"}},
|
|
|
|
|
{Length::Unit::Millimeter, Entry{"millimeter", "millimeters"}},
|
|
|
|
|
{Length::Unit::Centimeter, Entry{"centimeter", "centimeters"}},
|
|
|
|
|
{Length::Unit::Meter, Entry{"meter", "meters"}},
|
|
|
|
|
{Length::Unit::Kilometer, Entry{"kilometer", "kilometers"}},
|
|
|
|
|
{Length::Unit::NauticalMile, Entry{"nautical mile", "nautical miles"}},
|
|
|
|
|
{Length::Unit::Inch, Entry{"inch", "inches"}},
|
|
|
|
|
{Length::Unit::Foot, Entry{"foot", "feet"}},
|
|
|
|
|
{Length::Unit::Yard, Entry{"yard", "yards"}},
|
2022-11-03 17:53:20 +00:00
|
|
|
{Length::Unit::Mile, Entry{"mile", "miles"}},
|
|
|
|
|
};
|
2022-10-07 20:08:35 +00:00
|
|
|
|
|
|
|
|
auto iter = STRINGS.find(unit);
|
|
|
|
|
|
|
|
|
|
if (iter == STRINGS.end())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_FATAL_ERROR("A symbol could not be found for Length::Unit with value "
|
|
|
|
|
<< EnumHash()(unit));
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (plural)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return std::get<1>(iter->second);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return std::get<0>(iter->second);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-05-14 08:45:04 -07:00
|
|
|
std::optional<Length::Unit>
|
2022-10-07 20:08:35 +00:00
|
|
|
FromString(std::string unitString)
|
|
|
|
|
{
|
|
|
|
|
using UnitTable = std::unordered_map<std::string, Length::Unit>;
|
|
|
|
|
|
2022-11-03 17:53:20 +00:00
|
|
|
static const UnitTable UNITS{
|
|
|
|
|
{"nm", Length::Unit::Nanometer},
|
|
|
|
|
{"nanometer", Length::Unit::Nanometer},
|
|
|
|
|
{"nanometers", Length::Unit::Nanometer},
|
|
|
|
|
{"nanometre", Length::Unit::Nanometer},
|
|
|
|
|
{"nanometres", Length::Unit::Nanometer},
|
|
|
|
|
{"um", Length::Unit::Micrometer},
|
|
|
|
|
{"micrometer", Length::Unit::Micrometer},
|
|
|
|
|
{"micrometers", Length::Unit::Micrometer},
|
|
|
|
|
{"micrometre", Length::Unit::Micrometer},
|
|
|
|
|
{"micrometres", Length::Unit::Micrometer},
|
|
|
|
|
{"mm", Length::Unit::Millimeter},
|
|
|
|
|
{"millimeter", Length::Unit::Millimeter},
|
|
|
|
|
{"millimeters", Length::Unit::Millimeter},
|
|
|
|
|
{"millimetre", Length::Unit::Millimeter},
|
|
|
|
|
{"millimetres", Length::Unit::Millimeter},
|
|
|
|
|
{"cm", Length::Unit::Centimeter},
|
|
|
|
|
{"centimeter", Length::Unit::Centimeter},
|
|
|
|
|
{"centimeters", Length::Unit::Centimeter},
|
|
|
|
|
{"centimetre", Length::Unit::Centimeter},
|
|
|
|
|
{"centimetres", Length::Unit::Centimeter},
|
|
|
|
|
{"m", Length::Unit::Meter},
|
|
|
|
|
{"meter", Length::Unit::Meter},
|
|
|
|
|
{"metre", Length::Unit::Meter},
|
|
|
|
|
{"meters", Length::Unit::Meter},
|
|
|
|
|
{"metres", Length::Unit::Meter},
|
|
|
|
|
{"km", Length::Unit::Kilometer},
|
|
|
|
|
{"kilometer", Length::Unit::Kilometer},
|
|
|
|
|
{"kilometers", Length::Unit::Kilometer},
|
|
|
|
|
{"kilometre", Length::Unit::Kilometer},
|
|
|
|
|
{"kilometres", Length::Unit::Kilometer},
|
|
|
|
|
{"nmi", Length::Unit::NauticalMile},
|
|
|
|
|
{"nauticalmile", Length::Unit::NauticalMile},
|
|
|
|
|
{"nauticalmiles", Length::Unit::NauticalMile},
|
|
|
|
|
{"in", Length::Unit::Inch},
|
|
|
|
|
{"inch", Length::Unit::Inch},
|
|
|
|
|
{"inches", Length::Unit::Inch},
|
|
|
|
|
{"ft", Length::Unit::Foot},
|
|
|
|
|
{"foot", Length::Unit::Foot},
|
|
|
|
|
{"feet", Length::Unit::Foot},
|
|
|
|
|
{"yd", Length::Unit::Yard},
|
|
|
|
|
{"yard", Length::Unit::Yard},
|
|
|
|
|
{"yards", Length::Unit::Yard},
|
|
|
|
|
{"mi", Length::Unit::Mile},
|
|
|
|
|
{"mile", Length::Unit::Mile},
|
|
|
|
|
{"miles", Length::Unit::Mile},
|
|
|
|
|
};
|
2022-10-07 20:08:35 +00:00
|
|
|
|
|
|
|
|
// function to trim whitespace and convert to lowercase in one pass
|
|
|
|
|
static auto Normalize = [](const std::string& str) {
|
|
|
|
|
std::string output;
|
|
|
|
|
output.reserve(str.size());
|
|
|
|
|
|
|
|
|
|
for (unsigned char c : str)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
// this strips all spaces not just beg/end but is fine for our purposes
|
|
|
|
|
if (std::isspace(c))
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
continue;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
output.push_back(std::tolower(c));
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return output;
|
2020-10-02 11:06:06 -07:00
|
|
|
};
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
unitString = Normalize(unitString);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
auto iter = UNITS.find(unitString);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (iter != UNITS.end())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return iter->second;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return std::nullopt;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ostream&
|
2022-10-07 20:08:35 +00:00
|
|
|
operator<<(std::ostream& stream, const Length& l)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
stream << l.As(Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return stream;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ostream&
|
2022-10-07 20:08:35 +00:00
|
|
|
operator<<(std::ostream& stream, const Length::Quantity& q)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
stream << q.Value() << ' ' << ToSymbol(q.Unit());
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return stream;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::ostream&
|
2022-10-07 20:08:35 +00:00
|
|
|
operator<<(std::ostream& stream, Length::Unit unit)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
stream << ToName(unit);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return stream;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2020-12-17 11:42:18 -08:00
|
|
|
/**
|
|
|
|
|
* This function provides a string parsing method that does not rely
|
|
|
|
|
* on istream, which has been found to have different behaviors in different
|
|
|
|
|
* implementations.
|
|
|
|
|
*
|
|
|
|
|
* The input string can either contain a double (for example, "5.5") or
|
|
|
|
|
* a double and a string with no space between them (for example, "5.5m")
|
|
|
|
|
*
|
|
|
|
|
* \param input The input string
|
|
|
|
|
* \return A three element tuple containing the result of parsing the string.
|
|
|
|
|
* The first tuple element is a boolean indicating whether the parsing succeeded
|
|
|
|
|
* or failed. The second element contains the value of the double that was
|
|
|
|
|
* extracted from the string. The third element was the unit symbol that was
|
|
|
|
|
* extracted from the string. If the input string did not have a unit symbol,
|
|
|
|
|
* the third element will contain an empty string.
|
|
|
|
|
*/
|
|
|
|
|
std::tuple<bool, double, std::string>
|
2022-10-07 20:08:35 +00:00
|
|
|
ParseLengthString(const std::string& input)
|
2020-12-17 11:42:18 -08:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_FUNCTION(input);
|
2020-12-17 11:42:18 -08:00
|
|
|
|
|
|
|
|
double value = 0;
|
|
|
|
|
std::size_t pos = 0;
|
|
|
|
|
std::string symbol;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
value = std::stod(input, &pos);
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& e)
|
|
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_ERROR("Caught exception while parsing double: " << e.what());
|
2020-12-17 11:42:18 -08:00
|
|
|
|
|
|
|
|
return std::make_tuple(false, 0, "");
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// skip any whitespace between value and symbol
|
|
|
|
|
while (pos < input.size() && std::isspace(input[pos]))
|
2022-10-06 22:09:53 +00:00
|
|
|
{
|
2020-12-17 11:42:18 -08:00
|
|
|
++pos;
|
2022-10-06 22:09:53 +00:00
|
|
|
}
|
2020-12-17 11:42:18 -08:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (pos < input.size())
|
2020-12-17 11:42:18 -08:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
NS_LOG_LOGIC("String has value and symbol, extracting symbol");
|
2020-12-17 11:42:18 -08:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// input has a double followed by a string
|
2020-12-17 11:42:18 -08:00
|
|
|
symbol = input.substr(pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_tuple(true, value, symbol);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-02 11:06:06 -07:00
|
|
|
std::istream&
|
2022-10-07 20:08:35 +00:00
|
|
|
operator>>(std::istream& stream, Length& l)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
bool success = false;
|
|
|
|
|
double value = 0;
|
|
|
|
|
std::string symbol;
|
|
|
|
|
std::string temp;
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// configure stream to skip whitespace in case it was disabled
|
|
|
|
|
auto origFlags = stream.flags();
|
|
|
|
|
std::skipws(stream);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// Read the contents into a temporary string and parse it manually
|
|
|
|
|
stream >> temp;
|
2020-12-17 11:42:18 -08:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
std::tie(success, value, symbol) = ParseLengthString(temp);
|
2020-12-17 11:42:18 -08:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (success && symbol.empty())
|
|
|
|
|
{
|
|
|
|
|
NS_LOG_LOGIC("Temp string only contained value, extracting unit symbol from stream");
|
2020-12-17 11:42:18 -08:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// temp only contained the double
|
|
|
|
|
// still need to read the symbol from the stream
|
|
|
|
|
stream >> symbol;
|
|
|
|
|
}
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// special handling for nautical mile which is two words
|
|
|
|
|
if (symbol == "nautical")
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
stream >> temp;
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
if (!temp.empty())
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
symbol.push_back(' ');
|
|
|
|
|
symbol.append(temp);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
Length(value, symbol).swap(l);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
// restore original flags
|
|
|
|
|
stream.flags(origFlags);
|
2020-10-02 11:06:06 -07:00
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
return stream;
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
NanoMeters(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Nanometer);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
MicroMeters(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Micrometer);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
MilliMeters(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Millimeter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
CentiMeters(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Centimeter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
Meters(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Meter);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
KiloMeters(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Kilometer);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
NauticalMiles(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::NauticalMile);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
Inches(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Inch);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
Feet(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Foot);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
Yards(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Yard);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Length
|
2022-10-07 20:08:35 +00:00
|
|
|
Miles(double value)
|
2020-10-02 11:06:06 -07:00
|
|
|
{
|
2022-10-07 20:08:35 +00:00
|
|
|
return Length(value, Length::Unit::Mile);
|
2020-10-02 11:06:06 -07:00
|
|
|
}
|
|
|
|
|
|
2022-10-07 20:08:35 +00:00
|
|
|
} // namespace ns3
|