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
25namespace {
27template <typename T> std::string toString(const T &value) { return boost::lexical_cast<std::string>(value); }
28
30template <typename T> std::string toString(const std::shared_ptr<T> &value) {
32 throw boost::bad_lexical_cast();
33}
34
36template <typename T> std::string toString(const std::vector<T> &value, const std::string &delimiter = ",") {
37 std::stringstream result;
38 std::size_t vsize = value.size();
39 for (std::size_t i = 0; i < vsize; ++i) {
40 result << value[i];
41 if (i + 1 != vsize)
42 result << delimiter;
43 }
44 return result.str();
45}
46
48template <typename T>
49std::string toString(const std::vector<std::vector<T>> &value, const std::string &outerDelimiter = ",",
50 const std::string &innerDelimiter = "+") {
51 std::stringstream result;
52 std::size_t vsize = value.size();
53 for (std::size_t i = 0; i < vsize; ++i) {
54 std::size_t innervsize = value[i].size();
55 for (std::size_t j = 0; j < innervsize; ++j) {
56 result << value[i][j];
57 if (j + 1 != innervsize)
58 result << innerDelimiter;
59 }
60
61 if (i + 1 != vsize)
62 result << outerDelimiter;
63 }
64 return result.str();
65}
66
67// --------------------- convert values to pretty strings
69template <typename T> std::string toPrettyString(const T &value, size_t maxLength = 0, bool collapseLists = true) {
70 UNUSED_ARG(collapseLists);
71 return Strings::shorten(boost::lexical_cast<std::string>(value), maxLength);
72}
73
75template <typename T>
76std::string toPrettyString(const std::shared_ptr<T> &value, size_t maxLength = 0, bool collapseLists = true) {
78 UNUSED_ARG(maxLength);
79 UNUSED_ARG(collapseLists);
80 throw boost::bad_lexical_cast();
81}
82
87template <typename T>
88std::string toPrettyString(
89 const std::vector<T> &value, size_t maxLength = 0, bool collapseLists = true, const std::string &delimiter = ",",
90 const std::string &unusedDelimiter = "+",
91 typename std::enable_if<!(std::is_integral<T>::value && std::is_arithmetic<T>::value)>::type * = nullptr) {
92 UNUSED_ARG(unusedDelimiter);
93 UNUSED_ARG(collapseLists);
94 return Strings::shorten(Strings::join(value.begin(), value.end(), delimiter), maxLength);
95}
96
104template <typename T>
105std::string
106toPrettyString(const std::vector<T> &value, size_t maxLength = 0, bool collapseLists = true,
107 const std::string &delimiter = ",", const std::string &listDelimiter = "-",
108 typename std::enable_if<std::is_integral<T>::value && std::is_arithmetic<T>::value>::type * = nullptr) {
109 std::string retVal;
110 if (collapseLists) {
111 retVal = Strings::joinCompress(value.begin(), value.end(), delimiter, listDelimiter);
112 } else {
113 retVal = Strings::join(value.begin(), value.end(), delimiter);
114 }
115 return Strings::shorten(retVal, maxLength);
116}
117
118GNU_DIAG_OFF("unused-function")
119
120
125template <>
126std::string toPrettyString(const std::vector<bool> &value, size_t maxLength, bool collapseLists,
127 const std::string &delimiter, const std::string &unusedDelimiter,
128 typename std::enable_if<std::is_same<bool, bool>::value>::type *) {
129 UNUSED_ARG(unusedDelimiter);
130 UNUSED_ARG(collapseLists);
131 return Strings::shorten(Strings::join(value.begin(), value.end(), delimiter), maxLength);
132}
133
134GNU_DIAG_ON("unused-function")
135
136
137template <typename T>
138std::string toPrettyString(const std::vector<std::vector<T>> &value, size_t maxLength = 0, bool collapseLists = true,
139 const std::string &outerDelimiter = ",", const std::string &innerDelimiter = "+") {
140 UNUSED_ARG(collapseLists);
141 return Strings::shorten(toString<T>(value, outerDelimiter, innerDelimiter), maxLength);
142}
143
146template <typename T> int findSize(const T &) { return 1; }
147
149template <typename T> int findSize(const std::vector<T> &value) { return static_cast<int>(value.size()); }
150
151// ------------- Convert strings to values
152template <typename T> inline void appendValue(const std::string &strvalue, std::vector<T> &value) {
153 // try to split the string
154 std::size_t pos = strvalue.find(':');
155 std::size_t numChar = std::string::npos; // go to the end of the string
156 T step{1};
157 if (pos == std::string::npos) {
158 pos = strvalue.find('-', 1);
159 } else {
160 const auto posStep = strvalue.find(':', pos + 1);
161 if (posStep != std::string::npos) {
162 step = boost::lexical_cast<T>(strvalue.substr(posStep + 1));
163 numChar = posStep - pos - 1;
164 }
165 }
166
167 // just convert the whole thing into a value
168 if (pos == std::string::npos) {
169 value.emplace_back(boost::lexical_cast<T>(strvalue));
170 return;
171 }
172
173 if (step == static_cast<T>(0))
174 throw std::logic_error("Step size must be non-zero");
175
176 // convert the input string into boundaries and run through a list
177 const auto start = boost::lexical_cast<T>(strvalue.substr(0, pos));
178 const auto stop = boost::lexical_cast<T>(strvalue.substr(pos + 1, numChar));
179 if (start <= stop) {
180 if (start + step < start)
181 throw std::logic_error("Step size is negative with increasing limits");
182 for (auto i = start; i <= stop;) {
183 value.emplace_back(i);
184 // done inside the loop because gcc7 doesn't like i+=step for short
185 // unsigned int
186 i = static_cast<T>(i + step);
187 }
188 } else {
189 if (start + step >= start)
190 throw std::logic_error("Step size is positive with decreasing limits");
191 for (auto i = start; i >= stop;) {
192 value.emplace_back(i);
193 // done inside the loop because gcc7 doesn't like i+=step for short
194 // unsigned int
195 i = static_cast<T>(i + step);
196 }
197 }
198}
199
200template <typename T> void toValue(const std::string &strvalue, T &value) { value = boost::lexical_cast<T>(strvalue); }
201
202template <typename T> void toValue(const std::string &, std::shared_ptr<T> &) { throw boost::bad_lexical_cast(); }
203
204namespace detail {
205// vector<int> specializations
206template <typename T> void toValue(const std::string &strvalue, std::vector<T> &value, std::true_type) {
209 value.clear();
210 value.reserve(values.count());
211 for (const auto &token : values) {
212 appendValue(token, value);
213 }
214}
215
216template <typename T> void toValue(const std::string &strvalue, std::vector<T> &value, std::false_type) {
217 // Split up comma-separated properties
220
221 value.clear();
222 value.reserve(values.count());
223 std::transform(values.cbegin(), values.cend(), std::back_inserter(value),
224 [](const std::string &str) { return boost::lexical_cast<T>(str); });
225}
226
227// bool and char don't make sense as types to generate a range of values.
228// This is similar to std::is_integral<T>, but bool and char are std::false_type
229template <class T> struct is_range_type : public std::false_type {};
230template <class T> struct is_range_type<const T> : public is_range_type<T> {};
231template <class T> struct is_range_type<volatile const T> : public is_range_type<T> {};
232template <class T> struct is_range_type<volatile T> : public is_range_type<T> {};
233
234template <> struct is_range_type<unsigned short> : public std::true_type {};
235template <> struct is_range_type<unsigned int> : public std::true_type {};
236template <> struct is_range_type<unsigned long> : public std::true_type {};
237template <> struct is_range_type<unsigned long long> : public std::true_type {};
238
239template <> struct is_range_type<short> : public std::true_type {};
240template <> struct is_range_type<int> : public std::true_type {};
241template <> struct is_range_type<long> : public std::true_type {};
242template <> struct is_range_type<long long> : public std::true_type {};
243} // namespace detail
244template <typename T> void toValue(const std::string &strvalue, std::vector<T> &value) {
245 detail::toValue(strvalue, value, detail::is_range_type<T>());
246}
247
248template <typename T>
249void toValue(const std::string &strvalue, std::vector<std::vector<T>> &value, const std::string &outerDelimiter = ",",
250 const std::string &innerDelimiter = "+") {
252 tokenizer tokens(strvalue, outerDelimiter, tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
253
254 value.clear();
255 value.reserve(tokens.count());
256
257 for (const auto &token : tokens) {
258 tokenizer values(token, innerDelimiter, tokenizer::TOK_IGNORE_EMPTY | tokenizer::TOK_TRIM);
259 std::vector<T> vect;
260 vect.reserve(values.count());
261 std::transform(values.begin(), values.end(), std::back_inserter(vect),
262 [](const std::string &str) { return boost::lexical_cast<T>(str); });
263 value.emplace_back(std::move(vect));
264 }
265}
266
267/*Used specifically to retrieve a vector of type T populated with values
268 * given to it from strvalue parameter, Using toValue method.
269 (See constructor used specifically for vector assignments)
270 */
271template <typename T> T extractToValueVector(const std::string &strvalue) {
272 T valueVec;
273 toValue(strvalue, valueVec);
274 return valueVec;
275}
276
277//------------------------------------------------------------------------------------------------
278// Templated += operator functions for specific types
279template <typename T> inline void addingOperator(T &lhs, const T &rhs) {
280 // The cast here (and the expansion of the compound operator which that
281 // necessitates) is because if this function is created for a template
282 // type narrower than an int, the compiler will expande the operands to
283 // ints which leads to a compiler warning when it's assigned back to the
284 // narrower type.
285 lhs = static_cast<T>(lhs + rhs);
286}
287
288template <typename T> inline void addingOperator(std::vector<T> &lhs, const std::vector<T> &rhs) {
289 // This concatenates the two
290 if (&lhs != &rhs) {
291 lhs.insert(lhs.end(), rhs.begin(), rhs.end());
292 } else {
293 std::vector<T> rhs_copy(rhs);
294 lhs.insert(lhs.end(), rhs_copy.begin(), rhs_copy.end());
295 }
296}
297
298template <> inline void addingOperator(bool &, const bool &) {
299 throw Exception::NotImplementedError("PropertyWithValue.h: += operator not implemented for type bool");
300}
301
302template <> inline void addingOperator(OptionalBool &, const OptionalBool &) {
303 throw Exception::NotImplementedError("PropertyWithValue.h: += operator not implemented for type OptionalBool");
304}
305
306template <typename T> inline void addingOperator(std::shared_ptr<T> &, const std::shared_ptr<T> &) {
307 throw Exception::NotImplementedError("PropertyWithValue.h: += operator not implemented for std::shared_ptr");
308}
309
310template <typename T> inline std::vector<std::string> determineAllowedValues(const T &, const IValidator &validator) {
311 return validator.allowedValues();
312}
313
314template <> inline std::vector<std::string> determineAllowedValues(const OptionalBool &, const IValidator &) {
315 auto enumMap = OptionalBool::enumToStrMap();
316 std::vector<std::string> values;
317 values.reserve(enumMap.size());
318 std::transform(enumMap.cbegin(), enumMap.cend(), std::back_inserter(values),
319 [](const std::pair<OptionalBool::Value, std::string> &str) { return str.second; });
320 return values;
321}
322} // namespace
323
324} // namespace Kernel
325} // 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:64
#define GNU_DIAG_ON(x)
#define GNU_DIAG_OFF(x)
This is a collection of macros for turning compiler warnings off in a controlled manner.
static std::map< Value, std::string > enumToStrMap()
@ TOK_IGNORE_EMPTY
ignore empty tokens
@ TOK_TRIM
remove leading and trailing whitespace from tokens
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:196
MANTID_KERNEL_DLL std::string shorten(const std::string &input, const size_t max_length)
Converts long strings into "start ... end".
Definition: Strings.cpp:54
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
std::string toString(const T &value)
Convert a number to a string.
Definition: Strings.cpp:703
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.