forked from Chatterino/chatterino2
-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
optimize chatter list (Chatterino#2814)
* optimize chatter list * changelog * Fix tests Co-authored-by: Rasmus Karlsson <[email protected]>
- Loading branch information
Showing
19 changed files
with
372 additions
and
533 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
Language: Cpp | ||
|
||
AccessModifierOffset: -4 | ||
AlignEscapedNewlinesLeft: true | ||
AllowShortFunctionsOnASingleLine: false | ||
AllowShortIfStatementsOnASingleLine: false | ||
AllowShortLambdasOnASingleLine: Empty | ||
AllowShortLoopsOnASingleLine: false | ||
AlwaysBreakAfterDefinitionReturnType: false | ||
AlwaysBreakBeforeMultilineStrings: false | ||
BasedOnStyle: Google | ||
BraceWrapping: { | ||
AfterClass: 'true' | ||
AfterControlStatement: 'true' | ||
AfterFunction: 'true' | ||
AfterNamespace: 'false' | ||
BeforeCatch: 'true' | ||
BeforeElse: 'true' | ||
} | ||
BreakBeforeBraces: Custom | ||
BreakConstructorInitializersBeforeComma: true | ||
ColumnLimit: 80 | ||
ConstructorInitializerAllOnOneLineOrOnePerLine: false | ||
DerivePointerBinding: false | ||
FixNamespaceComments: true | ||
IndentCaseLabels: true | ||
IndentWidth: 4 | ||
IndentWrappedFunctionNames: true | ||
IndentPPDirectives: AfterHash | ||
IncludeBlocks: Preserve | ||
NamespaceIndentation: Inner | ||
PointerBindsToType: false | ||
SpacesBeforeTrailingComments: 2 | ||
Standard: Auto | ||
ReflowComments: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,115 @@ | ||
/* | ||
/* | ||
* File: lrucache.hpp | ||
* Author: Alexander Ponomarev | ||
* Original Author: Alexander Ponomarev | ||
* | ||
* Created on June 20, 2013, 5:09 PM | ||
*/ | ||
|
||
#ifndef _LRUCACHE_HPP_INCLUDED_ | ||
#define _LRUCACHE_HPP_INCLUDED_ | ||
#define _LRUCACHE_HPP_INCLUDED_ | ||
|
||
#include <unordered_map> | ||
#include <list> | ||
#include <cstddef> | ||
#include <list> | ||
#include <stdexcept> | ||
#include <unordered_map> | ||
|
||
namespace cache { | ||
|
||
template<typename key_t, typename value_t> | ||
class lru_cache { | ||
template <typename key_t, typename value_t> | ||
class lru_cache | ||
{ | ||
public: | ||
typedef typename std::pair<key_t, value_t> key_value_pair_t; | ||
typedef typename std::list<key_value_pair_t>::iterator list_iterator_t; | ||
|
||
lru_cache(size_t max_size) : | ||
_max_size(max_size) { | ||
} | ||
|
||
void put(const key_t& key, const value_t& value) { | ||
auto it = _cache_items_map.find(key); | ||
_cache_items_list.push_front(key_value_pair_t(key, value)); | ||
if (it != _cache_items_map.end()) { | ||
_cache_items_list.erase(it->second); | ||
_cache_items_map.erase(it); | ||
} | ||
_cache_items_map[key] = _cache_items_list.begin(); | ||
|
||
if (_cache_items_map.size() > _max_size) { | ||
auto last = _cache_items_list.end(); | ||
last--; | ||
_cache_items_map.erase(last->first); | ||
_cache_items_list.pop_back(); | ||
} | ||
} | ||
|
||
const value_t& get(const key_t& key) { | ||
auto it = _cache_items_map.find(key); | ||
if (it == _cache_items_map.end()) { | ||
throw std::range_error("There is no such key in cache"); | ||
} else { | ||
_cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second); | ||
return it->second->second; | ||
} | ||
} | ||
|
||
bool exists(const key_t& key) const { | ||
return _cache_items_map.find(key) != _cache_items_map.end(); | ||
} | ||
|
||
size_t size() const { | ||
return _cache_items_map.size(); | ||
} | ||
|
||
typedef typename std::pair<key_t, value_t> key_value_pair_t; | ||
typedef typename std::list<key_value_pair_t>::iterator list_iterator_t; | ||
|
||
lru_cache(size_t max_size) | ||
: _max_size(max_size) | ||
{ | ||
} | ||
|
||
// copy doesn't make sense since we reference the linked list elements directly | ||
lru_cache(lru_cache<key_t, value_t> &) = delete; | ||
lru_cache<key_t, value_t> &operator=(lru_cache<key_t, value_t> &) = delete; | ||
|
||
// move | ||
lru_cache(lru_cache<key_t, value_t> &&other) | ||
: _cache_items_list(std::move(other._cache_items_list)) | ||
, _cache_items_map(std::move(other._cache_items_map)) | ||
{ | ||
other._cache_items_list.clear(); | ||
other._cache_items_map.clear(); | ||
} | ||
|
||
lru_cache<key_t, value_t> &operator=(lru_cache<key_t, value_t> &&other) | ||
{ | ||
_cache_items_list = std::move(other._cache_items_list); | ||
_cache_items_map = std::move(other._cache_items_map); | ||
other._cache_items_list.clear(); | ||
other._cache_items_map.clear(); | ||
return *this; | ||
} | ||
|
||
void put(const key_t &key, const value_t &value) | ||
{ | ||
auto it = _cache_items_map.find(key); | ||
_cache_items_list.push_front(key_value_pair_t(key, value)); | ||
if (it != _cache_items_map.end()) | ||
{ | ||
_cache_items_list.erase(it->second); | ||
_cache_items_map.erase(it); | ||
} | ||
_cache_items_map[key] = _cache_items_list.begin(); | ||
|
||
if (_cache_items_map.size() > _max_size) | ||
{ | ||
auto last = _cache_items_list.end(); | ||
last--; | ||
_cache_items_map.erase(last->first); | ||
_cache_items_list.pop_back(); | ||
} | ||
} | ||
|
||
const value_t &get(const key_t &key) | ||
{ | ||
auto it = _cache_items_map.find(key); | ||
if (it == _cache_items_map.end()) | ||
{ | ||
throw std::range_error("There is no such key in cache"); | ||
} | ||
else | ||
{ | ||
_cache_items_list.splice(_cache_items_list.begin(), | ||
_cache_items_list, it->second); | ||
return it->second->second; | ||
} | ||
} | ||
|
||
bool exists(const key_t &key) const | ||
{ | ||
return _cache_items_map.find(key) != _cache_items_map.end(); | ||
} | ||
|
||
size_t size() const | ||
{ | ||
return _cache_items_map.size(); | ||
} | ||
|
||
auto begin() const | ||
{ | ||
return _cache_items_list.begin(); | ||
} | ||
|
||
auto end() const | ||
{ | ||
return _cache_items_list.end(); | ||
} | ||
|
||
private: | ||
std::list<key_value_pair_t> _cache_items_list; | ||
std::unordered_map<key_t, list_iterator_t> _cache_items_map; | ||
size_t _max_size; | ||
std::list<key_value_pair_t> _cache_items_list; | ||
std::unordered_map<key_t, list_iterator_t> _cache_items_map; | ||
size_t _max_size; | ||
}; | ||
|
||
} // namespace cache | ||
|
||
#endif /* _LRUCACHE_HPP_INCLUDED_ */ | ||
} // namespace cache | ||
|
||
#endif /* _LRUCACHE_HPP_INCLUDED_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#include "common/ChatterSet.hpp" | ||
|
||
#include <tuple> | ||
#include "debug/Benchmark.hpp" | ||
|
||
namespace chatterino { | ||
|
||
ChatterSet::ChatterSet() | ||
: items(chatterLimit) | ||
{ | ||
} | ||
|
||
void ChatterSet::addRecentChatter(const QString &userName) | ||
{ | ||
this->items.put(userName.toLower(), userName); | ||
} | ||
|
||
void ChatterSet::updateOnlineChatters( | ||
const std::unordered_set<QString> &lowerCaseUsernames) | ||
{ | ||
BenchmarkGuard bench("update online chatters"); | ||
|
||
// Create a new lru cache without the users that are not present anymore. | ||
cache::lru_cache<QString, QString> tmp(chatterLimit); | ||
|
||
for (auto &&chatter : lowerCaseUsernames) | ||
{ | ||
if (this->items.exists(chatter)) | ||
tmp.put(chatter, this->items.get(chatter)); | ||
|
||
// Less chatters than the limit => try to preserve as many as possible. | ||
else if (lowerCaseUsernames.size() < chatterLimit) | ||
tmp.put(chatter, chatter); | ||
} | ||
|
||
this->items = std::move(tmp); | ||
} | ||
|
||
bool ChatterSet::contains(const QString &userName) const | ||
{ | ||
return this->items.exists(userName.toLower()); | ||
} | ||
|
||
std::vector<QString> ChatterSet::filterByPrefix(const QString &prefix) const | ||
{ | ||
QString lowerPrefix = prefix.toLower(); | ||
std::vector<QString> result; | ||
|
||
for (auto &&item : this->items) | ||
{ | ||
if (item.first.startsWith(lowerPrefix)) | ||
result.push_back(item.second); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
} // namespace chatterino |
Oops, something went wrong.