Merge {timestamp_manager,iindexer}.{cc,h}; remove standard_includes.*; use last_write_time

This commit is contained in:
Fangrui Song 2018-04-22 10:01:44 -07:00
parent b4cca890c6
commit d821ac34d8
27 changed files with 171 additions and 491 deletions

View File

@ -96,11 +96,12 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(ccls PRIVATE Threads::Threads)
if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin)
target_link_libraries(ccls PRIVATE -lc++experimental)
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
target_link_libraries(ccls PRIVATE -lstdc++fs)
elseif(MSVC)
else()
target_link_libraries(ccls PRIVATE -lstdc++fs)
# e.g. Darwin, FreeBSD
target_link_libraries(ccls PRIVATE -lc++experimental)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL Linux)
@ -212,7 +213,6 @@ target_sources(ccls PRIVATE
src/file_consumer.cc
src/filesystem.cc
src/fuzzy_match.cc
src/iindexer.cc
src/import_pipeline.cc
src/include_complete.cc
src/method.cc
@ -229,11 +229,9 @@ target_sources(ccls PRIVATE
src/query.cc
src/queue_manager.cc
src/serializer.cc
src/standard_includes.cc
src/test.cc
src/third_party_impl.cc
src/timer.cc
src/timestamp_manager.cc
src/type_printer.cc
src/utils.cc
src/working_files.cc)

View File

@ -143,10 +143,3 @@ std::unique_ptr<IndexFile> ICacheManager::TakeOrLoad(const std::string& path) {
assert(result);
return result;
}
void ICacheManager::IterateLoadedCaches(std::function<void(IndexFile*)> fn) {
for (const auto& cache : caches_) {
assert(cache.second);
fn(cache.second.get());
}
}

View File

@ -2,7 +2,6 @@
#include <optional>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
@ -41,8 +40,11 @@ struct ICacheManager {
virtual std::optional<std::string> LoadCachedFileContents(
const std::string& path) = 0;
// Iterate over all loaded caches.
void IterateLoadedCaches(std::function<void(IndexFile*)> fn);
template <typename Fn>
void IterateLoadedCaches(Fn fn) {
for (const auto& cache : caches_)
fn(cache.second.get());
}
protected:
virtual std::unique_ptr<IndexFile> RawCacheLoad(const std::string& path) = 0;

View File

@ -371,7 +371,7 @@ IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
param->seen_files.push_back(file_name);
// Set modification time.
std::optional<int64_t> modification_time = GetLastModificationTime(file_name);
std::optional<int64_t> modification_time = LastWriteTime(file_name);
LOG_IF_S(ERROR, !modification_time)
<< "Failed fetching modification time for " << file_name;
if (modification_time)
@ -2358,3 +2358,60 @@ void Reflect(Writer& visitor, Reference& value) {
Reflect(visitor, value.role);
}
}
namespace {
struct TestIndexer : IIndexer {
static std::unique_ptr<TestIndexer> FromEntries(
const std::vector<TestEntry>& entries) {
auto result = std::make_unique<TestIndexer>();
for (const TestEntry& entry : entries) {
std::vector<std::unique_ptr<IndexFile>> indexes;
if (entry.num_indexes > 0)
indexes.push_back(std::make_unique<IndexFile>(entry.path, "<empty>"));
for (int i = 1; i < entry.num_indexes; ++i) {
indexes.push_back(std::make_unique<IndexFile>(
entry.path + "_extra_" + std::to_string(i) + ".h", "<empty>"));
}
result->indexes.insert(std::make_pair(entry.path, std::move(indexes)));
}
return result;
}
~TestIndexer() override = default;
std::vector<std::unique_ptr<IndexFile>> Index(
FileConsumerSharedState* file_consumer_shared,
std::string file,
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) override {
auto it = indexes.find(file);
if (it == indexes.end()) {
// Don't return any indexes for unexpected data.
assert(false && "no indexes");
return {};
}
// FIXME: allow user to control how many times we return the index for a
// specific file (atm it is always 1)
auto result = std::move(it->second);
indexes.erase(it);
return result;
}
std::unordered_map<std::string, std::vector<std::unique_ptr<IndexFile>>>
indexes;
};
} // namespace
// static
std::unique_ptr<IIndexer> IIndexer::MakeTestIndexer(
std::initializer_list<TestEntry> entries) {
return TestIndexer::FromEntries(entries);
}

View File

@ -138,6 +138,8 @@ const char* ClangBuiltinTypeName(CXTypeKind kind) {
case CXType_Bool: return "bool";
case CXType_Char_U: return "char";
case CXType_UChar: return "unsigned char";
case CXType_Char16: return "char16_t";
case CXType_Char32: return "char32_t";
case CXType_UShort: return "unsigned short";
case CXType_UInt: return "unsigned int";
case CXType_ULong: return "unsigned long";
@ -146,6 +148,7 @@ const char* ClangBuiltinTypeName(CXTypeKind kind) {
case CXType_Char_S: return "char";
case CXType_SChar: return "signed char";
case CXType_WChar: return "wchar_t";
case CXType_Short: return "short";
case CXType_Int: return "int";
case CXType_Long: return "long";
case CXType_LongLong: return "long long";

View File

@ -21,7 +21,6 @@
#include "serializers/json.h"
#include "test.h"
#include "timer.h"
#include "timestamp_manager.h"
#include "working_files.h"
#include <doctest/doctest.h>

View File

@ -29,8 +29,6 @@ bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
a.data[2] == b.data[2];
}
FileContents::FileContents() : line_offsets_{0} {}
FileContents::FileContents(const std::string& path, const std::string& content)
: path(path), content(content) {
line_offsets_.push_back(0);

View File

@ -18,7 +18,7 @@ MAKE_HASHABLE(CXFileUniqueID, t.data[0], t.data[1], t.data[2]);
bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b);
struct FileContents {
FileContents();
FileContents() = default;
FileContents(const std::string& path, const std::string& content);
std::optional<int> ToOffset(Position p) const;

View File

@ -1,83 +0,0 @@
#include "iindexer.h"
#include "indexer.h"
namespace {
struct ClangIndexer : IIndexer {
~ClangIndexer() override = default;
std::vector<std::unique_ptr<IndexFile>> Index(
FileConsumerSharedState* file_consumer_shared,
std::string file,
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) override {
return Parse(file_consumer_shared, file, args, file_contents, perf, &index);
}
// Note: constructing this acquires a global lock
ClangIndex index;
};
struct TestIndexer : IIndexer {
static std::unique_ptr<TestIndexer> FromEntries(
const std::vector<TestEntry>& entries) {
auto result = std::make_unique<TestIndexer>();
for (const TestEntry& entry : entries) {
std::vector<std::unique_ptr<IndexFile>> indexes;
if (entry.num_indexes > 0)
indexes.push_back(std::make_unique<IndexFile>(entry.path, "<empty>"));
for (int i = 1; i < entry.num_indexes; ++i) {
indexes.push_back(std::make_unique<IndexFile>(
entry.path + "_extra_" + std::to_string(i) + ".h", "<empty>"));
}
result->indexes.insert(std::make_pair(entry.path, std::move(indexes)));
}
return result;
}
~TestIndexer() override = default;
std::vector<std::unique_ptr<IndexFile>> Index(
FileConsumerSharedState* file_consumer_shared,
std::string file,
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) override {
auto it = indexes.find(file);
if (it == indexes.end()) {
// Don't return any indexes for unexpected data.
assert(false && "no indexes");
return {};
}
// FIXME: allow user to control how many times we return the index for a
// specific file (atm it is always 1)
auto result = std::move(it->second);
indexes.erase(it);
return result;
}
std::unordered_map<std::string, std::vector<std::unique_ptr<IndexFile>>>
indexes;
};
} // namespace
IIndexer::TestEntry::TestEntry(const std::string& path, int num_indexes)
: path(path), num_indexes(num_indexes) {}
// static
std::unique_ptr<IIndexer> IIndexer::MakeClangIndexer() {
return std::make_unique<ClangIndexer>();
}
// static
std::unique_ptr<IIndexer> IIndexer::MakeTestIndexer(
std::initializer_list<TestEntry> entries) {
return TestIndexer::FromEntries(entries);
}

View File

@ -1,42 +0,0 @@
#pragma once
#include <optional>
#include <initializer_list>
#include <memory>
#include <string>
#include <vector>
// TODO:
// - rename indexer.h to clang_indexer.h and pull out non-clang specific code
// like IndexFile
// - rename this file to indexer.h
struct IndexFile;
struct FileContents;
struct FileConsumerSharedState;
struct PerformanceImportFile;
// Abstracts away the actual indexing process. Each IIndexer instance is
// per-thread and constructing an instance may be extremely expensive (ie,
// acquire a lock) and should be done as rarely as possible.
struct IIndexer {
struct TestEntry {
std::string path;
int num_indexes = 0;
TestEntry(const std::string& path, int num_indexes);
};
static std::unique_ptr<IIndexer> MakeClangIndexer();
static std::unique_ptr<IIndexer> MakeTestIndexer(
std::initializer_list<TestEntry> entries);
virtual ~IIndexer() = default;
virtual std::vector<std::unique_ptr<IndexFile>> Index(
FileConsumerSharedState* file_consumer_shared,
std::string file,
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) = 0;
};

View File

@ -3,7 +3,6 @@
#include "cache_manager.h"
#include "config.h"
#include "diagnostics_engine.h"
#include "iindexer.h"
#include "import_manager.h"
#include "lsp.h"
#include "message_handler.h"
@ -12,15 +11,11 @@
#include "query_utils.h"
#include "queue_manager.h"
#include "timer.h"
#include "timestamp_manager.h"
#include <doctest/doctest.h>
#include <loguru.hpp>
#include <atomic>
#include <chrono>
#include <string>
#include <vector>
namespace {
@ -63,14 +58,14 @@ struct IterationLoop {
struct IModificationTimestampFetcher {
virtual ~IModificationTimestampFetcher() = default;
virtual std::optional<int64_t> GetModificationTime(const std::string& path) = 0;
virtual std::optional<int64_t> LastWriteTime(const std::string& path) = 0;
};
struct RealModificationTimestampFetcher : IModificationTimestampFetcher {
~RealModificationTimestampFetcher() override = default;
// IModificationTimestamp:
std::optional<int64_t> GetModificationTime(const std::string& path) override {
return GetLastModificationTime(path);
std::optional<int64_t> LastWriteTime(const std::string& path) override {
return ::LastWriteTime(path);
}
};
struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
@ -79,7 +74,7 @@ struct FakeModificationTimestampFetcher : IModificationTimestampFetcher {
~FakeModificationTimestampFetcher() override = default;
// IModificationTimestamp:
std::optional<int64_t> GetModificationTime(const std::string& path) override {
std::optional<int64_t> LastWriteTime(const std::string& path) override {
auto it = entries.find(path);
assert(it != entries.end());
return it->second;
@ -174,7 +169,7 @@ ShouldParse FileNeedsParse(
}
std::optional<int64_t> modification_timestamp =
modification_timestamp_fetcher->GetModificationTime(path);
modification_timestamp_fetcher->LastWriteTime(path);
// Cannot find file.
if (!modification_timestamp)
@ -327,7 +322,7 @@ std::vector<FileContents> PreloadFileContents(
// still valid. if so, we can use it, otherwise we need to load from disk.
auto get_latest_content = [](const std::string& path, int64_t cached_time,
const std::string& cached) -> std::string {
std::optional<int64_t> mod_time = GetLastModificationTime(path);
std::optional<int64_t> mod_time = LastWriteTime(path);
if (!mod_time)
return "";
@ -533,6 +528,29 @@ bool IndexMergeIndexUpdates() {
} // namespace
std::optional<int64_t> TimestampManager::GetLastCachedModificationTime(
ICacheManager* cache_manager,
const std::string& path) {
{
std::lock_guard<std::mutex> guard(mutex_);
auto it = timestamps_.find(path);
if (it != timestamps_.end())
return it->second;
}
IndexFile* file = cache_manager->TryLoad(path);
if (!file)
return std::nullopt;
UpdateCachedModificationTime(path, file->last_modification_time);
return file->last_modification_time;
}
void TimestampManager::UpdateCachedModificationTime(const std::string& path,
int64_t timestamp) {
std::lock_guard<std::mutex> guard(mutex_);
timestamps_[path] = timestamp;
}
ImportPipelineStatus::ImportPipelineStatus()
: num_active_threads(0), next_progress_output(0) {}
@ -586,7 +604,7 @@ void Indexer_Main(DiagnosticsEngine* diag_engine,
RealModificationTimestampFetcher modification_timestamp_fetcher;
auto* queue = QueueManager::instance();
// Build one index per-indexer, as building the index acquires a global lock.
auto indexer = IIndexer::MakeClangIndexer();
auto indexer = std::make_unique<ClangIndexer>();
while (true) {
bool did_work = false;

View File

@ -5,20 +5,37 @@
#include <atomic>
#include <memory>
#include <optional>
#include <string>
#include <mutex>
#include <unordered_map>
#include <vector>
struct ClangTranslationUnit;
class DiagnosticsEngine;
struct FileConsumerSharedState;
struct ICacheManager;
struct ImportManager;
struct MultiQueueWaiter;
struct Project;
struct QueryDatabase;
struct SemanticHighlightSymbolCache;
struct TimestampManager;
struct WorkingFiles;
// Caches timestamps of cc files so we can avoid a filesystem reads. This is
// important for import perf, as during dependency checking the same files are
// checked over and over again if they are common headers.
struct TimestampManager {
std::optional<int64_t> GetLastCachedModificationTime(ICacheManager* cache_manager,
const std::string& path);
void UpdateCachedModificationTime(const std::string& path, int64_t timestamp);
// TODO: use std::shared_mutex so we can have multiple readers.
std::mutex mutex_;
std::unordered_map<std::string, int64_t> timestamps_;
};
struct ImportPipelineStatus {
std::atomic<int> num_active_threads;
std::atomic<long long> next_progress_output;

View File

@ -4,7 +4,6 @@
#include "match.h"
#include "platform.h"
#include "project.h"
#include "standard_includes.h"
#include "timer.h"
#include <thread>
@ -107,7 +106,6 @@ void IncludeComplete::Rescan() {
SetThreadName("scan_includes");
Timer timer;
InsertStlIncludes();
InsertIncludesFromDirectory(g_config->projectRoot,
false /*use_angle_brackets*/);
for (const std::string& dir : project_->quote_include_directories)
@ -189,14 +187,6 @@ void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
std::move(result.completion_item));
}
void IncludeComplete::InsertStlIncludes() {
std::lock_guard<std::mutex> lock(completion_items_mutex);
for (const char* stl_header : kStandardLibraryIncludes) {
completion_items.push_back(BuildCompletionItem(
stl_header, true /*use_angle_brackets*/, true /*is_stl*/));
}
}
std::optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(
const std::string& absolute_path) {
std::lock_guard<std::mutex> lock(completion_items_mutex);

View File

@ -22,7 +22,6 @@ struct IncludeComplete {
// blocking function and should be run off the querydb thread.
void InsertIncludesFromDirectory(std::string directory,
bool use_angle_brackets);
void InsertStlIncludes();
std::optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
const std::string& absolute_path);

View File

@ -488,3 +488,40 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
bool ConcatTypeAndName(std::string& type, const std::string& name);
void IndexInit();
// Abstracts away the actual indexing process. Each IIndexer instance is
// per-thread and constructing an instance may be extremely expensive (ie,
// acquire a lock) and should be done as rarely as possible.
struct IIndexer {
struct TestEntry {
std::string path;
int num_indexes = 0;
};
static std::unique_ptr<IIndexer> MakeTestIndexer(
std::initializer_list<TestEntry> entries);
virtual ~IIndexer() = default;
virtual std::vector<std::unique_ptr<IndexFile>> Index(
FileConsumerSharedState* file_consumer_shared,
std::string file,
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) = 0;
};
struct ClangIndexer : IIndexer {
~ClangIndexer() override = default;
std::vector<std::unique_ptr<IndexFile>> Index(
FileConsumerSharedState* file_consumer_shared,
std::string file,
const std::vector<std::string>& args,
const std::vector<FileContents>& file_contents,
PerformanceImportFile* perf) override {
return Parse(file_consumer_shared, file, args, file_contents, perf, &index);
}
// Note: constructing this acquires a global lock
ClangIndex index;
};

View File

@ -18,29 +18,4 @@ struct lsCodeLensCommandArguments {
lsPosition position;
std::vector<lsLocation> locations;
};
// FIXME Don't use array in vscode-ccls
inline void Reflect(Writer& visitor, lsCodeLensCommandArguments& value) {
visitor.StartArray(3);
Reflect(visitor, value.uri);
Reflect(visitor, value.position);
Reflect(visitor, value.locations);
visitor.EndArray();
}
inline void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) {
int i = 0;
visitor.IterArray([&](Reader& visitor) {
switch (i++) {
case 0:
Reflect(visitor, value.uri);
break;
case 1:
Reflect(visitor, value.position);
break;
case 2:
Reflect(visitor, value.locations);
break;
}
});
}
MAKE_REFLECT_STRUCT(lsCodeLensCommandArguments, uri, position, locations)

View File

@ -1,11 +1,11 @@
#include "cache_manager.h"
#include "import_pipeline.h"
#include "match.h"
#include "message_handler.h"
#include "platform.h"
#include "project.h"
#include "queue_manager.h"
#include "timer.h"
#include "timestamp_manager.h"
#include "working_files.h"
#include <loguru.hpp>
@ -66,7 +66,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
need_index.insert(file->def->path);
std::optional<int64_t> modification_timestamp =
GetLastModificationTime(file->def->path);
LastWriteTime(file->def->path);
if (!modification_timestamp)
continue;
std::optional<int64_t> cached_modification =

View File

@ -166,28 +166,6 @@ void SetThreadName(const std::string& thread_name) {
#endif
}
std::optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
struct stat buf;
if (stat(absolute_path.c_str(), &buf) != 0) {
switch (errno) {
case ENOENT:
// std::cerr << "GetLastModificationTime: unable to find file " <<
// absolute_path << std::endl;
return std::nullopt;
case EINVAL:
// std::cerr << "GetLastModificationTime: invalid param to _stat for
// file file " << absolute_path << std::endl;
return std::nullopt;
default:
// std::cerr << "GetLastModificationTime: unhandled for " <<
// absolute_path << std::endl; exit(1);
return std::nullopt;
}
}
return buf.st_mtime;
}
void FreeUnusedMemory() {
#if defined(__GLIBC__)
malloc_trim(0);

View File

@ -79,28 +79,6 @@ void SetThreadName(const std::string& thread_name) {
}
}
std::optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
struct _stat buf;
if (_stat(absolute_path.c_str(), &buf) != 0) {
switch (errno) {
case ENOENT:
// std::cerr << "GetLastModificationTime: unable to find file " <<
// absolute_path << std::endl;
return std::nullopt;
case EINVAL:
// std::cerr << "GetLastModificationTime: invalid param to _stat for
// file file " << absolute_path << std::endl;
return std::nullopt;
default:
// std::cerr << "GetLastModificationTime: unhandled for " <<
// absolute_path << std::endl; exit(1);
return std::nullopt;
}
}
return buf.st_mtime;
}
void FreeUnusedMemory() {}
// TODO Wait for debugger to attach

View File

@ -6,7 +6,6 @@
#include <sparsepp/spp.h>
#include <forward_list>
#include <functional>
struct QueryFile;
struct QueryType;

View File

@ -1,182 +0,0 @@
#include "standard_includes.h"
// See http://stackoverflow.com/a/2029106.
const char* kStandardLibraryIncludes[177] = {
"aio.h",
"algorithm",
"any",
"arpa/inet.h",
"array",
"assert.h",
"atomic",
"bitset",
"cassert",
"ccomplex",
"cctype",
"cerrno",
"cfenv",
"cfloat",
"chrono",
"cinttypes",
"ciso646",
"climits",
"clocale",
"cmath",
"codecvt",
"complex",
"complex.h",
"condition_variable",
"cpio.h",
"csetjmp",
"csignal",
"cstdalign",
"cstdarg",
"cstdbool",
"cstddef",
"cstdint",
"cstdio",
"cstdlib",
"cstring",
"ctgmath",
"ctime",
"ctype.h",
"cuchar",
"curses.h",
"cwchar",
"cwctype",
"deque",
"dirent.h",
"dlfcn.h",
"errno.h",
"exception",
"execution",
"fcntl.h",
"fenv.h",
"filesystem",
"float.h",
"fmtmsg.h",
"fnmatch.h",
"forward_list",
"fstream",
"ftw.h",
"functional",
"future",
"glob.h",
"grp.h",
"iconv.h",
"initializer_list",
"inttypes.h",
"iomanip",
"ios",
"iosfwd",
"iostream",
"iso646.h",
"istream",
"iterator",
"langinfo.h",
"libgen.h",
"limits",
"limits.h",
"list",
"locale",
"locale.h",
"map",
"math.h",
"memory",
"memory_resource",
"monetary.h",
"mqueue.h",
"mutex",
"ndbm.h",
"net/if.h",
"netdb.h",
"netinet/in.h",
"netinet/tcp.h",
"new",
"nl_types.h",
"numeric",
"std::optional",
"ostream",
"poll.h",
"pthread.h",
"pwd.h",
"queue",
"random",
"ratio",
"regex",
"regex.h",
"sched.h",
"scoped_allocator",
"search.h",
"semaphore.h",
"set",
"setjmp.h",
"shared_mutex",
"signal.h",
"spawn.h",
"sstream",
"stack",
"stdalign.h",
"stdarg.h",
"stdatomic.h",
"stdbool.h",
"stddef.h",
"stdexcept",
"stdint.h",
"stdio.h",
"stdlib.h",
"stdnoreturn.h",
"streambuf",
"string",
"string.h",
"string_view",
"strings.h",
"stropts.h",
"strstream",
"sys/ipc.h",
"sys/mman.h",
"sys/msg.h",
"sys/resource.h",
"sys/select.h",
"sys/sem.h",
"sys/shm.h",
"sys/socket.h",
"sys/stat.h",
"sys/statvfs.h",
"sys/time.h",
"sys/times.h",
"sys/types.h",
"sys/uio.h",
"sys/un.h",
"sys/utsname.h",
"sys/wait.h",
"syslog.h",
"system_error",
"tar.h",
"term.h",
"termios.h",
"tgmath.h",
"thread",
"threads.h",
"time.h",
"trace.h",
"tuple",
"type_traits",
"typeindex",
"typeinfo",
"uchar.h",
"ulimit.h",
"uncntrl.h",
"unistd.h",
"unordered_map",
"unordered_set",
"utility",
"utime.h",
"utmpx.h",
"valarray",
"variant",
"vector",
"wchar.h",
"wctype.h",
"wordexp.h",
};

View File

@ -1,4 +0,0 @@
#pragma once
// A set of standard libary header names, ie, "vector".
extern const char* kStandardLibraryIncludes[177];

View File

@ -7,7 +7,6 @@
// front of others.
enum class SymbolKind : uint8_t { Invalid, File, Type, Func, Var };
MAKE_REFLECT_TYPE_PROXY(SymbolKind);
MAKE_ENUM_HASHABLE(SymbolKind);
// clang/Basic/Specifiers.h clang::StorageClass
enum class StorageClass : uint8_t {
@ -44,7 +43,6 @@ enum class Role : uint16_t {
All = (1 << 9) - 1,
};
MAKE_REFLECT_TYPE_PROXY(Role);
MAKE_ENUM_HASHABLE(Role);
inline uint16_t operator&(Role lhs, Role rhs) {
return uint16_t(lhs) & uint16_t(rhs);

View File

@ -1,27 +0,0 @@
#include "timestamp_manager.h"
#include "cache_manager.h"
#include "indexer.h"
std::optional<int64_t> TimestampManager::GetLastCachedModificationTime(
ICacheManager* cache_manager,
const std::string& path) {
{
std::lock_guard<std::mutex> guard(mutex_);
auto it = timestamps_.find(path);
if (it != timestamps_.end())
return it->second;
}
IndexFile* file = cache_manager->TryLoad(path);
if (!file)
return std::nullopt;
UpdateCachedModificationTime(path, file->last_modification_time);
return file->last_modification_time;
}
void TimestampManager::UpdateCachedModificationTime(const std::string& path,
int64_t timestamp) {
std::lock_guard<std::mutex> guard(mutex_);
timestamps_[path] = timestamp;
}

View File

@ -1,22 +0,0 @@
#pragma once
#include <optional>
#include <mutex>
#include <unordered_map>
struct ICacheManager;
// Caches timestamps of cc files so we can avoid a filesystem reads. This is
// important for import perf, as during dependency checking the same files are
// checked over and over again if they are common headers.
struct TimestampManager {
std::optional<int64_t> GetLastCachedModificationTime(ICacheManager* cache_manager,
const std::string& path);
void UpdateCachedModificationTime(const std::string& path, int64_t timestamp);
// TODO: use std::shared_mutex so we can have multiple readers.
std::mutex mutex_;
std::unordered_map<std::string, int64_t> timestamps_;
};

View File

@ -1,5 +1,6 @@
#include "utils.h"
#include "filesystem.hh"
#include "platform.h"
#include <doctest/doctest.h>
@ -130,6 +131,7 @@ std::optional<std::string> ReadContent(const std::string& filename) {
size_t n;
while ((n = fread(buf, 1, sizeof buf, f)) > 0)
ret.append(buf, n);
fclose(f);
return ret;
}
@ -142,6 +144,15 @@ void WriteToFile(const std::string& filename, const std::string& content) {
fclose(f);
}
std::optional<int64_t> LastWriteTime(const std::string& filename) {
std::error_code ec;
auto ftime = fs::last_write_time(filename, ec);
if (ec) return std::nullopt;
return std::chrono::time_point_cast<std::chrono::nanoseconds>(ftime)
.time_since_epoch()
.count();
}
std::string GetDefaultResourceDirectory() {
std::string result;

View File

@ -62,8 +62,8 @@ void EnsureEndsInSlash(std::string& path);
std::string EscapeFileName(std::string path);
std::optional<std::string> ReadContent(const std::string& filename);
void WriteToFile(const std::string& filename, const std::string& content);
std::optional<int64_t> LastWriteTime(const std::string& filename);
// http://stackoverflow.com/a/38140932
//
@ -95,14 +95,4 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
}; \
}
#define MAKE_ENUM_HASHABLE(type) \
namespace std { \
template <> \
struct hash<type> { \
std::size_t operator()(const type& t) const { \
return hash<int>()(static_cast<int>(t)); \
} \
}; \
}
std::string GetDefaultResourceDirectory();