Merge string utils to one file
Reviewers: buda Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D281
This commit is contained in:
parent
541c3f0af7
commit
5434e79ea6
@ -324,9 +324,6 @@ set(memgraph_src_files
|
||||
${src_dir}/config/config.cpp
|
||||
${src_dir}/dbms/dbms.cpp
|
||||
# ${src_dir}/dbms/cleaner.cpp
|
||||
${src_dir}/utils/string/transform.cpp
|
||||
${src_dir}/utils/string/join.cpp
|
||||
${src_dir}/utils/string/file.cpp
|
||||
${src_dir}/utils/numerics/saturate.cpp
|
||||
${src_dir}/io/network/addrinfo.cpp
|
||||
${src_dir}/io/network/network_endpoint.cpp
|
||||
|
@ -10,23 +10,31 @@ namespace fs = std::experimental::filesystem;
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
#include "utils/string/trim.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
std::string extract_query(const fs::path &path) {
|
||||
/**
|
||||
* Reads a query from the file specified by the path argument.
|
||||
* The first line of a query should start with "// Query: ". Query can be
|
||||
* in more than one line but every line has to start with "//".
|
||||
*
|
||||
* @param path to the query file.
|
||||
* @return query as a string.
|
||||
*/
|
||||
|
||||
std::string ExtractQuery(const fs::path &path) {
|
||||
auto comment_mark = std::string("// ");
|
||||
auto query_mark = comment_mark + std::string("Query: ");
|
||||
auto lines = utils::read_lines(path);
|
||||
auto lines = utils::ReadLines(path);
|
||||
// find the line with a query (the query can be split across multiple
|
||||
// lines)
|
||||
for (int i = 0; i < (int)lines.size(); ++i) {
|
||||
for (int i = 0; i < static_cast<int>(lines.size()); ++i) {
|
||||
// find query in the line
|
||||
auto &line = lines[i];
|
||||
auto pos = line.find(query_mark);
|
||||
// if query doesn't exist pass
|
||||
if (pos == std::string::npos) continue;
|
||||
auto query = utils::trim(line.substr(pos + query_mark.size()));
|
||||
while (i + 1 < (int)lines.size() &&
|
||||
auto query = utils::Trim(line.substr(pos + query_mark.size()));
|
||||
while (i + 1 < static_cast<int>(lines.size()) &&
|
||||
lines[i + 1].find(comment_mark) != std::string::npos) {
|
||||
query += lines[i + 1].substr(lines[i + 1].find(comment_mark) +
|
||||
comment_mark.length());
|
||||
@ -61,7 +69,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
QueryPreprocessor preprocessor;
|
||||
for (auto &src_file : src_files) {
|
||||
auto query = extract_query(src_file);
|
||||
auto query = ExtractQuery(src_file);
|
||||
auto query_hash = preprocessor.preprocess(query).hash;
|
||||
auto dst_file = dst_path / fs::path(std::to_string(query_hash) + ".cpp");
|
||||
fs::copy(src_file, dst_file, fs::copy_options::overwrite_existing);
|
||||
|
@ -9,10 +9,10 @@ namespace fs = std::experimental::filesystem;
|
||||
#include "logging/loggable.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/frontend/opencypher/parser.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "query/plan_compiler.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "query/preprocessor.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "utils/dynamic_lib.hpp"
|
||||
|
||||
/**
|
||||
@ -26,11 +26,12 @@ namespace fs = std::experimental::filesystem;
|
||||
* the results should be returned (more optimal then just return
|
||||
* the whole result set)
|
||||
*/
|
||||
template <typename Stream> class QueryEngine : public Loggable {
|
||||
private:
|
||||
template <typename Stream>
|
||||
class QueryEngine : public Loggable {
|
||||
private:
|
||||
using QueryPlanLib = DynamicLib<QueryPlanTrait<Stream>>;
|
||||
|
||||
public:
|
||||
public:
|
||||
QueryEngine() : Loggable("QueryEngine") {}
|
||||
|
||||
/**
|
||||
@ -63,7 +64,6 @@ public:
|
||||
*/
|
||||
auto Run(const std::string &query, GraphDbAccessor &db_accessor,
|
||||
Stream &stream) {
|
||||
|
||||
if (CONFIG_BOOL(config::INTERPRET)) {
|
||||
query::Interpret(query, db_accessor, stream);
|
||||
return true;
|
||||
@ -109,12 +109,12 @@ public:
|
||||
*
|
||||
* @return size_t the number of loaded query plans
|
||||
*/
|
||||
auto Size() { // TODO: const once whan ConcurrentMap::Accessor becomes const
|
||||
auto Size() { // TODO: const once whan ConcurrentMap::Accessor becomes const
|
||||
return query_plans.access().size();
|
||||
}
|
||||
// return query_plans.access().size(); }
|
||||
|
||||
private:
|
||||
private:
|
||||
/**
|
||||
* Loads query plan eather from hardcoded folder or from the file that is
|
||||
* generated in this method.
|
||||
@ -175,13 +175,13 @@ private:
|
||||
auto path_so = CONFIG(config::COMPILE_PATH) + std::to_string(hash) + "_" +
|
||||
(std::string)Timestamp::now() + ".so";
|
||||
|
||||
plan_compiler.compile(path_cpp, path_so);
|
||||
plan_compiler.Compile(path_cpp, path_so);
|
||||
|
||||
auto query_plan = std::make_unique<QueryPlanLib>(path_so);
|
||||
// TODO: underlying object has to be live during query execution
|
||||
// fix that when Antler will be introduced into the database
|
||||
|
||||
auto query_plan_instance = query_plan->instance(); // because of move
|
||||
auto query_plan_instance = query_plan->instance(); // because of move
|
||||
plans_accessor.insert(hash, std::move(query_plan));
|
||||
|
||||
// return an instance of runnable code (PlanInterface)
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "logging/loggable.hpp"
|
||||
#include "query/exceptions.hpp"
|
||||
#include "query/plan_compiler_flags.hpp"
|
||||
#include "utils/string/join.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
// TODO:
|
||||
// * all libraries have to be compiled in the server compile time
|
||||
@ -27,19 +27,18 @@ class PlanCompiler : public Loggable {
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void compile(const std::string &in_file, const std::string &out_file) {
|
||||
void Compile(const std::string &in_file, const std::string &out_file) {
|
||||
// generate compile command
|
||||
auto compile_command = utils::prints(
|
||||
"clang++", compile_flags,
|
||||
auto compile_command =
|
||||
utils::Join({"clang++", compile_flags,
|
||||
#ifdef HARDCODED_OUTPUT_STREAM
|
||||
"-DHARDCODED_OUTPUT_STREAM",
|
||||
"-DHARDCODED_OUTPUT_STREAM",
|
||||
#endif
|
||||
in_file, // input file
|
||||
"-o", out_file, // ouput file
|
||||
include_dirs,
|
||||
link_dirs, "-lmemgraph_pic",
|
||||
"-shared -fPIC" // shared library flags
|
||||
);
|
||||
in_file, // input file
|
||||
"-o", out_file, // ouput file
|
||||
include_dirs, link_dirs, "-lmemgraph_pic",
|
||||
"-shared -fPIC"}, // shared library flags
|
||||
" ");
|
||||
|
||||
logger.debug("compile command -> {}", compile_command);
|
||||
|
||||
|
@ -1,17 +1,25 @@
|
||||
#include "template_engine/engine.hpp"
|
||||
|
||||
#include "utils/string/replace.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace template_engine {
|
||||
|
||||
string render(const string& form, const data& partials) {
|
||||
/**
|
||||
* Replaces all placeholders in the form string marked as {{ key }} with values
|
||||
* defined in the partials dictionary.
|
||||
*
|
||||
* @param form template string.
|
||||
* @param partials values to inject into the template string.
|
||||
* @return string rendered based on template string and values.
|
||||
*/
|
||||
std::string Render(const std::string &form, const data &partials) {
|
||||
// TODO more optimal implementation
|
||||
// another option is something like https://github.com/no1msd/mstch
|
||||
// but it has to be wrapped
|
||||
string rendered = form;
|
||||
for (auto partial : partials) {
|
||||
for (const auto &partial : partials) {
|
||||
string key = "{{" + partial.first + "}}";
|
||||
rendered = utils::replace(rendered, key, partial.second);
|
||||
rendered = utils::Replace(rendered, key, partial.second);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
namespace template_engine {
|
||||
|
||||
using std::string;
|
||||
using data = std::unordered_map<string, string>;
|
||||
using data = std::unordered_map<std::string, std::string>;
|
||||
|
||||
string render(const string& form, const data& partials);
|
||||
std::string Render(const string& form, const data& partials);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <experimental/filesystem>
|
||||
#include <fstream>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
namespace utils {
|
||||
@ -50,4 +50,36 @@ inline auto LoadFilePaths(const fs::path &directory,
|
||||
|
||||
return file_paths;
|
||||
}
|
||||
|
||||
// TODO: add error checking
|
||||
/**
|
||||
* Reads all lines from the file specified by path.
|
||||
*
|
||||
* @param path file path.
|
||||
* @return vector of all lines from the file.
|
||||
*/
|
||||
std::vector<std::string> ReadLines(const fs::path &path) {
|
||||
std::vector<std::string> lines;
|
||||
|
||||
std::ifstream stream(path.c_str());
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) {
|
||||
lines.emplace_back(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes test into the file specified by path.
|
||||
*
|
||||
* @param text content which will be written in the file.
|
||||
* @param path a path to the file.
|
||||
*/
|
||||
void Write(const std::string &text, const fs::path &path) {
|
||||
std::ofstream stream;
|
||||
stream.open(path.c_str());
|
||||
stream << text;
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <limits.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <unistd.h>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
95
src/utils/string.hpp
Normal file
95
src/utils/string.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 prev(end) exists.
|
||||
return s;
|
||||
}
|
||||
while (begin != end && isspace(*begin)) {
|
||||
++begin;
|
||||
}
|
||||
while (prev(end) != begin && isspace(*prev(end))) {
|
||||
--end;
|
||||
}
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string with all lowercased characters (locale independent).
|
||||
*/
|
||||
std::string ToLowerCase(std::string s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](char c) { return tolower(c); });
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return string with all uppercased characters (locale independent).
|
||||
*/
|
||||
std::string ToUpperCase(std::string s) {
|
||||
std::string s2(s.size(), ' ');
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](char c) { return toupper(c); });
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join strings in vector separated by a given separator.
|
||||
*/
|
||||
std::string Join(const std::vector<std::string>& strings,
|
||||
const char* separator) {
|
||||
std::ostringstream oss;
|
||||
std::copy(strings.begin(), strings.end(),
|
||||
std::ostream_iterator<std::string>(oss, separator));
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all occurences of <match> in <src> with <replacement>.
|
||||
*/
|
||||
// TODO: This could be implemented much more efficient.
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split string by delimeter and return vector of results.
|
||||
*/
|
||||
std::vector<std::string> Split(const std::string& src,
|
||||
const std::string& delimiter) {
|
||||
size_t index = 0;
|
||||
std::vector<std::string> res;
|
||||
size_t n = src.find(delimiter, index);
|
||||
while (n != std::string::npos) {
|
||||
n = src.find(delimiter, index);
|
||||
res.push_back(src.substr(index, n - index));
|
||||
index = n + delimiter.size();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "intercalate.hpp"
|
||||
#include "linereader.hpp"
|
||||
#include "replace.hpp"
|
||||
#include "split.hpp"
|
@ -1,38 +0,0 @@
|
||||
#include "utils/string/file.hpp"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace utils {
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
Text read_text(const fs::path &path) {
|
||||
std::ifstream in(path, std::ios::in | std::ios::binary);
|
||||
|
||||
if (in)
|
||||
return Text(std::string(std::istreambuf_iterator<char>(in),
|
||||
std::istreambuf_iterator<char>()));
|
||||
|
||||
auto error_message = fmt::format("{0}{1}", "Fail to read: ", path.c_str());
|
||||
throw std::runtime_error(error_message);
|
||||
}
|
||||
|
||||
std::vector<std::string> read_lines(const fs::path &path) {
|
||||
std::vector<std::string> lines;
|
||||
|
||||
std::ifstream stream(path.c_str());
|
||||
std::string line;
|
||||
while (std::getline(stream, line)) {
|
||||
lines.emplace_back(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
void write(const Text &text, const fs::path &path) {
|
||||
std::ofstream stream;
|
||||
stream.open(path.c_str());
|
||||
stream << text.str();
|
||||
stream.close();
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cerrno>
|
||||
#include <fstream>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
// TODO: remove experimental from here once that becomes possible
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* Type safe text object.
|
||||
*/
|
||||
class Text {
|
||||
public:
|
||||
Text() = default;
|
||||
explicit Text(const std::string& text) : text_(text) {}
|
||||
|
||||
// text could be huge and copy operationt would be too expensive
|
||||
Text(const Text& other) = delete;
|
||||
Text& operator=(const Text& other) = delete;
|
||||
|
||||
// the object is movable
|
||||
Text(Text&& other) = default;
|
||||
Text& operator=(Text&& other) {
|
||||
text_ = std::move(other.text_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string& str() const { return text_; }
|
||||
|
||||
private:
|
||||
std::string text_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Reads the whole text from a file at the path.
|
||||
*/
|
||||
Text read_text(const fs::path& path);
|
||||
|
||||
/*
|
||||
* Reads all the lines from a file at the path.
|
||||
*/
|
||||
std::vector<std::string> read_lines(const fs::path& path);
|
||||
|
||||
// TODO: lazy implementation of read_lines functionality (line by line)
|
||||
|
||||
// TODO: read word by word + lazy implementation
|
||||
|
||||
/*
|
||||
* Write text in a file at the path.
|
||||
*/
|
||||
void write(const Text& text, const fs::path& path);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
template <typename It>
|
||||
std::string intercalate(It first, It last, const std::string& separator) {
|
||||
if (first == last) return "";
|
||||
|
||||
std::stringstream ss;
|
||||
It second(first);
|
||||
|
||||
// append the first N-1 elements with a separator
|
||||
for (second++; second != last; ++first, ++second) ss << *first << separator;
|
||||
|
||||
// append the last element
|
||||
ss << *first;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#include "utils/string/join.hpp"
|
||||
|
||||
namespace utils {
|
||||
|
||||
std::string join(const std::vector<std::string>& strings,
|
||||
const char* separator) {
|
||||
std::ostringstream oss;
|
||||
std::copy(strings.begin(), strings.end(),
|
||||
std::ostream_iterator<std::string>(oss, separator));
|
||||
return oss.str();
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
|
||||
std::string join(const std::vector<std::string>& strings,
|
||||
const char* separator);
|
||||
|
||||
template <typename... Args>
|
||||
std::string prints(const Args&... args) {
|
||||
std::vector<std::string> strings = {args...};
|
||||
return join(strings, " ");
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
void linereader(std::istream& stream,
|
||||
std::function<void(const std::string&)> cb) {
|
||||
std::string line;
|
||||
|
||||
while (std::getline(stream, line)) cb(line);
|
||||
}
|
||||
|
||||
void linereader(const std::string& filename,
|
||||
std::function<void(const std::string&)> cb) {
|
||||
std::fstream fs(filename.c_str());
|
||||
|
||||
// should this throw an error? figure out how to handle this TODO
|
||||
|
||||
if (fs.is_open() == false)
|
||||
throw std::runtime_error("[ERROR] can't open file " + filename);
|
||||
|
||||
linereader(fs, cb);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
// replaces all occurences of <match> in <src> with <replacement>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
|
||||
std::vector<std::string> split(const std::string& src,
|
||||
const std::string& delimiter) {
|
||||
size_t index = 0;
|
||||
std::vector<std::string> res;
|
||||
size_t n = src.find(delimiter, index);
|
||||
|
||||
while (n != std::string::npos) {
|
||||
n = src.find(delimiter, index);
|
||||
res.push_back(src.substr(index, n - index));
|
||||
index = n + delimiter.size();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// doesn't work with gcc even though it's only c++11...
|
||||
// and it's slow as hell compared to the split implementation above
|
||||
// (more powerful though)
|
||||
|
||||
std::vector<std::string> regex_split(const std::string& input,
|
||||
const std::string& regex) {
|
||||
auto rgx = std::regex(regex);
|
||||
|
||||
std::sregex_token_iterator last, first{input.begin(), input.end(), rgx, -1};
|
||||
|
||||
return {first, last};
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <x86intrin.h>
|
||||
|
||||
namespace sse42 {
|
||||
constexpr int strcmp_mode = _SIDD_CMP_EQUAL_EACH | _SIDD_NEGATIVE_POLARITY;
|
||||
|
||||
constexpr unsigned CF = 0x1;
|
||||
constexpr unsigned ZF = 0x40;
|
||||
|
||||
bool streq(const char* lhs, const char* rhs) {
|
||||
int idx, eflags;
|
||||
|
||||
while (true) {
|
||||
auto lhs_mm = _mm_loadu_si128((__m128i*)lhs);
|
||||
auto rhs_mm = _mm_loadu_si128((__m128i*)rhs);
|
||||
|
||||
idx = _mm_cmpistri(lhs_mm, rhs_mm, strcmp_mode);
|
||||
eflags = __readeflags();
|
||||
|
||||
if (idx != 0x10) return false;
|
||||
|
||||
if ((eflags & (ZF | CF)) != 0) return true;
|
||||
|
||||
lhs += 16;
|
||||
rhs += 16;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#include "utils/string/transform.hpp"
|
||||
|
||||
namespace utils {
|
||||
|
||||
// TODO CPPCheck -> function never used
|
||||
void str_tolower(std::string& s) {
|
||||
// en_US.utf8 localization
|
||||
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) {
|
||||
return std::tolower(c, std::locale("en_US.utf8"));
|
||||
});
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
void str_tolower(std::string& s);
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
std::string trim(const std::string &str) {
|
||||
size_t first = str.find_first_not_of(' ');
|
||||
if (std::string::npos == first) {
|
||||
return str;
|
||||
}
|
||||
size_t last = str.find_last_not_of(' ');
|
||||
return str.substr(first, (last - first + 1));
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/total_ordering.hpp"
|
||||
#include "utils/total_ordering_with.hpp"
|
||||
|
||||
class WeakString {
|
||||
public:
|
||||
constexpr WeakString() : str(nullptr), len(0) {}
|
||||
|
||||
WeakString(const std::string& str) : str(str.c_str()), len(str.size()) {}
|
||||
|
||||
WeakString(const char* str) : str(str), len(strlen(str)) {}
|
||||
|
||||
constexpr WeakString(const char* str, size_t len) : str(str), len(len) {}
|
||||
|
||||
const char& operator[](size_t idx) const {
|
||||
debug_assert(idx < len, "Index not smaller than length.");
|
||||
return str[idx];
|
||||
}
|
||||
|
||||
const char& front() const {
|
||||
debug_assert(len > 0, "String is empty.");
|
||||
return str[0];
|
||||
}
|
||||
|
||||
const char& back() const {
|
||||
debug_assert(len > 0, "String is empty.");
|
||||
return str[len - 1];
|
||||
}
|
||||
|
||||
const char* data() const { return str; }
|
||||
|
||||
bool empty() const { return len == 0; }
|
||||
|
||||
size_t size() const { return len; }
|
||||
|
||||
size_t length() const { return size(); }
|
||||
|
||||
std::string to_string() const { return std::string(str, len); }
|
||||
|
||||
friend bool operator==(const WeakString& lhs, const WeakString rhs) {
|
||||
// oh dear god, make this better with custom iterators
|
||||
if (lhs.size() != rhs.size()) return false;
|
||||
|
||||
for (size_t i = 0; i < lhs.size(); ++i)
|
||||
if (lhs[i] != rhs[i]) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool operator!=(const WeakString& lhs, const WeakString& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
const char* str;
|
||||
size_t len;
|
||||
};
|
@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace utils {
|
||||
|
||||
/*
|
||||
* Variadic argument print
|
||||
*/
|
||||
template <class Head>
|
||||
void print_vargs(std::ostream& s, Head&& head) {
|
||||
s << std::forward<Head>(head);
|
||||
}
|
||||
template <class Head, class... Tail>
|
||||
void print_vargs(std::ostream& s, Head&& head, Tail&&... tail) {
|
||||
s << std::forward<Head>(head);
|
||||
print_vargs(s, std::forward<Tail>(tail)...);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile time print line.
|
||||
*
|
||||
* USAGE:
|
||||
* RUN: utils::printer("ONE ", "TWO");
|
||||
* OUTPUT: "ONE TWO\n"
|
||||
*
|
||||
* TODO: reimplament with C++17 fold expressions
|
||||
*/
|
||||
template <class... Args>
|
||||
void println(Args&&... args) {
|
||||
print_vargs(std::cout, std::forward<Args>(args)...);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// value equality with any of variadic argument
|
||||
// example: value == varg[0] OR value == varg[1] OR ...
|
||||
|
||||
template <class Value, class Head>
|
||||
bool _or_vargs(Value&& value, Head&& head) {
|
||||
return value == head;
|
||||
}
|
||||
template <class Value, class Head, class... Tail>
|
||||
bool _or_vargs(Value&& value, Head&& head, Tail&&... tail) {
|
||||
return value == head || _or_vargs(std::forward<Value>(value), tail...);
|
||||
}
|
||||
template <class Value, class... Array>
|
||||
bool or_vargs(Value&& value, Array&&... array) {
|
||||
return _or_vargs(std::forward<Value>(value), std::forward<Array>(array)...);
|
||||
}
|
||||
}
|
@ -12,8 +12,7 @@ namespace fs = std::experimental::filesystem;
|
||||
#include "stream/print_record_stream.hpp"
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
#include "utils/file.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
#include "utils/string/trim.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace tests {
|
||||
namespace integration {
|
||||
@ -55,7 +54,7 @@ auto LoadQueryHashes(Logger &log, const fs::path &path) {
|
||||
// hashes calculated from all queries in queries file
|
||||
QueryHashesT query_hashes;
|
||||
// fill the above set
|
||||
auto queries = utils::read_lines(path);
|
||||
auto queries = utils::ReadLines(path);
|
||||
for (auto &query : queries) {
|
||||
if (query.empty()) continue;
|
||||
query_hashes.insert(preprocessor.preprocess(query).hash);
|
||||
@ -86,7 +85,7 @@ auto LoadQueryPlans(Logger &log, QueryEngineT &engine,
|
||||
auto comment = std::string("// ");
|
||||
auto query_mark = comment + std::string("Query: ");
|
||||
for (auto &plan_path : plan_paths) {
|
||||
auto lines = read_lines(plan_path);
|
||||
auto lines = utils::ReadLines(plan_path);
|
||||
// find the line with a query in order
|
||||
// be able to place it in the dynamic libs container (base on query
|
||||
// hash)
|
||||
@ -96,7 +95,7 @@ auto LoadQueryPlans(Logger &log, QueryEngineT &engine,
|
||||
auto pos = line.find(query_mark);
|
||||
// if query doesn't exist pass
|
||||
if (pos == std::string::npos) continue;
|
||||
auto query = trim(line.substr(pos + query_mark.size()));
|
||||
auto query = utils::Trim(line.substr(pos + query_mark.size()));
|
||||
while (i + 1 < (int)lines.size() &&
|
||||
lines[i + 1].find(comment) != std::string::npos) {
|
||||
query +=
|
||||
@ -131,10 +130,10 @@ auto ExecuteQueryPlans(Logger &log, QueryEngineT &engine, Dbms &dbms,
|
||||
const fs::path &path, StreamT &stream) {
|
||||
log.info("*** Execute the queries from the queries_file ***");
|
||||
// execute all queries from queries_file
|
||||
auto queries = utils::read_lines(path);
|
||||
auto queries = utils::ReadLines(path);
|
||||
for (auto &query : queries) {
|
||||
if (query.empty()) continue;
|
||||
permanent_assert(engine.Loaded(trim(query)),
|
||||
permanent_assert(engine.Loaded(utils::Trim(query)),
|
||||
"Implementation wasn't loaded");
|
||||
// Create new db_accessor since one query is associated with one
|
||||
// transaction.
|
||||
|
@ -41,14 +41,14 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
auto comment = std::string("// ");
|
||||
auto query_mark = comment + std::string("Query: ");
|
||||
auto lines = read_lines(event.path);
|
||||
auto lines = utils::ReadLines(event.path);
|
||||
for (int i = 0; i < (int)lines.size(); ++i) {
|
||||
// find query in the line
|
||||
auto& line = lines[i];
|
||||
auto pos = line.find(query_mark);
|
||||
// if query doesn't exist pass
|
||||
if (pos == std::string::npos) continue;
|
||||
auto query = trim(line.substr(pos + query_mark.size()));
|
||||
auto query = utils::Trim(line.substr(pos + query_mark.size()));
|
||||
while (i + 1 < (int)lines.size() &&
|
||||
lines[i + 1].find(comment) != std::string::npos) {
|
||||
query += lines[i + 1].substr(lines[i + 1].find(comment) +
|
||||
|
@ -5,11 +5,7 @@
|
||||
#include "logging/streams/stdout.hpp"
|
||||
#include "query/preprocessor.hpp"
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
#include "utils/type_discovery.hpp"
|
||||
#include "utils/variadic/variadic.hpp"
|
||||
|
||||
using utils::println;
|
||||
|
||||
/**
|
||||
* Useful when somebody wants to get a hash for some query.
|
||||
@ -32,13 +28,14 @@ int main(int argc, char **argv) {
|
||||
auto preprocessed = preprocessor.preprocess(query);
|
||||
|
||||
// print query, stripped query, hash and variable values (propertie values)
|
||||
println("Query: ", query);
|
||||
println("Stripped query: ", preprocessed.query);
|
||||
println("Query hash: ", preprocessed.hash);
|
||||
println("Property values:");
|
||||
for (int i = 0; i < preprocessed.arguments.Size(); ++i)
|
||||
println(" ", preprocessed.arguments.At(i));
|
||||
println("");
|
||||
std::cout << fmt::format("Query: {}\n", query);
|
||||
std::cout << fmt::format("Stripped query: {}\n", preprocessed.query);
|
||||
std::cout << fmt::format("Query hash: {}\n", preprocessed.hash);
|
||||
std::cout << fmt::format("Property values:\n");
|
||||
for (int i = 0; i < static_cast<int>(preprocessed.arguments.Size()); ++i) {
|
||||
fmt::format(" {}", preprocessed.arguments.At(i));
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "template_engine/engine.hpp"
|
||||
|
||||
TEST(TemplateEngine, BasicPlaceholderReplacement) {
|
||||
auto rendered = template_engine::render("{{one}} {{two}}",
|
||||
auto rendered = template_engine::Render("{{one}} {{two}}",
|
||||
{{"one", "two"}, {"two", "one"}});
|
||||
|
||||
ASSERT_EQ(rendered, "two one");
|
||||
|
Loading…
Reference in New Issue
Block a user