utils: Support std::basic_string with allocators

Reviewers: mtomic, mferencevic, msantl

Reviewed By: mtomic

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2102
This commit is contained in:
Teon Banek 2019-05-29 13:37:11 +02:00
parent c0dc37fe34
commit 38c6625e2c
9 changed files with 338 additions and 260 deletions

View File

@ -807,7 +807,7 @@ TypedValue Right(TypedValue *args, int64_t nargs, const EvaluationContext &,
case TypedValue::Type::Null: \
return TypedValue::Null; \
case TypedValue::Type::String: \
return function(args[0].ValueString()); \
return std::string(function(args[0].ValueString())); \
default: \
throw QueryRuntimeException("'" #lowercased_name \
"' argument should be a string."); \

View File

@ -142,15 +142,23 @@ inline bool Contains(const TIterable &iterable, const TElement &element) {
}
/**
* Returns a *copy* of a collection with its elements in reversed order.
*
* @param collection Collection to be reversed.
* Return a reversed copy of the given collection.
* The copy is allocated using the default allocator.
*/
template <class TCollection>
TCollection Reversed(const TCollection &collection) {
return TCollection(std::rbegin(collection), std::rend(collection));
}
/**
* Return a reversed copy of the given collection.
* The copy is allocated with the given `alloc`.
*/
template <class TCollection, class TAllocator>
TCollection Reversed(const TCollection &collection, const TAllocator &alloc) {
return TCollection(std::rbegin(collection), std::rend(collection), alloc);
}
/**
* Converts a (beginning, end) pair of iterators into an iterable that can be
* passed on to itertools.

View File

@ -1,3 +1,4 @@
/** @file */
#pragma once
#include <algorithm>
@ -9,284 +10,328 @@
#include <regex>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include "utils/exceptions.hpp"
namespace utils {
/**
* Removes whitespace characters from the start of a string.
*
* @param str string that is going to be trimmed
*
* @return trimmed string
*/
inline std::string LTrim(const std::string &s) {
auto begin = s.begin();
auto end = s.end();
if (begin == end) {
// Need to check this to be sure that std::prev(end) exists.
return s;
/** Remove whitespace characters from the start of a string. */
inline std::string_view LTrim(const std::string_view &s) {
size_t start = 0;
while (start < s.size() && isspace(s[start])) {
++start;
}
while (begin < end && isspace(*begin)) {
++begin;
return std::string_view(s.data() + start, s.size() - start);
}
/** Remove characters found in `chars` from the start of a string. */
inline std::string_view LTrim(const std::string_view &s,
const std::string_view &chars) {
size_t start = 0;
while (start < s.size() && chars.find(s[start]) != std::string::npos) {
++start;
}
return std::string(begin, end);
return std::string_view(s.data() + start, s.size() - start);
}
/** Remove whitespace characters from the end of a string. */
inline std::string_view RTrim(const std::string_view &s) {
size_t count = s.size();
while (count > static_cast<size_t>(0) && isspace(s[count - 1])) {
--count;
}
return std::string_view(s.data(), count);
}
/** Remove characters found in `chars` from the end of a string. */
inline std::string_view RTrim(const std::string_view &s,
const std::string_view &chars) {
size_t count = s.size();
while (count > static_cast<size_t>(0) &&
chars.find(s[count - 1]) != std::string::npos) {
--count;
}
return std::string_view(s.data(), count);
}
/** Remove whitespace characters from the start and from the end of a string. */
inline std::string_view Trim(const std::string_view &s) {
size_t start = 0;
size_t count = s.size();
while (start < s.size() && isspace(s[start])) {
++start;
}
while (count > start && isspace(s[count - 1])) {
--count;
}
return std::string_view(s.data() + start, count - start);
}
/** Remove characters found in `chars` from the start and the end of `s`. */
inline std::string_view Trim(const std::string_view &s,
const std::string_view &chars) {
size_t start = 0;
size_t count = s.size();
while (start < s.size() && chars.find(s[start]) != std::string::npos) {
++start;
}
while (count > start && chars.find(s[count - 1]) != std::string::npos) {
--count;
}
return std::string_view(s.data() + start, count - start);
}
/**
* Removes characters contained in chars from the start of a string.
*
* @param s string that is going to be trimmed
* @param chars string that contains chars that are to be removed
*
* @return trimmed string
* Lowercase all characters of a string and store the result in `out`.
* Transformation is locale independent.
* @return pointer to `out`.
*/
inline std::string LTrim(const std::string &s, const std::string &chars) {
auto begin = s.begin();
auto end = s.end();
if (begin == end) {
// Need to check this to be sure that std::prev(end) exists.
return s;
}
while (begin < end && chars.find(*begin) != std::string::npos) {
++begin;
}
return std::string(begin, end);
}
/**
* Removes whitespace characters from the end of a string.
*
* @param str string that is going to be trimmed
*
* @return trimmed string
*/
inline std::string RTrim(const std::string &s) {
auto begin = s.begin();
auto end = s.end();
if (begin == end) {
// Need to check this to be sure that std::prev(end) exists.
return s;
}
while (end > begin && isspace(*std::prev(end))) {
--end;
}
return std::string(begin, end);
}
/**
* Removes characters contained in chars from the end of a string.
*
* @param s string that is going to be trimmed
* @param chars string that contains chars that are to be removed
*
* @return trimmed string
*/
inline std::string RTrim(const std::string &s, const std::string &chars) {
auto begin = s.begin();
auto end = s.end();
if (begin == end) {
// Need to check this to be sure that std::prev(end) exists.
return s;
}
while (end > begin && chars.find(*std::prev(end)) != std::string::npos) {
--end;
}
return std::string(begin, end);
}
/**
* Removes whitespace characters from the start and from the end of a string.
*
* @param str string that is going to be trimmed
*
* @return trimmed string
*/
inline std::string Trim(const std::string &s) {
auto begin = s.begin();
auto end = s.end();
if (begin == end) {
// Need to check this to be sure that std::prev(end) exists.
return s;
}
while (begin < end && isspace(*begin)) {
++begin;
}
while (end > begin && isspace(*std::prev(end))) {
--end;
}
return std::string(begin, end);
}
/**
* Removes characters contained in chars from the start and the end of a string.
*
* @param s string that is going to be trimmed
* @param chars string that contains chars that are to be removed
*
* @return trimmed string
*/
inline std::string Trim(const std::string &s, const std::string &chars) {
auto begin = s.begin();
auto end = s.end();
if (begin == end) {
// Need to check this to be sure that std::prev(end) exists.
return s;
}
while (begin < end && chars.find(*begin) != std::string::npos) {
++begin;
}
while (end > begin && chars.find(*std::prev(end)) != std::string::npos) {
--end;
}
return std::string(begin, end);
}
/**
* Return string with all lowercased characters (locale independent).
*/
inline std::string ToLowerCase(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
template <class TAllocator>
std::basic_string<char, std::char_traits<char>, TAllocator> *ToLowerCase(
std::basic_string<char, std::char_traits<char>, TAllocator> *out,
const std::string_view &s) {
out->resize(s.size());
std::transform(s.begin(), s.end(), out->begin(),
[](char c) { return tolower(c); });
return s;
return out;
}
/**
* Return string with all uppercased characters (locale independent).
* Lowercase all characters of a string.
* Transformation is locale independent.
*/
inline std::string ToUpperCase(std::string s) {
std::transform(s.begin(), s.end(), s.begin(),
inline std::string ToLowerCase(const std::string_view &s) {
std::string res;
ToLowerCase(&res, s);
return res;
}
/**
* Uppercase all characters of a string and store the result in `out`.
* Transformation is locale independent.
* @return pointer to `out`.
*/
template <class TAllocator>
std::basic_string<char, std::char_traits<char>, TAllocator> *ToUpperCase(
std::basic_string<char, std::char_traits<char>, TAllocator> *out,
const std::string_view &s) {
out->resize(s.size());
std::transform(s.begin(), s.end(), out->begin(),
[](char c) { return toupper(c); });
return s;
return out;
}
/**
* Join strings in vector separated by a given separator.
* Uppercase all characters of a string and store the result in `out`.
* Transformation is locale independent.
*/
inline std::string Join(const std::vector<std::string> &strings,
const std::string &separator) {
if (strings.size() == 0U) return "";
inline std::string ToUpperCase(const std::string_view &s) {
std::string res;
ToUpperCase(&res, s);
return res;
}
/**
* Join the `strings` collection separated by a given separator into `out`.
* @return pointer to `out`.
*/
template <class TCollection, class TAllocator>
std::basic_string<char, std::char_traits<char>, TAllocator> *Join(
std::basic_string<char, std::char_traits<char>, TAllocator> *out,
const TCollection &strings, const std::string_view &separator) {
out->clear();
if (strings.empty()) return out;
int64_t total_size = 0;
for (const auto &x : strings) {
total_size += x.size();
}
total_size += separator.size() * (static_cast<int64_t>(strings.size()) - 1);
std::string s;
s.reserve(total_size);
s += strings[0];
out->reserve(total_size);
*out += strings[0];
for (auto it = strings.begin() + 1; it != strings.end(); ++it) {
s += separator;
s += *it;
*out += separator;
*out += *it;
}
return s;
return out;
}
/**
* Replaces all occurences of <match> in <src> with <replacement>.
* Join the `strings` collection separated by a given separator.
*/
// TODO: This could be implemented much more efficiently.
inline std::string Replace(std::string src, const std::string &match,
const std::string &replacement) {
for (size_t pos = src.find(match); pos != std::string::npos;
pos = src.find(match, pos + replacement.size())) {
src.erase(pos, match.length()).insert(pos, replacement);
}
return src;
inline std::string Join(const std::vector<std::string> &strings,
const std::string_view &separator) {
std::string res;
Join(&res, strings, separator);
return res;
}
/**
* Split string by delimeter and return vector of results.
*
* @param src - The string to split.
* @param delimitier - The delimiter to split on.
* @param splits - The maximum number of splits. For the given value N the
* returned vector will contain at most (N + 1) elements. If given a negative
* value, all possible splits are performed.
* @return - a vector of splits.
* Replace all occurrences of `match` in `src` with `replacement`.
* @return pointer to `out`.
*/
inline std::vector<std::string> Split(const std::string &src,
const std::string &delimiter,
int splits = -1) {
std::vector<std::string> res;
if (src.empty()) {
return res;
template <class TAllocator>
std::basic_string<char, std::char_traits<char>, TAllocator> *Replace(
std::basic_string<char, std::char_traits<char>, TAllocator> *out,
const std::string_view &src, const std::string_view &match,
const std::string_view &replacement, const TAllocator &alloc) {
// TODO: This could be implemented much more efficiently.
*out = src;
for (size_t pos = out->find(match); pos != std::string::npos;
pos = out->find(match, pos + replacement.size())) {
out->erase(pos, match.length()).insert(pos, replacement);
}
return out;
}
/** Replace all occurrences of `match` in `src` with `replacement`. */
inline std::string Replace(const std::string_view &src,
const std::string_view &match,
const std::string_view &replacement) {
std::string res;
Replace(&res, src, match, replacement, std::allocator<char>());
return res;
}
/**
* Split a string by `delimiter` with a maximum of `splits` into a vector.
* The vector will have at most `splits` + 1 elements. Negative value of
* `splits` indicates to perform all possible splits.
* @return pointer to `out`.
*/
template <class TString, class TAllocator>
std::vector<TString, TAllocator> *Split(std::vector<TString, TAllocator> *out,
const std::string_view &src,
const std::string_view &delimiter,
int splits = -1) {
out->clear();
if (src.empty()) return out;
size_t index = 0;
while (splits < 0 || splits-- != 0) {
auto n = src.find(delimiter, index);
if (n == std::string::npos) break;
res.emplace_back(src.substr(index, n - index));
out->emplace_back(src.substr(index, n - index));
index = n + delimiter.size();
}
res.emplace_back(src.substr(index));
return res;
out->emplace_back(src.substr(index));
return out;
}
/**
* Split string by delimiter, from right to left, and return vector of results.
* For example, RSplit("a.b.c.", ".", 1) results in {"a.b", "c"}.
*
* @param src - The string to split.
* @param delimitier - The delimiter to split on.
* @param splits - The maximum number of splits. For the given value N the
* returned vector will contain at most (N + 1) elements. If given a negative
* value, all possible splits are performed.
* Split a string by `delimiter` with a maximum of `splits` into a vector.
* The vector will have at most `splits` + 1 elements. Negative value of
* `splits` indicates to perform all possible splits.
*/
inline std::vector<std::string> RSplit(const std::string &src,
const std::string &delimiter,
int splits = -1) {
inline std::vector<std::string> Split(const std::string_view &src,
const std::string_view &delimiter,
int splits = -1) {
std::vector<std::string> res;
if (src.empty()) {
return res;
}
size_t index = src.size();
while (splits < 0 || splits-- != 0) {
auto n = src.rfind(delimiter, index - 1);
if (n == std::string::npos) break;
res.emplace_back(
src.substr(n + delimiter.size(), index - n - delimiter.size()));
index = n;
if (n == 0) break;
}
res.emplace_back(src.substr(0, index));
std::reverse(res.begin(), res.end());
Split(&res, src, delimiter, splits);
return res;
}
/**
* Split string by whitespace and return vector of results.
* Split a string by whitespace into a vector.
* Runs of consecutive whitespace are regarded as a single delimiter.
* Additionally, the result will not contain empty strings at the start or end
* as if the string was trimmed before splitting.
* @return pointer to `out`.
*/
template <class TString, class TAllocator>
std::vector<TString, TAllocator> *Split(std::vector<TString, TAllocator> *out,
const std::string_view &src) {
out->clear();
if (src.empty()) return out;
// TODO: Investigate how much regex allocate and perhaps replace with custom
// solution doing no allocations.
std::regex not_whitespace("[^\\s]+");
auto matches_begin =
std::cregex_iterator(src.data(), src.data() + src.size(), not_whitespace);
auto matches_end = std::cregex_iterator();
out->reserve(std::distance(matches_begin, matches_end));
for (auto match = matches_begin; match != matches_end; ++match) {
std::string_view match_view(&src[match->position()], match->length());
out->emplace_back(match_view);
}
return out;
}
/**
* Split a string by whitespace into a vector.
* Runs of consecutive whitespace are regarded as a single delimiter.
* Additionally, the result will not contain empty strings at the start or end
* as if the string was trimmed before splitting.
*/
inline std::vector<std::string> Split(const std::string &src) {
if (src.empty()) {
return {};
}
std::regex not_whitespace("[^\\s]+");
auto matches_begin =
std::sregex_iterator(src.begin(), src.end(), not_whitespace);
auto matches_end = std::sregex_iterator();
inline std::vector<std::string> Split(const std::string_view &src) {
std::vector<std::string> res;
res.reserve(std::distance(matches_begin, matches_end));
for (auto match = matches_begin; match != matches_end; ++match) {
res.emplace_back(match->str());
}
Split(&res, src);
return res;
}
/**
* Parse double using classic locale, throws BasicException if it wasn't able to
* parse whole string.
* Like `Split` but string is processed from right to left.
* For example, RSplit("a.b.c.", ".", 1) results in {"a.b", "c"}.
* The returned vector and its elements use `std::allocator<>`. The vector will
* have at most `splits` + 1 elements. Negative value of `splits` indicates to
* perform all possible splits.
* @return pointer to `out`.
*/
inline double ParseDouble(const std::string &s) {
template <class TString, class TAllocator>
std::vector<TString, TAllocator> *RSplit(std::vector<TString, TAllocator> *out,
const std::string_view &src,
const std::string_view &delimiter,
int splits = -1) {
out->clear();
if (src.empty()) return out;
size_t index = src.size();
while (splits < 0 || splits-- != 0) {
auto n = src.rfind(delimiter, index - 1);
if (n == std::string::npos) break;
out->emplace_back(
src.substr(n + delimiter.size(), index - n - delimiter.size()));
index = n;
if (n == 0) break;
}
out->emplace_back(src.substr(0, index));
std::reverse(out->begin(), out->end());
return out;
}
/**
* Like `Split` but string is processed from right to left.
* For example, RSplit("a.b.c.", ".", 1) results in {"a.b", "c"}.
* The returned vector and its elements use `std::allocator<>`. The vector will
* have at most `splits` + 1 elements. Negative value of `splits` indicates to
* perform all possible splits.
*/
inline std::vector<std::string> RSplit(const std::string_view &src,
const std::string_view &delimiter,
int splits = -1) {
std::vector<std::string> res;
RSplit(&res, src, delimiter, splits);
return res;
}
/**
* Parse a double floating point value from a string using classic locale.
* Note, the current implementation copies the given string which may perform a
* heap allocation if the string is big enough.
*
* @throw BasicException if unable to parse the whole string.
*/
inline double ParseDouble(const std::string_view &s) {
// stod would be nicer but it uses current locale so we shouldn't use it.
double t = 0.0;
std::istringstream iss(s);
// NOTE: Constructing std::istringstream will make a copy of the string, which
// may make a heap allocation if string is large enough. There is no
// std::istringstream constructor accepting a custom allocator. We could pass
// a std::basic_string with a custom allocator, but std::istringstream will
// probably invoke
// std::allocator_traits<>::select_on_container_copy_construction which
// doesn't really help as most allocators default to global new/delete
// allocator.
std::istringstream iss(std::string(s.data(), s.size()));
iss.imbue(std::locale::classic());
iss >> t;
if (iss.fail() || !iss.eof()) {
@ -295,25 +340,21 @@ inline double ParseDouble(const std::string &s) {
return t;
}
/**
* Checks if the given string `s` ends with the given `suffix`.
*/
inline bool EndsWith(const std::string &s, const std::string &suffix) {
/** Check if the given string `s` ends with the given `suffix`. */
inline bool EndsWith(const std::string_view &s,
const std::string_view &suffix) {
return s.size() >= suffix.size() &&
s.compare(s.size() - suffix.size(), std::string::npos, suffix) == 0;
}
/**
* Checks if the given string `s` starts with the given `prefix`.
*/
inline bool StartsWith(const std::string &s, const std::string &prefix) {
/** Check if the given string `s` starts with the given `prefix`. */
inline bool StartsWith(const std::string_view &s,
const std::string_view &prefix) {
return s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;
}
/**
* Case-insensitive string comparison.
*/
inline bool IEquals(const std::string &lhs, const std::string &rhs) {
/** Perform case-insensitive string equality test. */
inline bool IEquals(const std::string_view &lhs, const std::string_view &rhs) {
if (lhs.size() != rhs.size()) return false;
for (size_t i = 0; i < lhs.size(); ++i) {
if (tolower(lhs[i]) != tolower(rhs[i])) return false;
@ -321,8 +362,14 @@ inline bool IEquals(const std::string &lhs, const std::string &rhs) {
return true;
}
/** Creates a random alphanumeric string of the given length. */
inline std::string RandomString(size_t length) {
/**
* Create a random alphanumeric string of the given length.
* @return pointer to `out`.
*/
template <class TAllocator>
std::basic_string<char, std::char_traits<char>, TAllocator> *RandomString(
std::basic_string<char, std::char_traits<char>, TAllocator> *out,
size_t length) {
static const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@ -330,37 +377,57 @@ inline std::string RandomString(size_t length) {
static thread_local std::mt19937 pseudo_rand_gen{std::random_device{}()};
static thread_local std::uniform_int_distribution<size_t> rand_dist{
0, strlen(charset) - 1};
std::string str(length, 0);
out->resize(length);
for (size_t i = 0; i < length; ++i)
str[i] = charset[rand_dist(pseudo_rand_gen)];
return str;
(*out)[i] = charset[rand_dist(pseudo_rand_gen)];
return out;
}
/// Escapes all whitespace and quotation characters to produce a string
/// which can be used as a string literal.
inline std::string Escape(const std::string &src) {
std::string ret;
ret.reserve(src.size() + 2);
ret.append(1, '"');
/** Create a random alphanumeric string of the given length. */
inline std::string RandomString(size_t length) {
std::string res;
RandomString(&res, length);
return res;
}
/**
* Escape all whitespace and quotation characters in the given string.
* @return pointer to `out`.
*/
template <class TAllocator>
std::basic_string<char, std::char_traits<char>, TAllocator> *Escape(
std::basic_string<char, std::char_traits<char>, TAllocator> *out,
const std::string_view &src) {
out->clear();
out->reserve(src.size() + 2);
out->append(1, '"');
for (auto c : src) {
if (c == '\\' || c == '\'' || c == '"') {
ret.append(1, '\\');
ret.append(1, c);
out->append(1, '\\');
out->append(1, c);
} else if (c == '\b') {
ret.append("\\b");
out->append("\\b");
} else if (c == '\f') {
ret.append("\\f");
out->append("\\f");
} else if (c == '\n') {
ret.append("\\n");
out->append("\\n");
} else if (c == '\r') {
ret.append("\\r");
out->append("\\r");
} else if (c == '\t') {
ret.append("\\t");
out->append("\\t");
} else {
ret.append(1, c);
out->append(1, c);
}
}
ret.append(1, '"');
return ret;
out->append(1, '"');
return out;
}
/** Escape all whitespace and quotation characters in the given string. */
inline std::string Escape(const std::string_view &src) {
std::string res;
Escape(&res, src);
return res;
}
} // namespace utils

View File

@ -158,8 +158,9 @@ std::vector<io::network::Endpoint> GetEndpoints() {
for (const auto &endpoint : utils::Split(FLAGS_endpoints, ",")) {
auto split = utils::Split(utils::Trim(endpoint), ":");
CHECK(split.size() == 2) << "Invalid endpoint!";
ret.emplace_back(io::network::ResolveHostname(utils::Trim(split[0])),
static_cast<uint16_t>(std::stoi(utils::Trim(split[1]))));
ret.emplace_back(
io::network::ResolveHostname(std::string(utils::Trim(split[0]))),
static_cast<uint16_t>(std::stoi(std::string(utils::Trim(split[1])))));
}
return ret;
}

View File

@ -489,7 +489,7 @@ auto MakeLogicalPlans(query::CypherQuery *query, query::AstStorage &ast,
}
void RunInteractivePlanning(database::GraphDbAccessor *dba) {
auto in_db_filename = utils::Trim(FLAGS_load_mock_db_file);
std::string in_db_filename(utils::Trim(FLAGS_load_mock_db_file));
if (!in_db_filename.empty() && !std::filesystem::exists(in_db_filename)) {
std::cerr << "File '" << in_db_filename << "' does not exist!" << std::endl;
std::exit(EXIT_FAILURE);
@ -529,7 +529,7 @@ void RunInteractivePlanning(database::GraphDbAccessor *dba) {
std::cout << "Error: " << e.what() << std::endl;
}
}
auto db_filename = utils::Trim(FLAGS_save_mock_db_file);
std::string db_filename(utils::Trim(FLAGS_save_mock_db_file));
if (!db_filename.empty()) {
std::ofstream db_file(db_filename);
interactive_db.Save(db_file);

View File

@ -171,7 +171,7 @@ GraphState BuildFromConfig(int num_workers, const nlohmann::json &config) {
GraphState state(num_workers);
for (const auto &index : GetWithDefault(config, "indexes", {})) {
auto index_parts = utils::Split(index, ".");
auto index_parts = utils::Split(std::string(index), ".");
CHECK(index_parts.size() == 2) << "Index format should be Label.Property";
state.CreateIndex(index_parts[0], index_parts[1]);
}

View File

@ -12,6 +12,7 @@ TEST(String, LTrim) {
EXPECT_EQ(LTrim(" \t\n\r ab\r\n\t ab \r\t "), "ab\r\n\t ab \r\t ");
EXPECT_EQ(LTrim(" \t\n\r"), "");
EXPECT_EQ(LTrim("run()"), "run()");
EXPECT_EQ(LTrim("run()", "rn"), "un()");
EXPECT_EQ(LTrim(""), "");
}
@ -19,6 +20,7 @@ TEST(String, RTrim) {
EXPECT_EQ(RTrim(" \t\n\r ab\r\n\t ab \r\t "), " \t\n\r ab\r\n\t ab");
EXPECT_EQ(RTrim(" \t\n\r"), "");
EXPECT_EQ(RTrim("run()"), "run()");
EXPECT_EQ(RTrim("run()", "u()"), "run");
EXPECT_EQ(RTrim(""), "");
}

View File

@ -344,7 +344,7 @@ static std::optional<std::string> GetQuery() {
PrintHelp();
return "";
} else {
EchoFailure("Unsupported command", trimmed_line);
EchoFailure("Unsupported command", std::string(trimmed_line));
PrintHelp();
return "";
}

View File

@ -258,7 +258,7 @@ communication::bolt::Value StringToValue(const std::string &str,
std::vector<communication::bolt::Value> array;
array.reserve(elems.size());
for (const auto &elem : elems) {
array.push_back(convert(utils::Trim(elem), elem_type));
array.push_back(convert(std::string(utils::Trim(elem)), elem_type));
}
return array;
}
@ -279,7 +279,7 @@ void WriteNodeRow(
std::map<std::string, communication::bolt::Value> properties;
for (int i = 0; i < row.size(); ++i) {
const auto &field = fields[i];
auto value = utils::Trim(row[i]);
std::string value(utils::Trim(row[i]));
if (utils::StartsWith(field.type, "id")) {
CHECK(!id) << "Only one node ID must be specified";
NodeId node_id{value, GetIdSpace(field.type)};
@ -340,7 +340,7 @@ void WriteRelationshipsRow(
std::map<std::string, communication::bolt::Value> properties;
for (int i = 0; i < row.size(); ++i) {
const auto &field = fields[i];
auto value = utils::Trim(row[i]);
std::string value(utils::Trim(row[i]));
if (utils::StartsWith(field.type, "start_id")) {
CHECK(!start_id) << "Only one node ID must be specified";
NodeId node_id{value, GetIdSpace(field.type)};
@ -460,7 +460,7 @@ std::string GetOutputPath() {
// other flags which are defined in this file.
LoadConfig();
// Without durability_directory, we have to require 'out' flag.
auto durability_dir = utils::Trim(FLAGS_durability_directory);
std::string durability_dir(utils::Trim(FLAGS_durability_directory));
if (durability_dir.empty())
LOG(FATAL) << "Unable to determine snapshot output location. Please, "
"provide the 'out' flag";