#pragma once
#include <algorithm>
#include <exception>
#include <functional>
#include <boost/intrusive/list.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <folly/container/F14Set.h>
#include <folly/container/HeterogeneousAccess.h>
#include <folly/lang/Exception.h>
namespace folly {
template <
class TKey,
class TValue,
class THash = HeterogeneousAccessHash<TKey>,
class TKeyEqual = HeterogeneousAccessEqualTo<TKey>>
class EvictingCacheMap {
private:
struct Node;
struct NodeList;
struct KeyHasher;
struct KeyValueEqual;
using NodeMap = F14VectorSet<Node*, KeyHasher, KeyValueEqual>;
using TPair = std::pair<const TKey, TValue>;
public:
using PruneHookCall = std::function<void(TKey, TValue&&)>;
template <typename Value, typename TIterator>
class iterator_base : public boost::iterator_adaptor<
iterator_base<Value, TIterator>,
TIterator,
Value,
boost::bidirectional_traversal_tag> {
public:
iterator_base() {}
explicit iterator_base(TIterator it)
: iterator_base::iterator_adaptor_(it) {}
template <
typename V,
typename I,
std::enable_if_t<
std::is_same<V const, Value>::value &&
std::is_convertible<I, TIterator>::value,
int> = 0>
iterator_base(iterator_base<V, I> const& other)
: iterator_base::iterator_adaptor_(other.base()) {}
Value& dereference() const { return this->base_reference()->pr; }
};
using iterator = iterator_base<TPair, typename NodeList::iterator>;
using const_iterator =
iterator_base<const TPair, typename NodeList::const_iterator>;
using reverse_iterator =
iterator_base<TPair, typename NodeList::reverse_iterator>;
using const_reverse_iterator =
iterator_base<const TPair, typename NodeList::const_reverse_iterator>;
using key_type = TKey;
using mapped_type = TValue;
using hasher = THash;
static constexpr std::size_t kApproximateEntryMemUsage = 13 + sizeof(Node);
private:
template <typename K, typename T>
using EnableHeterogeneousFind = std::enable_if_t<
detail::EligibleForHeterogeneousFind<TKey, THash, TKeyEqual, K>::value,
T>;
template <typename K, typename T>
using EnableHeterogeneousInsert = std::enable_if_t<
detail::EligibleForHeterogeneousInsert<TKey, THash, TKeyEqual, K>::value,
T>;
template <typename K>
using IsIter = Disjunction<
std::is_same<iterator, remove_cvref_t<K>>,
std::is_same<const_iterator, remove_cvref_t<K>>>;
template <typename K, typename T>
using EnableHeterogeneousErase = std::enable_if_t<
detail::EligibleForHeterogeneousFind<
TKey,
THash,
TKeyEqual,
std::conditional_t<IsIter<K>::value, TKey, K>>::value &&
!IsIter<K>::value,
T>;
public:
explicit EvictingCacheMap(
std::size_t maxSize,
std::size_t clearSize = 1,
const THash& keyHash = THash(),
const TKeyEqual& keyEqual = TKeyEqual())
: … { … }
EvictingCacheMap(const EvictingCacheMap&) = delete;
EvictingCacheMap& operator=(const EvictingCacheMap&) = delete;
EvictingCacheMap(EvictingCacheMap&&) = default;
EvictingCacheMap& operator=(EvictingCacheMap&&) = default;
~EvictingCacheMap() { … }
void setMaxSize(size_t maxSize, PruneHookCall pruneHook = nullptr) { … }
std::size_t getMaxSize() const { … }
void setClearSize(std::size_t clearSize) { … }
bool exists(const TKey& key) const { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
bool exists(const K& key) const { … }
TValue& get(const TKey& key) { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
TValue& get(const K& key) { … }
iterator find(const TKey& key) { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
iterator find(const K& key) { … }
const TValue& getWithoutPromotion(const TKey& key) const { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
const TValue& getWithoutPromotion(const K& key) const { … }
TValue& getWithoutPromotion(const TKey& key) { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
TValue& getWithoutPromotion(const K& key) { … }
const_iterator findWithoutPromotion(const TKey& key) const { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
const_iterator findWithoutPromotion(const K& key) const { … }
iterator findWithoutPromotion(const TKey& key) { … }
template <typename K, EnableHeterogeneousFind<K, int> = 0>
iterator findWithoutPromotion(const K& key) { … }
bool erase(const TKey& key, PruneHookCall eraseHook = nullptr) { … }
template <typename K, EnableHeterogeneousErase<K, int> = 0>
bool erase(const K& key, PruneHookCall eraseHook = nullptr) { … }
iterator erase(const_iterator pos, PruneHookCall eraseHook = nullptr) { … }
void set(
const TKey& key,
TValue&& value,
bool promote = true,
PruneHookCall pruneHook = nullptr) { … }
void set(
const TKey& key,
const TValue& value,
bool promote = true,
PruneHookCall pruneHook = nullptr) { … }
template <typename K, EnableHeterogeneousInsert<K, int> = 0>
void set(
const K& key,
TValue&& value,
bool promote = true,
PruneHookCall pruneHook = nullptr) { … }
template <typename K, EnableHeterogeneousInsert<K, int> = 0>
void set(
const K& key,
const TValue& value,
bool promote = true,
PruneHookCall pruneHook = nullptr) { … }
std::pair<iterator, bool> insert(
const TKey& key, TValue&& value, PruneHookCall pruneHook = nullptr) { … }
std::pair<iterator, bool> insert(
const TKey& key, const TValue& value, PruneHookCall pruneHook = nullptr) { … }
template <typename K, EnableHeterogeneousInsert<K, int> = 0>
std::pair<iterator, bool> insert(
const K& key, TValue&& value, PruneHookCall pruneHook = nullptr) { … }
template <typename K, EnableHeterogeneousInsert<K, int> = 0>
std::pair<iterator, bool> insert(
const K& key, const TValue& value, PruneHookCall pruneHook = nullptr) { … }
template <typename K, typename... Args>
std::pair<iterator, bool> try_emplace(const K& key, Args&&... args) { … }
template <typename K, typename... Args>
std::pair<iterator, bool> emplaceWithPruneHook(
const K& key, Args&&... args, PruneHookCall pruneHook) { … }
std::size_t size() const { … }
bool empty() const { … }
void clear(PruneHookCall pruneHook = nullptr) { … }
void setPruneHook(PruneHookCall pruneHook) { … }
PruneHookCall getPruneHook() { … }
void prune(std::size_t pruneSize, PruneHookCall pruneHook = nullptr) { … }
iterator begin() { … }
iterator end() { … }
const_iterator begin() const { … }
const_iterator end() const { … }
const_iterator cbegin() const { … }
const_iterator cend() const { … }
reverse_iterator rbegin() { … }
reverse_iterator rend() { … }
const_reverse_iterator rbegin() const { … }
const_reverse_iterator rend() const { … }
const_reverse_iterator crbegin() const { … }
const_reverse_iterator crend() const { … }
private:
struct Node : public boost::intrusive::list_base_hook<
boost::intrusive::link_mode<boost::intrusive::safe_link>> {
template <typename K>
Node(const K& key, TValue&& value) : pr(key, std::move(value)) {}
template <typename Key, typename... Args>
explicit Node(std::piecewise_construct_t, Key&& k, Args&&... args)
: pr(std::piecewise_construct,
std::forward_as_tuple(std::forward<Key>(k)),
std::forward_as_tuple(std::forward<Args>(args)...)) {}
TPair pr;
};
using NodePtr = Node*;
struct NodeList : public boost::intrusive::list<Node> {
NodeList() {}
NodeList& operator=(NodeList&& that) noexcept {
clear_nodes();
boost::intrusive::list<Node>& this_parent = *this;
boost::intrusive::list<Node>&& that_parent = std::move(that);
this_parent = std::move(that_parent);
return *this;
}
NodeList(NodeList&& that) noexcept { *this = std::move(that); }
~NodeList() {
clear_nodes();
}
private:
void clear_nodes() {
boost::intrusive::list<Node>::clear_and_dispose(
[](Node* ptr) { delete ptr; });
}
};
struct KeyHasher {
using is_transparent = void;
using folly_is_avalanching = IsAvalanchingHasher<THash, TKey>;
KeyHasher() : hash() {}
explicit KeyHasher(const THash& keyHash) : hash(keyHash) {}
std::size_t operator()(const NodePtr& node) const {
return hash(node->pr.first);
}
template <typename K>
std::size_t operator()(const K& key) const {
return hash(key);
}
THash hash;
};
struct KeyValueEqual {
using is_transparent = void;
KeyValueEqual() : equal() {}
explicit KeyValueEqual(const TKeyEqual& keyEqual) : equal(keyEqual) {}
template <typename K>
bool operator()(const K& lhs, const NodePtr& rhs) const {
return equal(lhs, rhs->pr.first);
}
template <typename K>
bool operator()(const NodePtr& lhs, const K& rhs) const {
return equal(lhs->pr.first, rhs);
}
bool operator()(const NodePtr& lhs, const NodePtr& rhs) const {
return equal(lhs->pr.first, rhs->pr.first);
}
TKeyEqual equal;
};
template <typename K>
bool existsImpl(const K& key) const { … }
template <typename K>
TValue& getImpl(const K& key) { … }
template <typename Self>
using self_iterator_t =
std::conditional_t<std::is_const<Self>::value, const_iterator, iterator>;
template <typename Self, typename K>
static auto findImpl(Self& self, const K& key) { … }
template <typename Self, typename K>
static auto& getWithoutPromotionImpl(Self& self, const K& key) { … }
template <typename Self, typename K>
static auto findWithoutPromotionImpl(Self& self, const K& key) { … }
typename NodeList::iterator eraseImpl(
Node* ptr,
typename NodeList::const_iterator base_iter,
PruneHookCall eraseHook) { … }
template <typename K>
bool eraseKeyImpl(const K& key, PruneHookCall eraseHook) { … }
template <typename K>
void setImpl(
const K& key, TValue&& value, bool promote, PruneHookCall pruneHook) { … }
template <typename K>
auto insertImpl(const K& key, TValue&& value, PruneHookCall pruneHook) { … }
template <typename K>
auto insertImpl(std::unique_ptr<Node> nodeOwner, PruneHookCall pruneHook) { … }
template <typename K>
Node* findInIndex(const K& key) const { … }
PruneHookCall pruneHook_;
KeyHasher keyHash_;
KeyValueEqual keyEqual_;
NodeMap index_;
NodeList lru_;
std::size_t maxSize_;
std::size_t clearSize_;
};
}