diff --git a/index_tests/outline/outline.cc b/index_tests/outline/outline.cc deleted file mode 100644 index 08b07313..00000000 --- a/index_tests/outline/outline.cc +++ /dev/null @@ -1,120 +0,0 @@ -#include - -struct MergeableUpdate { - int a; - int b; - std::vector to_add; -}; - -/* -TEXT_REPLACE: -std::__1::vector <===> std::vector -c:@N@std@ST>2#T#T@vector <===> c:@N@std@N@__1@ST>2#T#T@vector -10956461108384510180 <===> 9178760565669096175 - -OUTPUT: -{ - "includes": [{ - "line": 0, - "resolved_path": "&vector" - }], - "skipped_by_preprocessor": [], - "types": [{ - "id": 0, - "usr": 14399919566014425846, - "detailed_name": "MergeableUpdate", - "short_name": "MergeableUpdate", - "kind": 23, - "declarations": [], - "spell": "3:8-3:23|-1|1|2", - "extent": "3:1-7:2|-1|1|0", - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [0, 1, 2], - "instances": [], - "uses": [] - }, { - "id": 1, - "usr": 17, - "detailed_name": "", - "short_name": "", - "kind": 0, - "declarations": [], - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [0, 1], - "uses": [] - }, { - "id": 2, - "usr": 9178760565669096175, - "detailed_name": "std::vector", - "short_name": "vector", - "kind": 0, - "declarations": [], - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [2], - "uses": ["6:8-6:14|-1|1|4"] - }, { - "id": 3, - "usr": 5401847601697785946, - "detailed_name": "", - "short_name": "", - "kind": 0, - "declarations": [], - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [], - "uses": ["6:3-6:6|0|2|4"] - }], - "funcs": [], - "vars": [{ - "id": 0, - "usr": 11633578660978286467, - "detailed_name": "int MergeableUpdate::a", - "short_name": "a", - "declarations": [], - "spell": "4:7-4:8|0|2|2", - "extent": "4:3-4:8|0|2|0", - "type": 1, - "uses": [], - "kind": 8, - "storage": 0 - }, { - "id": 1, - "usr": 14949552147532317793, - "detailed_name": "int MergeableUpdate::b", - "short_name": "b", - "declarations": [], - "spell": "5:7-5:8|0|2|2", - "extent": "5:3-5:8|0|2|0", - "type": 1, - "uses": [], - "kind": 8, - "storage": 0 - }, { - "id": 2, - "usr": 9003350345237582363, - "detailed_name": "std::vector MergeableUpdate::to_add", - "short_name": "to_add", - "declarations": [], - "spell": "6:20-6:26|0|2|2", - "extent": "6:3-6:26|0|2|0", - "type": 2, - "uses": [], - "kind": 8, - "storage": 0 - }] -} -*/ diff --git a/index_tests/outline/outline2.cc b/index_tests/outline/outline2.cc deleted file mode 100644 index c5a31861..00000000 --- a/index_tests/outline/outline2.cc +++ /dev/null @@ -1,158 +0,0 @@ -//#pragma once - -#include -#include - -struct CompilationEntry { - std::string directory; - std::string filename; - std::vector args; -}; - -std::vector LoadCompilationEntriesFromDirectory(const std::string& project_directory); - -/* -TEXT_REPLACE: -std::__1::vector <===> std::vector -std::__1::string <===> std::string -std::__cxx11::string <===> std::string -c:@N@std@string <===> c:@N@std@N@__1@T@string -c:@N@std@T@string <===> c:@N@std@N@__1@T@string -c:@N@std@N@__cxx11@T@string <===> c:@N@std@N@__1@T@string -c:@N@std@ST>2#T#T@vector <===> c:@N@std@N@__1@ST>2#T#T@vector -c:@F@LoadCompilationEntriesFromDirectory#&1$@N@std@N@__1@S@basic_string>#C#$@N@std@N@__1@S@char_traits>#C#$@N@std@N@__1@S@allocator>#C# <===> c:@F@LoadCompilationEntriesFromDirectory#&1$@N@std@S@basic_string>#C#$@N@std@S@char_traits>#C#$@N@std@S@allocator>#C# -c:@F@LoadCompilationEntriesFromDirectory#&1$@N@std@N@__cxx11@S@basic_string>#C#$@N@std@S@char_traits>#C#$@N@std@S@allocator>#C# <===> c:@F@LoadCompilationEntriesFromDirectory#&1$@N@std@S@basic_string>#C#$@N@std@S@char_traits>#C#$@N@std@S@allocator>#C# -4160338041907786 <===> 14151982074805896770 -7543170857910783654 <===> 14151982074805896770 -9802818309312685221 <===> 11244864715202245734 -7636646237071509980 <===> 14151982074805896770 -9178760565669096175 <===> 10956461108384510180 -10468929532989002392 <===> 11244864715202245734 -4160338041907786 <===> 14151982074805896770 -9802818309312685221 <===> 11244864715202245734 - -OUTPUT: -{ - "includes": [{ - "line": 2, - "resolved_path": "&string" - }, { - "line": 3, - "resolved_path": "&vector" - }], - "skipped_by_preprocessor": [], - "types": [{ - "id": 0, - "usr": 4992269036372211530, - "detailed_name": "CompilationEntry", - "short_name": "CompilationEntry", - "kind": 23, - "declarations": [], - "spell": "6:8-6:24|-1|1|2", - "extent": "6:1-10:2|-1|1|0", - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [0, 1, 2], - "instances": [], - "uses": ["12:13-12:29|-1|1|4"] - }, { - "id": 1, - "usr": 14151982074805896770, - "detailed_name": "std::string", - "short_name": "string", - "kind": 0, - "declarations": [], - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [0, 1], - "uses": ["7:8-7:14|-1|1|4", "8:8-8:14|-1|1|4", "9:20-9:26|-1|1|4", "12:78-12:84|-1|1|4"] - }, { - "id": 2, - "usr": 5401847601697785946, - "detailed_name": "", - "short_name": "", - "kind": 0, - "declarations": [], - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [], - "uses": ["7:3-7:6|0|2|4", "8:3-8:6|0|2|4", "9:3-9:6|0|2|4", "9:15-9:18|0|2|4", "12:1-12:4|-1|1|4", "12:73-12:76|-1|1|4"] - }, { - "id": 3, - "usr": 10956461108384510180, - "detailed_name": "std::vector", - "short_name": "vector", - "kind": 0, - "declarations": [], - "bases": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [2], - "uses": ["9:8-9:14|-1|1|4", "12:6-12:12|-1|1|4"] - }], - "funcs": [{ - "id": 0, - "usr": 11244864715202245734, - "detailed_name": "std::vector LoadCompilationEntriesFromDirectory(const std::string &project_directory)", - "short_name": "LoadCompilationEntriesFromDirectory", - "kind": 12, - "storage": 1, - "declarations": [{ - "spell": "12:31-12:66|-1|1|1", - "param_spellings": ["12:86-12:103"] - }], - "bases": [], - "derived": [], - "vars": [], - "uses": [], - "callees": [] - }], - "vars": [{ - "id": 0, - "usr": 1153224798516629792, - "detailed_name": "std::string CompilationEntry::directory", - "short_name": "directory", - "declarations": [], - "spell": "7:15-7:24|0|2|2", - "extent": "7:3-7:24|0|2|0", - "type": 1, - "uses": [], - "kind": 8, - "storage": 0 - }, { - "id": 1, - "usr": 2255668374222866345, - "detailed_name": "std::string CompilationEntry::filename", - "short_name": "filename", - "declarations": [], - "spell": "8:15-8:23|0|2|2", - "extent": "8:3-8:23|0|2|0", - "type": 1, - "uses": [], - "kind": 8, - "storage": 0 - }, { - "id": 2, - "usr": 12616880765274259414, - "detailed_name": "std::vector CompilationEntry::args", - "short_name": "args", - "declarations": [], - "spell": "9:28-9:32|0|2|2", - "extent": "9:3-9:32|0|2|0", - "type": 3, - "uses": [], - "kind": 8, - "storage": 0 - }] -} -*/ diff --git a/src/cache_manager.cc b/src/cache_manager.cc index 4ae4e55b..2c23f26c 100644 --- a/src/cache_manager.cc +++ b/src/cache_manager.cc @@ -47,10 +47,10 @@ struct RealCacheManager : ICacheManager { std::string cache_file; size_t len = config_->projectRoot.size(); if (StartsWith(source_file, config_->projectRoot)) { - cache_file = EscapeFileName(config_->projectRoot) + '/' + + cache_file = EscapeFileName(config_->projectRoot) + EscapeFileName(source_file.substr(len)); } else { - cache_file = '@' + EscapeFileName(config_->projectRoot) + '/' + + cache_file = '@' + EscapeFileName(config_->projectRoot) + EscapeFileName(source_file); } diff --git a/src/import_pipeline.cc b/src/import_pipeline.cc index 9c087ef4..bff9f65b 100644 --- a/src/import_pipeline.cc +++ b/src/import_pipeline.cc @@ -673,7 +673,7 @@ void QueryDb_DoIdMap(QueueManager* queue, // it, load the previous state from disk and rerun IdMap logic later. Do not // do this if we have already attempted in the past. if (!request->load_previous && !request->previous && - db->usr_to_file.find(NormalizedPath(request->current->path)) != + db->usr_to_file.find(LowerPathIfInsensitive(request->current->path)) != db->usr_to_file.end()) { assert(!request->load_previous); request->load_previous = true; @@ -740,7 +740,7 @@ void QueryDb_OnIndexed(QueueManager* queue, // Semantic highlighting. QueryFileId file_id = - db->usr_to_file[NormalizedPath(working_file->filename)]; + db->usr_to_file[LowerPathIfInsensitive(working_file->filename)]; QueryFile* file = &db->files[file_id.id]; EmitSemanticHighlighting(db, semantic_cache, working_file, file); } diff --git a/src/message_handler.cc b/src/message_handler.cc index 0d3a2082..897d9137 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -131,7 +131,7 @@ bool FindFileOrFail(QueryDatabase* db, QueryFileId* out_file_id) { *out_query_file = nullptr; - auto it = db->usr_to_file.find(NormalizedPath(absolute_path)); + auto it = db->usr_to_file.find(LowerPathIfInsensitive(absolute_path)); if (it != db->usr_to_file.end()) { QueryFile& file = db->files[it->second.id]; if (file.def) { diff --git a/src/query.cc b/src/query.cc index 9fcb4c41..389971b3 100644 --- a/src/query.cc +++ b/src/query.cc @@ -305,7 +305,7 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, Maybe GetQueryFileIdFromPath(QueryDatabase* query_db, const std::string& path, bool create_if_missing) { - NormalizedPath normalized_path(path); + std::string normalized_path = LowerPathIfInsensitive(path); auto it = query_db->usr_to_file.find(normalized_path); if (it != query_db->usr_to_file.end()) return QueryFileId(it->second.id); @@ -730,33 +730,12 @@ std::string IndexUpdate::ToString() { return output.GetString(); } -NormalizedPath::NormalizedPath(const std::string& path) - : path(LowerPathIfCaseInsensitive(path)) {} - -bool NormalizedPath::operator==(const NormalizedPath& rhs) const { - return path == rhs.path; -} - -bool NormalizedPath::operator!=(const NormalizedPath& rhs) const { - return path != rhs.path; -} - // ------------------------ // QUERYDB THREAD FUNCTIONS // ------------------------ void QueryDatabase::RemoveUsrs(SymbolKind usr_kind, const std::vector& to_remove) { - // This function runs on the querydb thread. - - // When we remove an element, we just erase the state from the storage. We do - // not update array indices because that would take a huge amount of time for - // a very large index. - // - // There means that there is some memory growth that will never be reclaimed, - // but it should be pretty minimal and is solved by simply restarting the - // indexer and loading from cache, which is a fast operation. - switch (usr_kind) { case SymbolKind::Type: { for (const Usr& usr : to_remove) { @@ -816,7 +795,7 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) { } for (const std::string& filename : update->files_removed) - files[usr_to_file[NormalizedPath(filename)].id].def = std::nullopt; + files[usr_to_file[LowerPathIfInsensitive(filename)].id].def = std::nullopt; ImportOrUpdate(update->files_def_update); RemoveUsrs(SymbolKind::Type, update->types_removed); @@ -845,7 +824,7 @@ void QueryDatabase::ImportOrUpdate( // This function runs on the querydb thread. for (auto& def : updates) { - auto it = usr_to_file.find(NormalizedPath(def.value.path)); + auto it = usr_to_file.find(LowerPathIfInsensitive(def.value.path)); assert(it != usr_to_file.end()); QueryFile& existing = files[it->second.id]; diff --git a/src/query.h b/src/query.h index ac746aa6..9fb8fcd9 100644 --- a/src/query.h +++ b/src/query.h @@ -257,15 +257,6 @@ MAKE_REFLECT_STRUCT(IndexUpdate, vars_declarations, vars_uses); -struct NormalizedPath { - explicit NormalizedPath(const std::string& path); - bool operator==(const NormalizedPath& rhs) const; - bool operator!=(const NormalizedPath& rhs) const; - - std::string path; -}; -MAKE_HASHABLE(NormalizedPath, t.path); - // The query database is heavily optimized for fast queries. It is stored // in-memory. struct QueryDatabase { @@ -279,7 +270,7 @@ struct QueryDatabase { std::vector vars; // Lookup symbol based on a usr. - spp::sparse_hash_map usr_to_file; + spp::sparse_hash_map usr_to_file; spp::sparse_hash_map usr_to_type; spp::sparse_hash_map usr_to_func; spp::sparse_hash_map usr_to_var; diff --git a/src/serializer.cc b/src/serializer.cc index 7cd1df72..3e8bd3b9 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -449,8 +449,6 @@ TEST_SUITE("Serializer utils") { REQUIRE(GetBaseName("foo/foo.cc") == "foo.cc"); REQUIRE(GetBaseName("/foo.cc") == "foo.cc"); REQUIRE(GetBaseName("///foo.cc") == "foo.cc"); - REQUIRE(GetBaseName("bar/") == "bar/"); - REQUIRE(GetBaseName("foobar/bar/") == - "foobar/bar/"); // TODO: Should be bar, but good enough. + REQUIRE(GetBaseName("bar/") == "."); } } diff --git a/src/test.cc b/src/test.cc index 016f0382..69b9c13e 100644 --- a/src/test.cc +++ b/src/test.cc @@ -81,38 +81,6 @@ void ParseTestExpectation( */ #endif - // Scan for TEXT_REPLACE: - { - bool in_output = false; - for (std::string line : lines_with_endings) { - TrimInPlace(line); - - if (StartsWith(line, "TEXT_REPLACE:")) { - assert(!in_output && "multiple TEXT_REPLACE sections"); - in_output = true; - continue; - } - - if (in_output && line.empty()) - break; - - if (in_output) { - static const std::string kKey = " <===> "; - size_t index = line.find(kKey); - LOG_IF_S(FATAL, index == std::string::npos) - << " No '" << kKey << "' in replacement string '" << line << "'" - << ", index=" << index; - - TextReplacer::Replacement replacement; - replacement.from = line.substr(0, index); - replacement.to = line.substr(index + kKey.size()); - TrimInPlace(replacement.from); - TrimInPlace(replacement.to); - replacer->replacements.push_back(replacement); - } - } - } - // Scan for EXTRA_FLAGS: { bool in_output = false; @@ -461,58 +429,3 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) { return success; } - -// TODO: ctor/dtor, copy ctor -// TODO: Always pass IndexFile by pointer, ie, search and remove all IndexFile& -// refs. - -TEST_SUITE("ParseTestExpectation") { - TEST_CASE("Parse TEXT_REPLACE") { - // clang-format off - std::vector lines_with_endings = { - "/*\n", - "TEXT_REPLACE:\n", - " foo <===> \tbar \n", - "01 <===> 2\n", - "\n", - "*/\n"}; - // clang-format on - - TextReplacer text_replacer; - std::vector flags; - std::unordered_map all_expected_output; - ParseTestExpectation("foo.cc", lines_with_endings, &text_replacer, &flags, - &all_expected_output); - - REQUIRE(text_replacer.replacements.size() == 2); - REQUIRE(text_replacer.replacements[0].from == "foo"); - REQUIRE(text_replacer.replacements[0].to == "bar"); - REQUIRE(text_replacer.replacements[1].from == "01"); - REQUIRE(text_replacer.replacements[1].to == "2"); - } - - TEST_CASE("Apply TEXT_REPLACE") { - TextReplacer replacer; - replacer.replacements.push_back(TextReplacer::Replacement{"foo", "bar"}); - replacer.replacements.push_back(TextReplacer::Replacement{"01", "2"}); - replacer.replacements.push_back(TextReplacer::Replacement{"3", "456"}); - - // Equal-length. - REQUIRE(replacer.Apply("foo") == "bar"); - REQUIRE(replacer.Apply("bar") == "bar"); - - // Shorter replacement. - REQUIRE(replacer.Apply("01") == "2"); - REQUIRE(replacer.Apply("2") == "2"); - - // Longer replacement. - REQUIRE(replacer.Apply("3") == "456"); - REQUIRE(replacer.Apply("456") == "456"); - - // Content before-after replacement. - REQUIRE(replacer.Apply("aaaa01bbbb") == "aaaa2bbbb"); - - // Multiple replacements. - REQUIRE(replacer.Apply("foofoobar0123") == "barbarbar22456"); - } -} diff --git a/src/utils.cc b/src/utils.cc index 19af1c3f..59b1c28d 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -7,16 +7,17 @@ #include #include +#include +#include +#include #include -#include -#include -#include #include #include #include #include #include #include +using namespace std::placeholders; // DEFAULT_RESOURCE_DIRECTORY is passed with quotes for non-MSVC compilers, ie, // foo vs "foo". @@ -28,32 +29,16 @@ #endif void TrimInPlace(std::string& s) { - s.erase(s.begin(), - std::find_if(s.begin(), s.end(), - std::not1(std::ptr_fun(std::isspace)))); - s.erase(std::find_if(s.rbegin(), s.rend(), - std::not1(std::ptr_fun(std::isspace))) - .base(), - s.end()); + auto f = [](char c) { return !isspace(c); }; + s.erase(s.begin(), std::find_if(s.begin(), s.end(), f)); + s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end()); } std::string Trim(std::string s) { TrimInPlace(s); return s; } -void RemoveLastCR(std::string& s) { - if (!s.empty() && *s.rbegin() == '\r') - s.pop_back(); -} -uint64_t HashUsr(const std::string& s) { - return HashUsr(s.c_str(), s.size()); -} - -uint64_t HashUsr(const char* s) { - return HashUsr(s, strlen(s)); -} - -uint64_t HashUsr(const char* s, size_t n) { +uint64_t HashUsr(std::string_view s) { union { uint64_t ret; uint8_t out[8]; @@ -61,43 +46,31 @@ uint64_t HashUsr(const char* s, size_t n) { // k is an arbitrary key. Don't change it. const uint8_t k[16] = {0xd0, 0xe5, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x61, 0x79, 0xea, 0x70, 0xca, 0x70, 0xf0, 0x0d}; - (void)siphash(reinterpret_cast(s), n, k, out, 8); + (void)siphash(reinterpret_cast(s.data()), s.size(), k, out, 8); return ret; } -// See http://stackoverflow.com/a/2072890 -bool EndsWith(std::string_view value, std::string_view ending) { - if (ending.size() > value.size()) - return false; - return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +bool EndsWith(std::string_view s, std::string_view suffix) { + return s.size() >= suffix.size() && + std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); } -bool StartsWith(std::string_view value, std::string_view start) { - if (start.size() > value.size()) - return false; - return std::equal(start.begin(), start.end(), value.begin()); +bool StartsWith(std::string_view s, std::string_view prefix) { + return s.size() >= prefix.size() && + std::equal(prefix.begin(), prefix.end(), s.begin()); } -bool AnyStartsWith(const std::vector& values, - const std::string& start) { - return std::any_of( - std::begin(values), std::end(values), - [&start](const std::string& value) { return StartsWith(value, start); }); +bool AnyStartsWith(const std::vector& xs, + std::string_view prefix) { + return std::any_of(xs.begin(), xs.end(), std::bind(StartsWith, _1, prefix)); } -bool StartsWithAny(const std::string& value, - const std::vector& startings) { - return std::any_of(std::begin(startings), std::end(startings), - [&value](const std::string& starting) { - return StartsWith(value, starting); - }); +bool StartsWithAny(std::string_view s, const std::vector& ps) { + return std::any_of(ps.begin(), ps.end(), std::bind(StartsWith, s, _1)); } -bool EndsWithAny(const std::string& value, - const std::vector& endings) { - return std::any_of( - std::begin(endings), std::end(endings), - [&value](const std::string& ending) { return EndsWith(value, ending); }); +bool EndsWithAny(std::string_view s, const std::vector& ss) { + return std::any_of(ss.begin(), ss.end(), std::bind(EndsWith, s, _1)); } bool FindAnyPartial(const std::string& value, @@ -120,10 +93,7 @@ std::string GetDirName(std::string path) { } std::string GetBaseName(const std::string& path) { - size_t last_slash = path.find_last_of('/'); - if (last_slash != std::string::npos && (last_slash + 1) < path.size()) - return path.substr(last_slash + 1); - return path; + return fs::path(path).filename(); } std::string StripFileType(const std::string& path) { @@ -149,13 +119,15 @@ std::vector SplitString(const std::string& str, return strings; } -std::string LowerPathIfCaseInsensitive(const std::string& path) { - std::string result = path; +std::string LowerPathIfInsensitive(const std::string& path) { #if defined(_WIN32) - for (size_t i = 0; i < result.size(); ++i) - result[i] = (char)tolower(result[i]); + std::string ret = path; + for (char& c : ret) + c = tolower(c); + return ret; +#else + return path; #endif - return result; } static void GetFilesInFolderHelper( @@ -164,7 +136,7 @@ static void GetFilesInFolderHelper( std::string output_prefix, const std::function& handler) { std::queue> q; - q.push(std::make_pair(fs::path(folder), fs::path(output_prefix))); + q.emplace(fs::path(folder), fs::path(output_prefix)); while (!q.empty()) { for (auto it = fs::directory_iterator(q.front().first); it != fs::directory_iterator(); ++it) { auto path = it->path(); @@ -212,58 +184,29 @@ void EnsureEndsInSlash(std::string& path) { } std::string EscapeFileName(std::string path) { - if (path.size() && path.back() == '/') - path.pop_back(); - std::replace(path.begin(), path.end(), '\\', '@'); - std::replace(path.begin(), path.end(), '/', '@'); - std::replace(path.begin(), path.end(), ':', '@'); + bool slash = path.size() && path.back() == '/'; + for (char& c : path) + if (c == '\\' || c == '/' || c == ':') + c = '@'; + if (slash) + path += '/'; return path; } -// http://stackoverflow.com/a/6089413 -std::istream& SafeGetline(std::istream& is, std::string& t) { - t.clear(); - - // The characters in the stream are read one-by-one using a std::streambuf. - // That is faster than reading them one-by-one using the std::istream. Code - // that uses streambuf this way must be guarded by a sentry object. The sentry - // object performs various tasks, such as thread synchronization and updating - // the stream state. - - std::istream::sentry se(is, true); - std::streambuf* sb = is.rdbuf(); - - for (;;) { - int c = sb->sbumpc(); - if (c == EOF) { - // Also handle the case when the last line has no line ending - if (t.empty()) - is.setstate(std::ios::eofbit); - return is; - } - - t += (char)c; - - if (c == '\n') - return is; - } -} - bool FileExists(const std::string& filename) { return fs::exists(filename); } std::optional ReadContent(const std::string& filename) { LOG_S(INFO) << "Reading " << filename; - std::ifstream cache; - cache.open(filename); - - try { - return std::string(std::istreambuf_iterator(cache), - std::istreambuf_iterator()); - } catch (std::ios_base::failure&) { - return std::nullopt; - } + char buf[4096]; + std::string ret; + FILE* f = fopen(filename.c_str(), "rb"); + if (!f) return {}; + size_t n; + while ((n = fread(buf, 1, sizeof buf, f)) > 0) + ret.append(buf, n); + return ret; } std::vector ReadFileLines(std::string filename) { @@ -302,14 +245,12 @@ std::string TextReplacer::Apply(const std::string& content) { } void WriteToFile(const std::string& filename, const std::string& content) { - std::ofstream file(filename, - std::ios::out | std::ios::trunc | std::ios::binary); - if (!file.good()) { + FILE* f = fopen(filename.c_str(), "wb"); + if (!f || fwrite(content.c_str(), content.size(), 1, f) != 1) { LOG_S(ERROR) << "Cannot write to " << filename; return; } - - file << content; + fclose(f); } std::string GetDefaultResourceDirectory() { diff --git a/src/utils.h b/src/utils.h index 4eb42ca6..16685885 100644 --- a/src/utils.h +++ b/src/utils.h @@ -13,19 +13,14 @@ void TrimInPlace(std::string& s); std::string Trim(std::string s); -uint64_t HashUsr(const std::string& s); -uint64_t HashUsr(const char* s); -uint64_t HashUsr(const char* s, size_t n); +uint64_t HashUsr(std::string_view s); // Returns true if |value| starts/ends with |start| or |ending|. bool StartsWith(std::string_view value, std::string_view start); bool EndsWith(std::string_view value, std::string_view ending); -bool AnyStartsWith(const std::vector& values, - const std::string& start); -bool StartsWithAny(const std::string& value, - const std::vector& startings); -bool EndsWithAny(const std::string& value, - const std::vector& endings); +bool AnyStartsWith(const std::vector& xs, std::string_view prefix); +bool StartsWithAny(std::string_view s, const std::vector& ps); +bool EndsWithAny(std::string_view s, const std::vector& ss); bool FindAnyPartial(const std::string& value, const std::vector& values); // Returns the dirname of |path|, i.e. "foo/bar.cc" => "foo", "foo" => ".", @@ -39,7 +34,7 @@ std::string StripFileType(const std::string& path); std::vector SplitString(const std::string& str, const std::string& delimiter); -std::string LowerPathIfCaseInsensitive(const std::string& path); +std::string LowerPathIfInsensitive(const std::string& path); template std::string StringJoinMap(const TValues& values,