Skip to content
Snippets Groups Projects
Commit 6f40ba8f authored by Nick Draper's avatar Nick Draper
Browse files

Shoeten arrays with integer lists

re #15164
parent c91acba9
No related branches found
No related tags found
No related merge requests found
...@@ -7,8 +7,11 @@ ...@@ -7,8 +7,11 @@
#endif #endif
#include "MantidKernel/OptionalBool.h" #include "MantidKernel/OptionalBool.h"
#include "MantidKernel/Strings.h"
#include "MantidKernel/StringTokenizer.h" #include "MantidKernel/StringTokenizer.h"
#include <type_traits>
namespace Mantid { namespace Mantid {
namespace Kernel { namespace Kernel {
...@@ -25,21 +28,44 @@ template <typename T> std::string toString(const boost::shared_ptr<T> &value) { ...@@ -25,21 +28,44 @@ template <typename T> std::string toString(const boost::shared_ptr<T> &value) {
throw boost::bad_lexical_cast(); throw boost::bad_lexical_cast();
} }
/// Specialisation for a property of type std::vector. /** Specialization for a property of type std::vector of non integral types.
* This will catch Vectors of char, double, float etc.
* This simply concatenates the values using a delimiter
*/
template <typename T> template <typename T>
std::string toString(const std::vector<T> &value, std::string toString(const std::vector<T> &value,
const std::string &delimiter = ",") { const std::string &delimiter = ",",
std::stringstream result; typename std::enable_if<!(std::is_integral<T>::value && std::is_arithmetic<T>::value)>::type* = 0) {
std::size_t vsize = value.size(); return Strings::join(value.begin(), value.end(), delimiter);
for (std::size_t i = 0; i < vsize; ++i) { }
result << value[i];
if (i + 1 != vsize) /** Specialization for a property of type std::vector of integral types.
result << delimiter; * This will catch Vectors of int, long, long long etc
} * including signed and unsigned types of these.
return result.str(); * This concatenates the values using a delimiter,
* adjacent items that are precisely 1 away from each other
* will be compressed into a list syntax e.g. 1-5.
*/
template <typename T>
std::string toString(const std::vector<T> &value,
const std::string &delimiter = ",",
typename std::enable_if<std::is_integral<T>::value && std::is_arithmetic<T>::value>::type* = 0) {
return Strings::joinCompress(value.begin(), value.end(), delimiter, "-");
}
/** Explicit specialization for a property of type std::vector<bool>.
* This will catch Vectors of char, double, float etc.
* This simply concatenates the values using a delimiter
*/
template <>
std::string toString(const std::vector<bool> &value,
const std::string &delimiter,
typename std::enable_if<std::is_same<bool,bool>::value>::type*) {
return Strings::join(value.begin(), value.end(), delimiter);
} }
/// Specialisation for a property of type std::vector<std::vector>. /// Specialization for a property of type std::vector<std::vector>.
template <typename T> template <typename T>
std::string toString(const std::vector<std::vector<T>> &value, std::string toString(const std::vector<std::vector<T>> &value,
const std::string &outerDelimiter = ",", const std::string &outerDelimiter = ",",
...@@ -60,11 +86,11 @@ std::string toString(const std::vector<std::vector<T>> &value, ...@@ -60,11 +86,11 @@ std::string toString(const std::vector<std::vector<T>> &value,
return result.str(); return result.str();
} }
/// Specialisation for any type, should be appropriate for properties with a /// Specialization for any type, should be appropriate for properties with a
/// single value. /// single value.
template <typename T> int findSize(const T &) { return 1; } template <typename T> int findSize(const T &) { return 1; }
/// Specialisation for properties that are of type vector. /// Specialization for properties that are of type vector.
template <typename T> int findSize(const std::vector<T> &value) { template <typename T> int findSize(const std::vector<T> &value) {
return static_cast<int>(value.size()); return static_cast<int>(value.size());
} }
......
...@@ -71,6 +71,65 @@ DLLExport std::string join(ITERATOR_TYPE begin, ITERATOR_TYPE end, ...@@ -71,6 +71,65 @@ DLLExport std::string join(ITERATOR_TYPE begin, ITERATOR_TYPE end,
return output.str(); return output.str();
} }
//------------------------------------------------------------------------------------------------
/** Join a set or vector of (something that turns into a string) together
* into one string, separated by a separator,
* adjacent items that are precisely 1 away from each other
* will be compressed into a list syntax e.g. 1-5.
* Returns an empty string if the range is null.
* Does not add the separator after the LAST item.
*
* For example, join a vector of strings with commas with:
* out = join(v.begin(), v.end(), ", ");
*
* @param begin :: iterator at the start
* @param end :: iterator at the end
* @param separator :: string to append between items.
* @param listSeparator :: string to append between list items.
* @return
*/
template <typename ITERATOR_TYPE>
DLLExport std::string joinCompress(ITERATOR_TYPE begin, ITERATOR_TYPE end,
const std::string &separator = ",",
const std::string &listSeparator = "-") {
std::stringstream result;
ITERATOR_TYPE i;
ITERATOR_TYPE previousValue;
std::string currentSeparator = separator;
for (i = begin; i != end;) {
// was this one higher than the last value
if (i == begin) {
//Special case, always include the first value
result << *i;
} else {
//if it is one higher than the last value
if (*i == (*previousValue + 1)) {
currentSeparator = listSeparator;
} else {
if (currentSeparator == listSeparator) {
//add the last value that was the end of the list
result << currentSeparator;
result << *previousValue;
currentSeparator = separator;
}
// add the current value
result << currentSeparator;
result << *i;
}
}
previousValue = i;
i++;
// if we have got to the end and part of a list output the last value
if ((i == end) && (currentSeparator == listSeparator)) {
result << currentSeparator;
result << *previousValue;
}
}
return result.str();
}
/// Return a string with all matching occurence-strings /// Return a string with all matching occurence-strings
MANTID_KERNEL_DLL std::string replace(const std::string &input, MANTID_KERNEL_DLL std::string replace(const std::string &input,
const std::string &find_what, const std::string &find_what,
......
...@@ -26,8 +26,8 @@ public: ...@@ -26,8 +26,8 @@ public:
TS_ASSERT(!iProp->documentation().compare("")) TS_ASSERT(!iProp->documentation().compare(""))
TS_ASSERT(typeid(std::vector<int>) == *iProp->type_info()) TS_ASSERT(typeid(std::vector<int>) == *iProp->type_info())
TS_ASSERT(iProp->isDefault()) TS_ASSERT(iProp->isDefault())
TS_ASSERT(iProp->operator()().empty()) TS_ASSERT(iProp->operator()().empty());
TS_ASSERT(!dProp->name().compare("doubleProp")) TS_ASSERT(!dProp->name().compare("doubleProp"))
TS_ASSERT(!dProp->documentation().compare("")) TS_ASSERT(!dProp->documentation().compare(""))
TS_ASSERT(typeid(std::vector<double>) == *dProp->type_info()) TS_ASSERT(typeid(std::vector<double>) == *dProp->type_info())
...@@ -82,7 +82,7 @@ public: ...@@ -82,7 +82,7 @@ public:
TS_ASSERT_EQUALS(i.operator()()[0], 1); TS_ASSERT_EQUALS(i.operator()()[0], 1);
TS_ASSERT_EQUALS(i.operator()()[1], 2); TS_ASSERT_EQUALS(i.operator()()[1], 2);
TS_ASSERT_EQUALS(i.operator()()[2], 3); TS_ASSERT_EQUALS(i.operator()()[2], 3);
TS_ASSERT_EQUALS(i.getDefault(), i_stringValue); TS_ASSERT_EQUALS(i.getDefault(), "1-3");
TS_ASSERT(i.isDefault()); TS_ASSERT(i.isDefault());
ArrayProperty<int> i2("i", "-1-1"); ArrayProperty<int> i2("i", "-1-1");
...@@ -301,6 +301,79 @@ public: ...@@ -301,6 +301,79 @@ public:
static_cast<Property *>(0)) static_cast<Property *>(0))
} }
void testListShortening() {
std::vector<std::string> inputList{
"1,2,3",
"-1,0,1",
"356,366,367,368,370,371,372,375",
"7,6,5,6,7,8,10",
"1-9998, 9999, 2000, 20002-29999"
};
std::vector<std::string> resultList{
"1-3",
"-1-1",
"356,366-368,370-372,375",
"7,6,5-8,10",
"1-9999,2000,20002-29999"
};
TSM_ASSERT("Test Failed for vectors of int", listShorteningwithType<int>(inputList, resultList));
TSM_ASSERT("Test Failed for vectors of long", listShorteningwithType<long>(inputList, resultList));
TSM_ASSERT("Test Failed for vectors of long long", listShorteningwithType<long long>(inputList, resultList));
// explicit test for in32_t with matches det_id_t and spec_id_t
TSM_ASSERT("Test Failed for vectors of int32_t", listShorteningwithType<int32_t>(inputList, resultList));
//unsigned types
std::vector<std::string> inputListUnsigned{
"1,2,3",
"356,366,367,368,370,371,372,375",
"7,6,5,6,7,8,10",
"1-9998, 9999, 2000, 20002-29999"
};
std::vector<std::string> resultListUnsigned{
"1-3",
"356,366-368,370-372,375",
"7,6,5-8,10",
"1-9999,2000,20002-29999"
};
TSM_ASSERT("Test Failed for vectors of unsigned int",
listShorteningwithType<unsigned int>(inputListUnsigned, resultListUnsigned));
TSM_ASSERT("Test Failed for vectors of size_t",
listShorteningwithType<size_t>(inputListUnsigned, resultListUnsigned));
//check shortening does not happen for floating point types
std::vector<std::string> inputListFloat{
"1.0,2.0,3.0",
"1.0,1.5,2.0,3.0",
"-1,0,1",
};
std::vector<std::string> resultListFloat{
"1,2,3",
"1,1.5,2,3",
"-1,0,1",
};
TSM_ASSERT("Test Failed for vectors of float",
listShorteningwithType<float>(inputListFloat, resultListFloat));
TSM_ASSERT("Test Failed for vectors of double",
listShorteningwithType<double>(inputListFloat, resultListFloat));
}
template <typename T>
bool listShorteningwithType(const std::vector<std::string>& inputList,
const std::vector<std::string>& resultList) {
bool success = true;
for (size_t i = 0; i < inputList.size(); i++) {
ArrayProperty<T> intListProperty("i", inputList[i]);
TS_ASSERT_EQUALS(intListProperty.value(), resultList[i]);
if (intListProperty.value() != resultList[i]) {
success = false;
}
}
return success;
}
private: private:
ArrayProperty<int> *iProp; ArrayProperty<int> *iProp;
ArrayProperty<double> *dProp; ArrayProperty<double> *dProp;
......
...@@ -267,6 +267,28 @@ public: ...@@ -267,6 +267,28 @@ public:
TS_ASSERT_EQUALS(out, "Help,Me,I'm,Stuck,Inside,A,Test"); TS_ASSERT_EQUALS(out, "Help,Me,I'm,Stuck,Inside,A,Test");
} }
void test_joinCompress() {
std::vector<std::vector<int>> inputList{
{1,2,3},
{-1,0,1},
{356,366,367,368,370,371,372,375},
{7,6,5,6,7,8,10}
};
std::vector<std::string> resultList{
"1-3",
"-1-1",
"356,366-368,370-372,375",
"7,6,5-8,10"
};
for (size_t i = 0; i < inputList.size(); i++) {
const auto& inputVector = inputList[i];
TS_ASSERT_EQUALS(joinCompress(inputVector.begin(), inputVector.end(),",","-"), resultList[i]);
}
}
void test_endsWithInt() { void test_endsWithInt() {
TS_ASSERT_EQUALS(endsWithInt("pixel22"), 22); TS_ASSERT_EQUALS(endsWithInt("pixel22"), 22);
TS_ASSERT_EQUALS(endsWithInt("pixel000123"), 123); TS_ASSERT_EQUALS(endsWithInt("pixel000123"), 123);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment