Commit 1be5173a authored by Simon Spannagel's avatar Simon Spannagel
Browse files

Update unit class, move implementations of templates inot template file

parent 0ab1f7d6
......@@ -3,10 +3,8 @@
* @brief Implementation of unit system
*
* @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
* This software is distributed under the terms of the MIT License, copied
* verbatim in the file "LICENSE.md".
* In applying this license, CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an
* This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
* In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
......@@ -20,7 +18,7 @@
#include <string>
#include <type_traits>
#include "core/utils/string.h"
#include "core/utils/text.h"
using namespace corryvreckan;
......@@ -29,8 +27,7 @@ std::map<std::string, corryvreckan::Units::UnitType> Units::unit_map_;
/**
* @throws std::invalid_argument If the unit already exists
*
* Units should consist of only alphabetical characters. Units are converted to
* lowercase internally. All the defined units
* Units should consist of only alphabetical characters. Units are converted to lowercase internally. All the defined units
* should have unique values and it is not possible to redefine them.
*
* @note No explicit check is done for alphabetical units
......@@ -49,8 +46,7 @@ void Units::add(std::string str, UnitType value) {
/**
* @throws std::invalid_argument If the requested unit does not exist
*
* All units are converted to lowercase before finding their value in the
* internal database.
* All units are converted to lowercase before finding their value in the internal database.
*/
corryvreckan::Units::UnitType Units::getSingle(std::string str) {
if(corryvreckan::trim(str).empty()) {
......@@ -70,10 +66,8 @@ corryvreckan::Units::UnitType Units::getSingle(std::string str) {
/**
* @throws invalid_argument If one tries to get the value of an empty unit
*
* Units are combined by applying the multiplication operator * and the division
* operator / linearly. The first unit is
* always multiplied, following common sense. Grouping units together within
* brackets or parentheses is not supported. Thus
* Units are combined by applying the multiplication operator * and the division operator / linearly. The first unit is
* always multiplied, following common sense. Grouping units together within brackets or parentheses is not supported. Thus
* any other character then a name of a unit, * or \ should lead to an error
*/
corryvreckan::Units::UnitType Units::get(std::string str) {
......@@ -143,11 +137,9 @@ corryvreckan::Units::UnitType Units::convert(UnitType input, std::string str) {
* @throws std::invalid_argument If the list of units is empty
*
* The best unit is determined using the two rules below:
* - If there exists at least one unit for which the value is larger than one,
* the unit with value nearest to one is chosen
* - If there exists at least one unit for which the value is larger than one, the unit with value nearest to one is chosen
* from all units with values larger than one
* - Otherwise the unit is chosen that has a value as close as possible to one
* (from below)
* - Otherwise the unit is chosen that has a value as close as possible to one (from below)
*/
std::string Units::display(UnitType input, std::initializer_list<std::string> units) {
if(units.size() == 0) {
......
......@@ -128,55 +128,22 @@ namespace corryvreckan {
// TODO [doc] Shall we change the name in something better here
static std::string display(UnitType input, std::string unit);
/**
* @brief Return value for display in the best of all the provided units for all vector elements
* @param input Vector of values in the base unit system
* @param units Name of the possible output units
* @return Vector of values between parentheses with best display units for each element
* @note Works for all vector types that can be converted to a string using \ref StringConversions "the string
* utilities".
*/
template <typename T> static std::string display(T input, std::initializer_list<std::string> units);
private:
static std::map<std::string, UnitType> unit_map_;
};
// TODO [doc] Move these to a separate template implementation file?
/**
* @throws std::overflow_error If the converted unit overflows the requested
* type
*
* The unit type is internally converted to the type \ref Units::UnitType. After
* multiplying the unit, the output is
* checked for overflow problems before the type is converted back to the
* original type.
*/
template <typename T> T Units::get(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) * get(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
// Getters for single and inverse units
template <typename T> T Units::getSingle(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) * getSingle(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
template <typename T> T Units::getSingleInverse(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) / getSingle(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
template <typename T> T Units::getInverse(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) / get(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
} // namespace corryvreckan
// Include template definitions
#include "unit.tpp"
#endif /* CORRYVRECKAN_UNIT_H */
#include "text.h"
namespace corryvreckan {
/**
* @throws std::overflow_error If the converted unit overflows the requested type
*
* The unit type is internally converted to the type \ref Units::UnitType. After multiplying the unit, the output is
* checked for overflow problems before the type is converted back to the original type.
*/
template <typename T> T Units::get(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) * get(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
// Getters for single and inverse units
template <typename T> T Units::getSingle(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) * getSingle(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
template <typename T> T Units::getSingleInverse(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) / getSingle(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
template <typename T> T Units::getInverse(T inp, std::string str) {
UnitType out = static_cast<UnitType>(inp) / get(std::move(str));
if(out > static_cast<UnitType>(std::numeric_limits<T>::max()) ||
out < static_cast<UnitType>(std::numeric_limits<T>::lowest())) {
throw std::overflow_error("unit conversion overflows the type");
}
return static_cast<T>(out);
}
// Display function for vectors
template <typename T> std::string Units::display(T inp, std::initializer_list<std::string> units) {
auto split = corryvreckan::split<Units::UnitType>(corryvreckan::to_string(inp));
std::string ret_str;
if(split.size() > 1) {
ret_str += "(";
}
for(auto& element : split) {
ret_str += Units::display(element, units);
ret_str += ",";
}
if(split.size() > 1) {
ret_str[ret_str.size() - 1] = ')';
} else {
ret_str.pop_back();
}
return ret_str;
}
} // namespace corryvreckan
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment