Commit 615a9859 authored by Simon Spannagel's avatar Simon Spannagel
Browse files

Merge branch 'master' into documentation

parents 16944dd4 017ba963
......@@ -7,6 +7,7 @@ ADD_LIBRARY(CorryvreckanCore SHARED
detector/Detector.cpp
utils/log.cpp
utils/unit.cpp
utils/text.cpp
clipboard/Clipboard.cpp
config/ConfigManager.cpp
config/ConfigReader.cpp
......
......@@ -16,7 +16,7 @@
#include <string>
#include <vector>
#include "core/utils/string.h"
#include "core/utils/text.h"
#include "exceptions.h"
namespace corryvreckan {
......@@ -142,12 +142,21 @@ namespace corryvreckan {
// TODO [doc] Provide second template parameter to specify the vector type to return it in
std::vector<std::string> getPathArray(const std::string& key, bool check_exists = false) const;
/**
* @brief Set value for a key in a given type with units
* @param key Key to set value of
* @param val Value to assign to the key
* @param units List of possible output units
*/
template <typename T> void set(const std::string& key, const T& val, std::initializer_list<std::string> units);
/**
* @brief Set value for a key in a given type
* @param key Key to set value of
* @param val Value to assign to the key
*/
template <typename T> void set(const std::string& key, const T& val);
/**
* @brief Set list of values for a key in a given type
* @param key Key to set values of
......
......@@ -129,14 +129,29 @@ namespace corryvreckan {
template <typename T> void Configuration::set(const std::string& key, const T& val) {
config_[key] = corryvreckan::to_string(val);
}
template <typename T>
void Configuration::set(const std::string& key, const T& val, std::initializer_list<std::string> units) {
auto split = corryvreckan::split<Units::UnitType>(corryvreckan::to_string(val));
std::string ret_str;
for(auto& element : split) {
ret_str += Units::display(element, units);
ret_str += ",";
}
ret_str.pop_back();
config_[key] = ret_str;
}
template <typename T> void Configuration::setArray(const std::string& key, const std::vector<T>& val) {
// NOTE: not the most elegant way to support arrays
std::string str;
for(auto& el : val) {
str += corryvreckan::to_string(el);
str += ",";
str += corryvreckan::to_string(val);
}
set(key, str);
str.pop_back();
config_[key] = str;
}
template <typename T> void Configuration::setDefault(const std::string& key, const T& val) {
......
......@@ -48,9 +48,9 @@ Detector::Detector(const Configuration& config) {
this->initialise();
LOG(TRACE) << "Initialized \"" << m_detectorType << "\": " << m_nPixelsX << "x" << m_nPixelsY << " px, pitch of "
<< display_vector(m_pitch, {"mm", "um"});
LOG(TRACE) << " Position: " << display_vector(m_displacement, {"mm", "um"});
LOG(TRACE) << " Orientation: " << display_vector(m_orientation, {"deg"}) << " (" << m_orientation_mode << ")";
<< Units::display(m_pitch, {"mm", "um"});
LOG(TRACE) << " Position: " << Units::display(m_displacement, {"mm", "um"});
LOG(TRACE) << " Orientation: " << Units::display(m_orientation, {"deg"}) << " (" << m_orientation_mode << ")";
if(m_timingOffset > 0.) {
LOG(TRACE) << "Timing offset: " << m_timingOffset;
}
......@@ -155,17 +155,17 @@ Configuration Detector::getConfiguration() {
Configuration config(name());
config.set("type", m_detectorType);
config.set("position", m_displacement);
config.set("position", m_displacement, {"um", "mm"});
config.set("orientation_mode", m_orientation_mode);
config.set("orientation", m_orientation);
config.set("orientation", m_orientation, {"deg"});
auto npixels = ROOT::Math::DisplacementVector2D<Cartesian2D<int>>(m_nPixelsX, m_nPixelsY);
config.set("number_of_pixels", npixels);
// Size of the pixels
config.set("pixel_pitch", m_pitch);
config.set("pixel_pitch", m_pitch, {"um"});
if(m_timingOffset != 0.) {
config.set("time_offset", m_timingOffset);
config.set("time_offset", m_timingOffset, {"ns", "us", "ms", "s"});
}
if(!m_maskfile_name.empty()) {
......
......@@ -22,7 +22,7 @@
#include <Math/PositionVector3D.h>
#include <TString.h>
#include "core/utils/string.h"
#include "core/utils/text.h"
#include "core/utils/type.h"
namespace corryvreckan {
......@@ -146,21 +146,6 @@ namespace corryvreckan {
inline std::ostream& operator<<(std::ostream& os, const ROOT::Math::PositionVector2D<T, U>& vec) {
return os << "(" << vec.x() << "," << vec.y() << ")";
}
/**
* @brief Utility function to display vector types with units
* @note Works for all vector types that can be converted to string using \ref StringConversions "the string utilities".
*/
template <typename T> inline std::string display_vector(T inp, std::initializer_list<std::string> units) {
auto split = corryvreckan::split<Units::UnitType>(corryvreckan::to_string(inp));
std::string ret_str = "(";
for(auto& element : split) {
ret_str += Units::display(element, units);
ret_str += ",";
}
ret_str[ret_str.size() - 1] = ')';
return ret_str;
}
} // namespace corryvreckan
#endif /* CORRYVRECKAN_ROOT_H */
/**
* @file
* @brief Implementation of string utilities
*
* @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
* Intergovernmental Organization or submit itself to any jurisdiction.
*
* Used extensively for parsing the configuration in the \ref corryvreckan::ConfigReader.
*/
#include "text.h"
#include "unit.h"
using namespace corryvreckan;
std::string corryvreckan::trim(const std::string& str, const std::string& delims) {
size_t b = str.find_first_not_of(delims);
size_t e = str.find_last_not_of(delims);
if(b == std::string::npos || e == std::string::npos) {
return "";
}
return std::string(str, b, e - b + 1);
}
std::string corryvreckan::from_string_helper(std::string str) {
// Check if string is not empty
str = trim(str);
if(str.empty()) {
throw std::invalid_argument("string is empty");
}
// Check if there is whitespace in the string
size_t white_space = str.find_first_of(" \t\n\r\v");
if(white_space != std::string::npos) {
throw std::invalid_argument("remaining data at end");
}
return str;
}
/**
* If a pair of enclosing double quotation marks is found, the whole string within the quotation marks is returned.
* Otherwise only the first part is read until whitespace is encountered.
*/
std::string corryvreckan::from_string_impl(std::string str, type_tag<std::string>) {
str = trim(str);
// If there are "" then we should take the whole string
if(!str.empty() && (str.front() == '\"' || str.front() == '\'')) {
if(str.find(str.front(), 1) != str.size() - 1) {
throw std::invalid_argument("remaining data at end");
}
return str.substr(1, str.size() - 2);
}
// Otherwise read a single string
return from_string_helper(str);
}
/**
* Both numerical (0, 1) and textual representations ("false", "true") are supported for booleans. No enclosing quotation
* marks should be used.
*/
bool corryvreckan::from_string_impl(std::string str, type_tag<bool>) {
str = from_string_helper(str);
std::istringstream sstream(str);
bool ret_value = false;
if(isalpha(str.back()) != 0) {
sstream >> std::boolalpha >> ret_value;
} else {
sstream >> ret_value;
}
// Check if the reading was succesfull and everything was read
if(sstream.fail() || sstream.peek() != EOF) {
throw std::invalid_argument("conversion not possible");
}
return ret_value;
}
......@@ -6,7 +6,7 @@
* 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.
*
* Used extensively for parsing the configuration in the \ref allpix::ConfigReader.
* Used extensively for parsing the configuration in the \ref corryvreckan::ConfigReader.
*/
/**
......@@ -14,8 +14,8 @@
* @brief Collection of all the overloads of string conversions
*/
#ifndef CORRYVRECKAN_STRING_H
#define CORRYVRECKAN_STRING_H
#ifndef CORRYVRECKAN_TEXT_H
#define CORRYVRECKAN_TEXT_H
#include <cctype>
#include <sstream>
......@@ -24,7 +24,6 @@
#include <vector>
#include "type.h"
#include "unit.h"
// TODO [doc]: should possible be put in a separate namespace
......@@ -35,182 +34,69 @@ namespace corryvreckan {
* @param str String that should be trimmed
* @param delims List of delimiters to trim from the string (defaults to all whitespace)
*/
inline std::string trim(const std::string& str, const std::string& delims = " \t\n\r\v") {
size_t b = str.find_first_not_of(delims);
size_t e = str.find_last_not_of(delims);
if(b == std::string::npos || e == std::string::npos) {
return "";
}
return std::string(str, b, e - b + 1);
}
std::string trim(const std::string& str, const std::string& delims = " \t\n\r\v");
/**
* @brief Converts a string to any supported type
* @param str String to convert
* @see StringConversions
*
* The matching converter function is automatically found if available. To add a new conversion the \ref from_string_impl
* function should be overloaded. The string is passed as first argument to this function, the second argument should be
* an \ref corryvreckan::type_tag with the type to convert to.
*
*/
template <typename T> T from_string(std::string str) {
// Use tag dispatch to select the correct helper function
return from_string_impl(str, type_tag<T>());
}
// TODO [doc] This should move to a source file
// FIXME: include exceptions better
// helper functions to do cleaning and checks for string reading
static std::string _from_string_helper(std::string str) {
// Check if string is not empty
str = trim(str);
if(str.empty()) {
throw std::invalid_argument("string is empty");
}
template <typename T> T from_string(std::string str);
// Check if there is whitespace in the string
size_t white_space = str.find_first_of(" \t\n\r\v");
if(white_space != std::string::npos) {
throw std::invalid_argument("remaining data at end");
}
return str;
}
/**
* @brief Internal helper method for checking and trimming conversions from string
* @param str Input string to check and trim
* @return Trimmed string
*/
std::string from_string_helper(std::string str);
/**
* @ingroup StringConversions
* @brief Conversion handler for all non implemented conversions
*
* Function does not return but will raise an static assertion.
* @warning Function does not return but will raise an static assertion.
*/
template <typename T, typename = std::enable_if_t<!std::is_arithmetic<T>::value>, typename = void>
constexpr T from_string_impl(const std::string&, type_tag<T>) {
static_assert(std::is_same<T, void>::value,
"Conversion to this type is not implemented: an overload should be added to support this conversion");
return T();
}
constexpr T from_string_impl(const std::string&, type_tag<T>);
/**
* @ingroup StringConversions
* @brief Conversion handler for all arithmetic types
* @throws std::invalid_argument If the string cannot be converted to the required arithmetic type
*
* The unit system is used through \ref Units::get to parse unit suffixes and convert the values to the appropriate
* standard framework unit.
*/
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
T from_string_impl(std::string str, type_tag<T>) {
str = _from_string_helper(str);
// Find an optional set of units
auto unit_idx = str.size() - 1;
for(; unit_idx > 0; --unit_idx) {
if(!isalpha(str[unit_idx]) && str[unit_idx] != '*' && str[unit_idx] != '/') {
break;
}
}
std::string units = str.substr(unit_idx + 1);
// Get the actual arithmetic value
std::istringstream sstream(str.substr(0, unit_idx + 1));
T ret_value = 0;
sstream >> ret_value;
// Check if the reading was succesfull and everything was read
if(sstream.fail() || sstream.peek() != EOF) {
throw std::invalid_argument("conversion not possible");
}
// Apply all the units if they exists
if(!units.empty()) {
ret_value = corryvreckan::Units::get(ret_value, units);
}
return ret_value;
}
T from_string_impl(std::string str, type_tag<T>);
/**
* @ingroup StringConversions
* @brief Conversion handler for strings
* @throws std::invalid_argument If the string has no closing quotation mark as last character after an opening quotation
* mark
* @throws std::invalid_argument If the string has no enclosing quotation marks but contains more data after whitespace
* is found
*
* If a pair of enclosing double quotation marks is found, the whole string within the quotation marks is returned.
* Otherwise only the first part is read until whitespace is encountered.
* @throws std::invalid_argument If no closing quotation mark as last character after an opening quotation mark
* @throws std::invalid_argument If string without enclosing quotation marks, but more data after whitespace is found
*/
inline std::string from_string_impl(std::string str, type_tag<std::string>) {
str = trim(str);
// If there are "" then we should take the whole string
if(!str.empty() && (str.front() == '\"' || str.front() == '\'')) {
if(str.find(str.front(), 1) != str.size() - 1) {
throw std::invalid_argument("remaining data at end");
}
return str.substr(1, str.size() - 2);
}
// Otherwise read a single string
return _from_string_helper(str);
}
std::string from_string_impl(std::string str, type_tag<std::string>);
/**
* @ingroup StringConversions
* @brief Conversion handler for booleans
* @throws std::invalid_argument If the string cannot be converted to a boolean type
*
* Converts both numerical (0, 1) and textual representations ("false", "true") are supported. No enclosing quotation
* marks should be used.
*/
inline bool from_string_impl(std::string str, type_tag<bool>) {
str = _from_string_helper(str);
std::istringstream sstream(str);
bool ret_value = false;
if(isalpha(str.back()) != 0) {
sstream >> std::boolalpha >> ret_value;
} else {
sstream >> ret_value;
}
// Check if the reading was succesfull and everything was read
if(sstream.fail() || sstream.peek() != EOF) {
throw std::invalid_argument("conversion not possible");
}
return ret_value;
}
bool from_string_impl(std::string str, type_tag<bool>);
/**
* @brief Converts any type to a string
* @note C-strings are not supported due to allocation issues
*
* The matching converter function is automatically found if available. To add a new conversion the \ref to_string_impl
* function should be overloaded. The string is passed as first argument to this function, the second argument should be
* an \ref corryvreckan::empty_tag (needed to search in the corryvreckan namespace).
*/
template <typename T> std::string to_string(T inp) {
// Use tag dispatch to select the correct implementation
return to_string_impl(inp, empty_tag());
}
template <typename T> std::string to_string(T inp);
/**
* @ingroup StringConversions
* @brief Conversion handler for all non implemented conversions
*
* Function does not return but will raise an static assertion.
* @warning Function does not return but will raise an static assertion.
*/
template <typename T, typename = std::enable_if_t<!std::is_arithmetic<T>::value>, typename = void>
constexpr void to_string_impl(T, empty_tag) {
static_assert(std::is_same<T, void>::value,
"Conversion to this type is not implemented: an overload should be added to support this conversion");
}
constexpr void to_string_impl(T, empty_tag);
/**
* @ingroup StringConversions
* @brief Conversion handler for all arithmetic types
*/
template <typename T, typename = std::enable_if_t<std::is_arithmetic<T>::value>>
std::string to_string_impl(T inp, empty_tag) {
std::ostringstream out;
out << inp;
return out.str();
}
std::string to_string_impl(T inp, empty_tag);
///@{
/**
......@@ -228,34 +114,13 @@ namespace corryvreckan {
/**
* @brief Splits string into substrings at delimiters
* @param str String to split
* @param delims Delimiters to split at
* @param delims Delimiters to split at (defaults to space, tab and comma)
* @return List of all the substrings with all empty substrings ignored (thus removed)
*/
template <typename T> std::vector<T> split(std::string str, const std::string& delims = " \t,") {
str = trim(str, delims);
// If the input string is empty, simply return empty container
if(str.empty()) {
return std::vector<T>();
}
// Else we have data, clear the default elements and chop the string:
std::vector<T> elems;
// Loop through the string
std::size_t prev = 0, pos;
while((pos = str.find_first_of(delims, prev)) != std::string::npos) {
if(pos > prev) {
elems.push_back(from_string<T>(str.substr(prev, pos - prev)));
}
prev = pos + 1;
}
if(prev < str.length()) {
elems.push_back(from_string<T>(str.substr(prev, std::string::npos)));
}
return elems;
}
template <typename T> std::vector<T> split(std::string str, const std::string& delims = " \t,");
} // namespace corryvreckan
#endif /* CORRYVRECKAN_STRING_H */
// Include template definitions
#include "text.tpp"
#endif /* CORRYVRECKAN_TEXT_H */
#include "unit.h"
namespace corryvreckan {
/**
* The matching converter function is automatically found if available. To add a new conversion the \ref from_string_impl
* function should be overloaded. The string is passed as first argument to this function, the second argument should be
* an \ref corryvreckan::type_tag with the type to convert to.
*/
template <typename T> T from_string(std::string str) {
// Use tag dispatch to select the correct helper function
return from_string_impl(str, type_tag<T>());
}
template <typename T, typename> constexpr T from_string_impl(const std::string&, type_tag<T>) {
static_assert(std::is_same<T, void>::value,
"Conversion to this type is not implemented: an overload should be added to support this conversion");
return T();
}
/**
* The unit system is used through \ref Units::get to parse unit suffixes and convert the values to the appropriate
* standard framework unit.
*/
template <typename T, typename> T from_string_impl(std::string str, type_tag<T>) {
str = from_string_helper(str);
// Find an optional set of units
auto unit_idx = str.size() - 1;
for(; unit_idx > 0; --unit_idx) {
if(!isalpha(str[unit_idx]) && str[unit_idx] != '*' && str[unit_idx] != '/') {
break;
}
}
std::string units = str.substr(unit_idx + 1);
// Get the actual arithmetic value
std::istringstream sstream(str.substr(0, unit_idx + 1));
T ret_value = 0;
sstream >> ret_value;
// Check if the reading was succesfull and everything was read
if(sstream.fail() || sstream.peek() != EOF) {
throw std::invalid_argument("conversion not possible");
}
// Apply all the units if they exists
if(!units.empty()) {
ret_value = corryvreckan::Units::get(ret_value, units);
}
return ret_value;
}
/**
* The matching converter function is automatically found if available. To add a new conversion the \ref to_string_impl
* function should be overloaded. The string is passed as first argument to this function, the second argument should be
* an \ref corryvreckan::empty_tag (required to search in the corryvreckan namespace).
*/
template <typename T> std::string to_string(T inp) {
// Use tag dispatch to select the correct implementation
return to_string_impl(inp, empty_tag());
}
template <typename T, typename, typename> constexpr void to_string_impl(T, empty_tag) {
static_assert(std::is_same<T, void>::value,
"Conversion to this type is not implemented: an overload should be added to support this conversion");
}
template <typename T, typename> std::string to_string_impl(T inp, empty_tag) {
std::ostringstream out;
out << inp;
return out.str();
}
template <typename T> std::vector<T> split(std::string str, const std::string& delims) {
str = trim(str, delims);
// If the input string is empty, simply return empty container
if(str.empty()) {
return std::vector<T>();
}
// Else we have data, clear the default elements and chop the string:
std::vector<T> elems;
// Loop through the string
std::size_t prev = 0, pos;
while((pos = str.find_first_of(delims, prev)) != std::string::npos) {
if(pos > prev) {
elems.push_back(from_string<T>(str.substr(prev, pos - prev)));
}
prev = pos + 1;
}
if(prev < str.length()) {
elems.push_back(from_string<T>(str.substr(prev, std::string::npos)));
}
return elems;
}
} // namespace corryvreckan
......@@ -2,10 +2,8 @@
* @file
* @brief Tags for type dispatching and run time type identification
* @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.
*/
......@@ -21,14 +19,12 @@
namespace corryvreckan {
/**
* @brief Tag for specific type