phrocker commented on a change in pull request #585: MINIFICPP-910 - Extend StringUtils with string join capability URL: https://github.com/apache/nifi-minifi-cpp/pull/585#discussion_r292914049
########## File path: libminifi/include/utils/StringUtils.h ########## @@ -92,172 +103,104 @@ class StringUtils { * @returns modified string */ - static inline std::string trimRight(std::string s) { - s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::pointer_to_unary_function<int, int>(isspace))).base(), s.end()); + inline std::string trimRight(std::string s) { + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::pointer_to_unary_function<int, int>(std::isspace))).base(), s.end()); return s; } + /** + * Trims a string left to right + * @param s incoming string + * @returns modified string + */ + inline std::string trim(std::string s) { + return trimRight(trimLeft(s)); + } + /** * Compares strings by lower casing them. */ - static inline bool equalsIgnoreCase(const std::string &left, const std::string right) { + inline bool equalsIgnoreCase(const std::string &left, const std::string right) { if (left.length() == right.length()) { - return std::equal(right.begin(), right.end(), left.begin(), [](unsigned char lc, unsigned char rc) {return tolower(lc) == tolower(rc);}); + return std::equal(right.begin(), right.end(), left.begin(), [](unsigned char lc, unsigned char rc) {return std::tolower(lc) == std::tolower(rc);}); } else { return false; } } - static std::vector<std::string> split(const std::string &str, const std::string &delimiter) { - std::vector<std::string> result; - auto curr = str.begin(); - auto end = str.end(); - auto is_func = [delimiter](int s) { - return delimiter.at(0) == s; - }; - while (curr != end) { - curr = std::find_if_not(curr, end, is_func); - if (curr == end) { - break; - } - auto next = std::find_if(curr, end, is_func); - result.push_back(std::string(curr, next)); - curr = next; - } - - return result; - } + std::vector<std::string> split(const std::string &str, const std::string &delimiter); /** * Converts a string to a float * @param input input string * @param output output float * @param cp failure policy */ - static bool StringToFloat(std::string input, float &output, FailurePolicy cp = RETURN) { - try { - output = std::stof(input); - } catch (const std::invalid_argument &ie) { - switch (cp) { - case RETURN: - case NOTHING: - return false; - case EXIT: - exit(1); - case EXCEPT: - throw ie; - } - } catch (const std::out_of_range &ofr) { - switch (cp) { - case RETURN: - case NOTHING: - return false; - case EXIT: - exit(1); - case EXCEPT: - throw ofr; + bool StringToFloat(std::string input, float &output, FailurePolicy cp = RETURN); - } - } - - return true; + std::string& replaceAll(std::string& source_string, const std::string &from_string, const std::string &to_string); - } - - static std::string replaceEnvironmentVariables(std::string& original_string) { - int32_t beg_seq = 0; - int32_t end_seq = 0; - std::string source_string = original_string; - do { - beg_seq = source_string.find("${", beg_seq); - if (beg_seq > 0 && source_string.at(beg_seq - 1) == '\\') { - beg_seq += 2; - continue; - } - if (beg_seq < 0) - break; - end_seq = source_string.find("}", beg_seq + 2); - if (end_seq < 0) - break; - if (end_seq - (beg_seq + 2) < 0) { - beg_seq += 2; - continue; - } - const std::string env_field = source_string.substr(beg_seq + 2, end_seq - (beg_seq + 2)); - const std::string env_field_wrapped = source_string.substr(beg_seq, end_seq + 1); - if (env_field.empty()) { - continue; - } - const auto strVal = std::getenv(env_field.c_str()); - std::string env_value; - if (strVal != nullptr) - env_value = strVal; - source_string = replaceAll(source_string, env_field_wrapped, env_value); - beg_seq = 0; // restart - } while (beg_seq >= 0); - - source_string = replaceAll(source_string, "\\$", "$"); - - return source_string; - } + std::string replaceMap(std::string source_string, const std::map<std::string, std::string> &replace_map); - static std::string& replaceAll(std::string& source_string, const std::string &from_string, const std::string &to_string) { - std::size_t loc = 0; - std::size_t lastFound; - while ((lastFound = source_string.find(from_string, loc)) != std::string::npos) { - source_string.replace(lastFound, from_string.size(), to_string); - loc = lastFound + to_string.size(); - } - return source_string; - } + std::string replaceEnvironmentVariables(const std::string& original_string); - inline static bool endsWithIgnoreCase(const std::string &value, const std::string & endString) { + inline bool endsWithIgnoreCase(const std::string &value, const std::string & endString) { if (endString.size() > value.size()) return false; return std::equal(endString.rbegin(), endString.rend(), value.rbegin(), [](unsigned char lc, unsigned char rc) {return tolower(lc) == tolower(rc);}); } - inline static bool endsWith(const std::string &value, const std::string & endString) { + inline bool endsWith(const std::string &value, const std::string & endString) { if (endString.size() > value.size()) return false; return std::equal(endString.rbegin(), endString.rend(), value.rbegin()); } - inline static std::string hex_ascii(const std::string& in) { - int len = in.length(); - std::string newString; - for (int i = 0; i < len; i += 2) { - std::string sstr = in.substr(i, 2); - char chr = (char) (int) strtol(sstr.c_str(), 0x00, 16); - newString.push_back(chr); - } - return newString; - } - - static std::string replaceMap(std::string source_string, const std::map<std::string, std::string> &replace_map) { - auto result_string = source_string; - - std::vector<std::pair<size_t, std::pair<size_t, std::string>>> replacements; - for (const auto &replace_pair : replace_map) { - size_t replace_pos = 0; - while ((replace_pos = source_string.find(replace_pair.first, replace_pos)) != std::string::npos) { - replacements.emplace_back(std::make_pair(replace_pos, std::make_pair(replace_pair.first.length(), replace_pair.second))); - replace_pos += replace_pair.first.length(); + std::string hex_ascii(const std::string& in); + + template<class TChar, class U, typename std::enable_if<std::is_same<typename U::value_type, std::basic_string<TChar>>::value>::type* = nullptr> + std::basic_string<TChar> join(const std::basic_string<TChar>& separator, const U& container) { + typedef typename U::const_iterator ITtype; + ITtype it = container.cbegin(); + std::basic_stringstream<TChar> sstream; + while(it != container.cend()) { + sstream << (*it); + ++it; + if(it != container.cend()) { + sstream << separator; } } - - std::sort(replacements.begin(), replacements.end(), [](const std::pair<size_t, std::pair<size_t, std::string>> a, - const std::pair<size_t, std::pair<size_t, std::string>> &b) { - return a.first > b.first; - }); - - for (const auto &replacement : replacements) { - result_string = source_string.replace(replacement.first, replacement.second.first, replacement.second.second); + return sstream.str(); + }; + + template<class TChar, class U, typename std::enable_if<std::is_same<typename U::value_type, std::basic_string<TChar>>::value>::type* = nullptr> + std::basic_string<TChar> join(const TChar* separator, const U& container) { + return join(std::basic_string<TChar>(separator), container); + }; + + + template<class TChar, class U, typename std::enable_if<std::is_integral<typename U::value_type>::value>::type* = nullptr, + typename std::enable_if<!std::is_same<U, std::basic_string<TChar>>::value>::type* = nullptr> + std::basic_string<TChar> join(const std::basic_string<TChar>& separator, const U& container) { + typedef typename U::const_iterator ITtype; + ITtype it = container.cbegin(); + std::basic_stringstream<TChar> sstream; + while(it != container.cend()) { + sstream << string_traits<TChar>::convert_to_string(*it); Review comment: This seems to enforce a semantic. I think basic stringstream assumes character if it is one. In that case, I don't see the need for the complexity as you could have one function that assumes what streamstream does and an overload that allows uint8_t to be interpreted with to_string. Two functions, much simpler and cleaner. Removing the rest of the changes will alleviate any linker issues. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services