Make EmptyParam empty & rewrite LruCache

This commit is contained in:
Fangrui Song 2018-11-26 21:00:30 -08:00
parent 6379beb9ba
commit a3e635fb09
6 changed files with 44 additions and 148 deletions

View File

@ -607,14 +607,14 @@ void CompletionManager::NotifySave(const std::string &filename) {
void CompletionManager::OnClose(const std::string &filename) { void CompletionManager::OnClose(const std::string &filename) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
preloads.TryTake(filename); preloads.Take(filename);
sessions.TryTake(filename); sessions.Take(filename);
} }
bool CompletionManager::EnsureCompletionOrCreatePreloadSession( bool CompletionManager::EnsureCompletionOrCreatePreloadSession(
const std::string &path) { const std::string &path) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
if (preloads.TryGet(path) || sessions.TryGet(path)) if (preloads.Get(path) || sessions.Get(path))
return false; return false;
// No CompletionSession, create new one. // No CompletionSession, create new one.
@ -633,11 +633,11 @@ std::shared_ptr<ccls::CompletionSession>
CompletionManager::TryGetSession(const std::string &path, bool preload, CompletionManager::TryGetSession(const std::string &path, bool preload,
bool *is_open) { bool *is_open) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
std::shared_ptr<ccls::CompletionSession> session = preloads.TryGet(path); std::shared_ptr<ccls::CompletionSession> session = preloads.Get(path);
if (session) { if (session) {
if (!preload) { if (!preload) {
preloads.TryTake(path); preloads.Take(path);
sessions.Insert(path, session); sessions.Insert(path, session);
if (is_open) if (is_open)
*is_open = true; *is_open = true;
@ -645,7 +645,7 @@ CompletionManager::TryGetSession(const std::string &path, bool preload,
return session; return session;
} }
session = sessions.TryGet(path); session = sessions.Get(path);
if (!session && !preload) { if (!session && !preload) {
session = std::make_shared<ccls::CompletionSession>( session = std::make_shared<ccls::CompletionSession>(
project_->FindEntry(path, false), wfiles_, PCH); project_->FindEntry(path, false), wfiles_, PCH);

View File

@ -4,7 +4,6 @@
#pragma once #pragma once
#include "clang_tu.hh" #include "clang_tu.hh"
#include "lru_cache.hh"
#include "lsp.hh" #include "lsp.hh"
#include "project.hh" #include "project.hh"
#include "threaded_queue.hh" #include "threaded_queue.hh"
@ -14,10 +13,12 @@
#include <clang/Frontend/FrontendActions.h> #include <clang/Frontend/FrontendActions.h>
#include <clang/Sema/CodeCompleteOptions.h> #include <clang/Sema/CodeCompleteOptions.h>
#include <algorithm>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <vector>
namespace ccls { namespace ccls {
struct PreambleData; struct PreambleData;
@ -40,6 +41,40 @@ TextEdit ToTextEdit(const clang::SourceManager &SM,
const clang::LangOptions &L, const clang::LangOptions &L,
const clang::FixItHint &FixIt); const clang::FixItHint &FixIt);
template <typename K, typename V> struct LruCache {
LruCache(int capacity) : capacity(capacity) {}
std::shared_ptr<V> Get(const K &key) {
for (auto it = items.begin(); it != items.end(); ++it)
if (it->first == key) {
auto x = std::move(*it);
std::move_backward(items.begin(), it, it + 1);
items[0] = std::move(x);
return items[0].second;
}
return nullptr;
}
std::shared_ptr<V> Take(const K &key) {
for (auto it = items.begin(); it != items.end(); ++it)
if (it->first == key) {
auto x = std::move(it->second);
items.erase(it);
return x;
}
return nullptr;
}
void Insert(const K &key, std::shared_ptr<V> value) {
if ((int)items.size() >= capacity)
items.pop_back();
items.emplace(items.begin(), key, std::move(value));
}
void Clear() { items.clear(); }
private:
std::vector<std::pair<K, std::shared_ptr<V>>> items;
int capacity;
};
struct CompletionSession struct CompletionSession
: public std::enable_shared_from_this<CompletionSession> { : public std::enable_shared_from_this<CompletionSession> {
std::mutex mutex; std::mutex mutex;

View File

@ -1,136 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <algorithm>
#include <cassert>
#include <limits>
#include <memory>
#include <vector>
// Cache that evicts old entries which have not been used recently. Implemented
// using array/linear search so this works well for small array sizes.
template <typename TKey, typename TValue> struct LruCache {
explicit LruCache(int max_entries);
// Fetches an entry for |key|. If it does not exist, |allocator| will be
// invoked to create one.
template <typename TAllocator>
std::shared_ptr<TValue> Get(const TKey &key, TAllocator allocator);
// Fetches the entry for |filename| and updates it's usage so it is less
// likely to be evicted.
std::shared_ptr<TValue> TryGet(const TKey &key);
// TryGetEntry, except the entry is removed from the cache.
std::shared_ptr<TValue> TryTake(const TKey &key);
// Inserts an entry. Evicts the oldest unused entry if there is no space.
void Insert(const TKey &key, const std::shared_ptr<TValue> &value);
// Call |func| on existing entries. If |func| returns false iteration
// temrinates early.
template <typename TFunc> void IterateValues(TFunc func);
// Empties the cache
void Clear(void);
private:
// There is a global score counter, when we access an element we increase
// its score to the current global value, so it has the highest overall
// score. This means that the oldest/least recently accessed value has the
// lowest score.
//
// There is a bit of special logic to handle score overlow.
struct Entry {
uint32_t score = 0;
TKey key;
std::shared_ptr<TValue> value;
bool operator<(const Entry &other) const { return score < other.score; }
};
void IncrementScore();
std::vector<Entry> entries_;
int max_entries_ = 1;
uint32_t next_score_ = 0;
};
template <typename TKey, typename TValue>
LruCache<TKey, TValue>::LruCache(int max_entries) : max_entries_(max_entries) {
assert(max_entries > 0);
}
template <typename TKey, typename TValue>
template <typename TAllocator>
std::shared_ptr<TValue> LruCache<TKey, TValue>::Get(const TKey &key,
TAllocator allocator) {
std::shared_ptr<TValue> result = TryGet(key);
if (!result)
Insert(key, result = allocator());
return result;
}
template <typename TKey, typename TValue>
std::shared_ptr<TValue> LruCache<TKey, TValue>::TryGet(const TKey &key) {
// Assign new score.
for (Entry &entry : entries_) {
if (entry.key == key) {
entry.score = next_score_;
IncrementScore();
return entry.value;
}
}
return nullptr;
}
template <typename TKey, typename TValue>
std::shared_ptr<TValue> LruCache<TKey, TValue>::TryTake(const TKey &key) {
for (size_t i = 0; i < entries_.size(); ++i) {
if (entries_[i].key == key) {
std::shared_ptr<TValue> copy = entries_[i].value;
entries_.erase(entries_.begin() + i);
return copy;
}
}
return nullptr;
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::Insert(const TKey &key,
const std::shared_ptr<TValue> &value) {
if ((int)entries_.size() >= max_entries_)
entries_.erase(std::min_element(entries_.begin(), entries_.end()));
Entry entry;
entry.score = next_score_;
IncrementScore();
entry.key = key;
entry.value = value;
entries_.push_back(entry);
}
template <typename TKey, typename TValue>
template <typename TFunc>
void LruCache<TKey, TValue>::IterateValues(TFunc func) {
for (Entry &entry : entries_) {
if (!func(entry.value))
break;
}
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::IncrementScore() {
// Overflow.
if (++next_score_ == 0) {
std::sort(entries_.begin(), entries_.end());
for (Entry &entry : entries_)
entry.score = next_score_++;
}
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::Clear(void) {
entries_.clear();
next_score_ = 0;
}

View File

@ -20,7 +20,7 @@ MAKE_HASHABLE(ccls::SymbolIdx, t.usr, t.kind);
namespace ccls { namespace ccls {
MAKE_REFLECT_STRUCT(CodeActionParam::Context, diagnostics); MAKE_REFLECT_STRUCT(CodeActionParam::Context, diagnostics);
MAKE_REFLECT_STRUCT(CodeActionParam, textDocument, range, context); MAKE_REFLECT_STRUCT(CodeActionParam, textDocument, range, context);
MAKE_REFLECT_STRUCT(EmptyParam, placeholder); void Reflect(Reader &, EmptyParam &) {}
MAKE_REFLECT_STRUCT(TextDocumentParam, textDocument); MAKE_REFLECT_STRUCT(TextDocumentParam, textDocument);
MAKE_REFLECT_STRUCT(DidOpenTextDocumentParam, textDocument); MAKE_REFLECT_STRUCT(DidOpenTextDocumentParam, textDocument);
MAKE_REFLECT_STRUCT(TextDocumentContentChangeEvent, range, rangeLength, text); MAKE_REFLECT_STRUCT(TextDocumentContentChangeEvent, range, rangeLength, text);

View File

@ -43,9 +43,7 @@ struct CodeActionParam {
std::vector<Diagnostic> diagnostics; std::vector<Diagnostic> diagnostics;
} context; } context;
}; };
struct EmptyParam { struct EmptyParam {};
bool placeholder;
};
struct DidOpenTextDocumentParam { struct DidOpenTextDocumentParam {
TextDocumentItem textDocument; TextDocumentItem textDocument;
}; };

View File

@ -453,7 +453,6 @@ void LaunchStdin() {
std::string method; std::string method;
ReflectMember(reader, "id", id); ReflectMember(reader, "id", id);
ReflectMember(reader, "method", method); ReflectMember(reader, "method", method);
auto param = std::make_unique<rapidjson::Value>();
on_request->PushBack( on_request->PushBack(
{id, std::move(method), std::move(message), std::move(document)}); {id, std::move(method), std::move(message), std::move(document)});