Mantid
Loading...
Searching...
No Matches
PropertyHelper.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#pragma once
8
9#ifndef Q_MOC_RUN
10#include <boost/lexical_cast.hpp>
11#include <memory>
12#endif
13
18
19#include <type_traits>
20
21namespace Mantid {
22namespace Kernel {
23
24// --------------------- convert values to strings
26template <typename T> std::string toString(const T &value) { return boost::lexical_cast<std::string>(value); }
27
29template <typename T> std::string toString(const std::shared_ptr<T> &) { throw boost::bad_lexical_cast(); }
30
32template <typename T> std::string toString(const std::vector<T> &value, const std::string &delimiter = ",") {
33 std::stringstream result;
34 std::size_t vsize = value.size();
35 for (std::size_t i = 0; i < vsize; ++i) {
36 result << value[i];
37 if (i + 1 != vsize)
38 result << delimiter;
39 }
40 return result.str();
41}
42
44template <typename T>
45std::string toString(const std::vector<std::vector<T>> &value, const std::string &outerDelimiter = ",",
46 const std::string &innerDelimiter = "+") {
47 std::stringstream result;
48 std::size_t vsize = value.size();
49 for (std::size_t i = 0; i < vsize; ++i) {
50 std::size_t innervsize = value[i].size();
51 for (std::size_t j = 0; j < innervsize; ++j) {
52 result << value[i][j];
53 if (j + 1 != innervsize)
54 result << innerDelimiter;
55 }
56
57 if (i + 1 != vsize)
58 result << outerDelimiter;
59 }
60 return result.str();
61}
62
63// --------------------- convert values to pretty strings
65template <typename T> std::string toPrettyString(const T &value, size_t maxLength = 0, bool collapseLists = true) {
66 UNUSED_ARG(collapseLists);
67 return Strings::shorten(boost::lexical_cast<std::string>(value), maxLength);
68}
69
71template <typename T>
72std::string toPrettyString(const std::shared_ptr<T> &value, size_t maxLength = 0, bool collapseLists = true) {
74 UNUSED_ARG(maxLength);
75 UNUSED_ARG(collapseLists);
76 throw boost::bad_lexical_cast();
77}
78
83template <typename T>
84std::string toPrettyString(
85 const std::vector<T> &value, size_t maxLength = 0, bool collapseLists = true, const std::string &delimiter = ",",
86 const std::string &unusedDelimiter = "+",
87 typename std::enable_if<!(std::is_integral<T>::value && std::is_arithmetic<T>::value)>::type * = nullptr) {
88 UNUSED_ARG(unusedDelimiter);
89 UNUSED_ARG(collapseLists);
90 return Strings::shorten(Strings::join(value.begin(), value.end(), delimiter), maxLength);
91}
92
100template <typename T>
101std::string
102toPrettyString(const std::vector<T> &value, size_t maxLength = 0, bool collapseLists = true,
103 const std::string &delimiter = ",", const std::string &listDelimiter = "-",
104 typename std::enable_if<std::is_integral<T>::value && std::is_arithmetic<T>::value>::type * = nullptr) {
105 std::string retVal;
106 if (collapseLists) {
107 retVal = Strings::joinCompress(value.begin(), value.end(), delimiter, listDelimiter);
108 } else {
109 retVal = Strings::join(value.begin(), value.end(), delimiter);
110 }
111 return Strings::shorten(retVal, maxLength);
112}
113
119template <>
120[[maybe_unused]]
121inline std::string toPrettyString(const std::vector<bool> &value, size_t maxLength, bool collapseLists,
122 const std::string &delimiter, const std::string &unusedDelimiter,
123 typename std::enable_if<std::is_same<bool, bool>::value>::type *) {
124 UNUSED_ARG(unusedDelimiter);
125 UNUSED_ARG(collapseLists);
126 return Strings::shorten(Strings::join(value.begin(), value.end(), delimiter), maxLength);
127}
128
130template <typename T>
131std::string toPrettyString(const std::vector<std::vector<T>> &value, size_t maxLength = 0, bool collapseLists = true,
132 const std::string &outerDelimiter = ",", const std::string &innerDelimiter = "+") {
133 UNUSED_ARG(collapseLists);
134 return Strings::shorten(toString<T>(value, outerDelimiter, innerDelimiter), maxLength);
135}
136
139template <typename T> int findSize(const T &) { return 1; }
140
142template <typename T> int findSize(const std::vector<T> &value) { return static_cast<int>(value.size()); }
143
144// ------------- Convert strings to values
145template <typename T> inline void appendValue(const std::string &strvalue, std::vector<T> &value) {
146 // try to split the string
147 std::size_t pos = strvalue.find(':');
148 std::size_t numChar = std::string::npos; // go to the end of the string
149 T step{1};
150 bool dashSeparator = false;
151 if (pos == std::string::npos) {
152 pos = strvalue.find('-', 1);
153 if (pos != std::string::npos)
154 dashSeparator = true;
155 } else {
156 const auto posStep = strvalue.find(':', pos + 1);
157 if (posStep != std::string::npos) {
158 step = boost::lexical_cast<T>(strvalue.substr(posStep + 1));
159 numChar = posStep - pos - 1;
160 }
161 }
162
163 // just convert the whole thing into a value
164 if (pos == std::string::npos) {
165 value.emplace_back(boost::lexical_cast<T>(strvalue));
166 return;
167 }
168
169 if (step == static_cast<T>(0))
170 throw std::logic_error("Step size must be non-zero");
171
172 // convert the input string into boundaries and run through a list
173 auto start = boost::lexical_cast<T>(strvalue.substr(0, pos));
174 auto stop = boost::lexical_cast<T>(strvalue.substr(pos + 1, numChar));
175
176 if ((start > stop) && (dashSeparator)) {
177 std::swap(start, stop);
178 }
179
180 if (start <= stop) {
181 if (start + step < start)
182 throw std::logic_error("Step size is negative with increasing limits");
183 for (auto i = start; i <= stop;) {
184 value.emplace_back(i);
185 // done inside the loop because gcc7 doesn't like i+=step for short
186 // unsigned int
187 i = static_cast<T>(i + step);
188 }
189 } else {
190 if (start + step >= start)
191 throw std::logic_error("Step size is positive with decreasing limits");
192 for (auto i = start; i >= stop;) {
193 value.emplace_back(i);
194 // done inside the loop because gcc7 doesn't like i+=step for short
195 // unsigned int
196 i = static_cast<T>(i + step);
197 }
198 }
199}
200
201template <typename T> inline void toValue(const std::string &strvalue, T &value) {
202 value = boost::lexical_cast<T>(strvalue);
203}
204
205template <typename T> inline void toValue(const std::string &, std::shared_ptr<T> &) {
206 throw boost::bad_lexical_cast();
207}
208
209// explicit instantiation for OptionalBool
210template <> MANTID_KERNEL_DLL void toValue(const std::string &strValue, OptionalBool &value);
211
212namespace detail {
213// vector<int> specializations
214template <typename T> void toValue(const std::string &strvalue, std::vector<T> &value, std::true_type) {
217 value.clear();
218 value.reserve(values.count());
219 for (const auto &token : values) {
220 appendValue(token, value);
221 }
222}
223
224template <typename T> void toValue(const std::string &strvalue, std::vector<T> &value, std::false_type) {
225 // Split up comma-separated properties
228
229 value.clear();
230 value.reserve(values.count());
231 std::transform(values.cbegin(), values.cend(), std::back_inserter(value),
232 [](const std::string &str) { return boost::lexical_cast<T>(str); });
233}
234
235// bool and char don't make sense as types to generate a range of values.
236// This is similar to std::is_integral<T>, but bool and char are std::false_type
237template <class T> struct is_range_type : public std::false_type {};
238template <class T> struct is_range_type<const T> : public is_range_type<T> {};
239template <class T> struct is_range_type<volatile const T> : public is_range_type<T> {};
240template <class T> struct is_range_type<volatile T> : public is_range_type<T> {};
241
242template <> struct is_range_type<unsigned short> : public std::true_type {};
243template <> struct is_range_type<unsigned int> : public std::true_type {};
244template <> struct is_range_type<unsigned long> : public std::true_type {};
245template <> struct is_range_type<unsigned long long> : public std::true_type {};
246
247template <> struct is_range_type<short> : public std::true_type {};
248template <> struct is_range_type<int> : public std::true_type {};
249template <> struct is_range_type<long> : public std::true_type {};
250template <> struct is_range_type<long long> : public std::true_type {};
251} // namespace detail
252template <typename T> void toValue(const std::string &strvalue, std::vector<T> &value) {
254}
255
256template <typename T>
257void toValue(const std::string &strvalue, std::vector<std::vector<T>> &value, const std::string &outerDelimiter = ",",
258 const std::string &innerDelimiter = "+") {
260 tokenizer tokens(strvalue, outerDelimiter, tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
261
262 value.clear();
263 value.reserve(tokens.count());
264
265 for (const auto &token : tokens) {
266 tokenizer values(token, innerDelimiter, tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
267 std::vector<T> vect;
268 vect.reserve(values.count());
269 std::transform(values.begin(), values.end(), std::back_inserter(vect),
270 [](const std::string &str) { return boost::lexical_cast<T>(str); });
271 value.emplace_back(std::move(vect));
272 }
273}
274
275/*Used specifically to retrieve a vector of type T populated with values
276 * given to it from strvalue parameter, Using toValue method.
277 (See constructor used specifically for vector assignments)
278 */
279template <typename T> T extractToValueVector(const std::string &strvalue) {
280 T valueVec;
281 toValue(strvalue, valueVec);
282 return valueVec;
283}
284
285//------------------------------------------------------------------------------------------------
286// Templated += operator functions for specific types
287template <typename T> inline void addingOperator(T &lhs, const T &rhs) {
288 // The cast here (and the expansion of the compound operator which that
289 // necessitates) is because if this function is created for a template
290 // type narrower than an int, the compiler will expande the operands to
291 // ints which leads to a compiler warning when it's assigned back to the
292 // narrower type.
293 lhs = static_cast<T>(lhs + rhs);
294}
295
296template <typename T> inline void addingOperator(std::vector<T> &lhs, const std::vector<T> &rhs) {
297 // This concatenates the two
298 if (&lhs != &rhs) {
299 lhs.insert(lhs.end(), rhs.begin(), rhs.end());
300 } else {
301 std::vector<T> rhs_copy(rhs);
302 lhs.insert(lhs.end(), rhs_copy.begin(), rhs_copy.end());
303 }
304}
305
306template <> inline void addingOperator(bool &, const bool &) {
307 throw Exception::NotImplementedError("PropertyWithValue.h: += operator not implemented for type bool");
308}
309
310template <> inline void addingOperator(OptionalBool &, const OptionalBool &) {
311 throw Exception::NotImplementedError("PropertyWithValue.h: += operator not implemented for type OptionalBool");
312}
313
314template <typename T> inline void addingOperator(std::shared_ptr<T> &, const std::shared_ptr<T> &) {
315 throw Exception::NotImplementedError("PropertyWithValue.h: += operator not implemented for std::shared_ptr");
316}
317
318template <typename T> inline std::vector<std::string> determineAllowedValues(const T &, const IValidator &validator) {
319 return validator.allowedValues();
320}
321
322template <> inline std::vector<std::string> determineAllowedValues(const OptionalBool &, const IValidator &) {
323 auto enumMap = OptionalBool::enumToStrMap();
324 std::vector<std::string> values;
325 values.reserve(enumMap.size());
326 std::transform(enumMap.cbegin(), enumMap.cend(), std::back_inserter(values),
327 [](const std::pair<OptionalBool::Value, std::string> &str) { return str.second; });
328 return values;
329}
330
331} // namespace Kernel
332} // namespace Mantid
const std::vector< double > & rhs
double value
The value of the point.
Definition FitMW.cpp:51
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
Marks code as not implemented yet.
Definition Exception.h:138
IValidator is the basic interface for all validators for properties.
Definition IValidator.h:43
virtual std::vector< std::string > allowedValues() const
The set of allowed values that this validator may have, if a discrete set exists.
Definition IValidator.h:77
OptionalBool : Tri-state bool.
static std::map< Value, std::string > enumToStrMap()
Iterator begin()
Iterator referring to first element in the container.
@ TOK_IGNORE_EMPTY
ignore empty tokens
@ TOK_TRIM
remove leading and trailing whitespace from tokens
Iterator end()
Iterator referring to the past-the-end element in the container.
ConstIterator cend() const
Const iterator referring to the past-the-end element in the container.
ConstIterator cbegin() const
Const iterator referring to first element in the container.
std::size_t count() const
Get the total number of tokens.
DLLExport std::string joinCompress(ITERATOR_TYPE begin, ITERATOR_TYPE end, const std::string &separator=",", const std::string &listSeparator="-")
Join a set or vector of (something that turns into a string) together into one string,...
Definition Strings.h:197
MANTID_KERNEL_DLL std::string shorten(const std::string &input, const size_t max_length)
Converts long strings into "start ... end".
Definition Strings.cpp:52
DLLExport std::string join(ITERATOR_TYPE begin, ITERATOR_TYPE end, const std::string &separator, typename std::enable_if<!(std::is_same< typename std::iterator_traits< ITERATOR_TYPE >::iterator_category, std::random_access_iterator_tag >::value)>::type *=nullptr)
Join a set or vector of (something that turns into a string) together into one string,...
Definition Strings.h:84
void toValue(const std::string &strvalue, std::vector< T > &value, std::true_type)
T extractToValueVector(const std::string &strvalue)
void toValue(const std::string &strvalue, T &value)
void appendValue(const std::string &strvalue, std::vector< T > &value)
std::string toString(const T &value)
Convert values to strings.
std::vector< std::string > determineAllowedValues(const T &, const IValidator &validator)
void addingOperator(T &lhs, const T &rhs)
int findSize(const T &)
Specialization for any type, should be appropriate for properties with a single value.
std::string toPrettyString(const T &value, size_t maxLength=0, bool collapseLists=true)
Convert values to pretty strings.
Helper class which provides the Collimation Length for SANS instruments.