Dependencies: Add lru-cache library
Adds a generic C++ based caching library to support material external modules. This is a template based library which means there is nothing to build or link. The only modification is to the CMakeLists.txt file to enable integration with FreeCAD, Original source: https://github.com/goldsborough/lru-cache
This commit is contained in:
committed by
Chris Hennes
parent
393ab112e5
commit
09f71cb40d
4
src/3rdParty/CMakeLists.txt
vendored
4
src/3rdParty/CMakeLists.txt
vendored
@@ -9,6 +9,10 @@ if(NOT FREECAD_USE_EXTERNAL_E57FORMAT)
|
||||
add_subdirectory(libE57Format)
|
||||
endif()
|
||||
|
||||
if(BUILD_MATERIAL_EXTERNAL)
|
||||
add_subdirectory(lru-cache)
|
||||
endif()
|
||||
|
||||
if (BUILD_ASSEMBLY AND NOT FREECAD_USE_EXTERNAL_ONDSELSOLVER)
|
||||
if( NOT EXISTS "${CMAKE_SOURCE_DIR}/src/3rdParty/OndselSolver/CMakeLists.txt" )
|
||||
message(FATAL_ERROR "The OndselSolver git submodule is not available. Please run
|
||||
|
||||
73
src/3rdParty/lru-cache/CMakeLists.txt
vendored
Normal file
73
src/3rdParty/lru-cache/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
###########################################################
|
||||
## CMAKE SETUP
|
||||
###########################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
project(lru-cache)
|
||||
|
||||
add_compile_options(-g)
|
||||
|
||||
########################################
|
||||
# C++ VERSIONING
|
||||
########################################
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
# check_cxx_compiler_flag("-std=c++14" COMPILER_SUPPORTS_CXX_14)
|
||||
# check_cxx_compiler_flag("-std=c++1z" COMPILER_SUPPORTS_CXX_1z)
|
||||
# check_cxx_compiler_flag("-std=c++17" COMPILER_SUPPORTS_CXX_17)
|
||||
|
||||
# if (COMPILER_SUPPORTS_CXX_1z)
|
||||
# message(STATUS "Compiling with C++1z")
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z")
|
||||
# elseif (COMPILER_SUPPORTS_CXX_14)
|
||||
# message(STATUS "Compiling with C++14")
|
||||
# set(CMAKE_CXX_STANDARD 14)
|
||||
# elseif (COMPILER_SUPPORTS_CXX_17)
|
||||
# message(STATUS "Compiling with C++17")
|
||||
# set(CMAKE_CXX_STANDARD 17)
|
||||
# else()
|
||||
# message(FATAL_ERROR "Please install a modern C++ compiler, they are not expensive.")
|
||||
# endif()
|
||||
|
||||
###########################################################
|
||||
## DEPENDENCIES
|
||||
###########################################################
|
||||
|
||||
set(CMAKE_MODULE_PATH
|
||||
${CMAKE_MODULE_PATH}
|
||||
"${CMAKE_SOURCE_DIR}/cmake/Modules/"
|
||||
)
|
||||
|
||||
###########################################################
|
||||
## INCLUDES
|
||||
###########################################################
|
||||
|
||||
# Need this top-level include for "tests/"
|
||||
# include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
###########################################################
|
||||
## EXAMPLES
|
||||
###########################################################
|
||||
|
||||
# add_subdirectory(examples)
|
||||
|
||||
########################################
|
||||
# TESTS
|
||||
########################################
|
||||
|
||||
# option(BUILD_LRU_CACHE_TESTS "Enable tests" OFF)
|
||||
|
||||
# if(BUILD_LRU_CACHE_TESTS)
|
||||
# message(STATUS "Enabling tests ...")
|
||||
# enable_testing()
|
||||
# add_subdirectory(tests)
|
||||
# else()
|
||||
# message(STATUS "Disabling tests ...")
|
||||
# endif()
|
||||
|
||||
file (GLOB LRU_HEADERS include/*.hpp)
|
||||
file (GLOB LRU_INTERNAL_HEADERS include/*.hpp)
|
||||
install (FILES ${LRU_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
|
||||
install (FILES ${LRU_INTERNAL_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include/internal)
|
||||
19
src/3rdParty/lru-cache/LICENSE
vendored
Normal file
19
src/3rdParty/lru-cache/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2016 Peter Goldsborough
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
304
src/3rdParty/lru-cache/README.md
vendored
Normal file
304
src/3rdParty/lru-cache/README.md
vendored
Normal file
File diff suppressed because one or more lines are too long
3
src/3rdParty/lru-cache/cpplint.cfg
vendored
Normal file
3
src/3rdParty/lru-cache/cpplint.cfg
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# cpplint configuration
|
||||
|
||||
filter=-build/c++11,-whitespace/parens,-runtime/references,-whitespace/operators
|
||||
2310
src/3rdParty/lru-cache/docs/Doxyfile
vendored
Normal file
2310
src/3rdParty/lru-cache/docs/Doxyfile
vendored
Normal file
File diff suppressed because it is too large
Load Diff
16
src/3rdParty/lru-cache/examples/CMakeLists.txt
vendored
Normal file
16
src/3rdParty/lru-cache/examples/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
###########################################################
|
||||
## BINARIES
|
||||
###########################################################
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/examples)
|
||||
|
||||
########################################
|
||||
# TARGETS
|
||||
########################################
|
||||
|
||||
add_executable(fibonacci-basic fibonacci-basic.cpp)
|
||||
add_executable(fibonacci-timed fibonacci-timed.cpp)
|
||||
add_executable(statistics statistics.cpp)
|
||||
add_executable(callbacks callbacks.cpp)
|
||||
add_executable(lowercase lowercase.cpp)
|
||||
add_executable(wrap wrap.cpp)
|
||||
76
src/3rdParty/lru-cache/examples/callbacks.cpp
vendored
Normal file
76
src/3rdParty/lru-cache/examples/callbacks.cpp
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using Cache = LRU::Cache<std::uint64_t, std::uint64_t>;
|
||||
|
||||
std::uint64_t fibonacci(std::uint64_t n, Cache& cache) {
|
||||
if (n < 2) return 1;
|
||||
|
||||
// We std::uint64_ternally keep track of the last accessed key, meaning a
|
||||
// `contains(key)` + `lookup(key)` sequence will involve only a single hash
|
||||
// table lookup.
|
||||
if (cache.contains(n)) return cache[n];
|
||||
|
||||
auto value = fibonacci(n - 1, cache) + fibonacci(n - 2, cache);
|
||||
|
||||
// Caches are 100% move-aware and we have implemented
|
||||
// `unordered_map` style emplacement and insertion.
|
||||
cache.emplace(n, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::uint64_t fibonacci(std::uint64_t n) {
|
||||
// Use a capacity of 100 (after 100 insertions, the next insertion will evict
|
||||
// the least-recently inserted element). The default capacity is 128. Note
|
||||
// that for fibonacci, a capacity of 2 is sufficient (and ideal).
|
||||
Cache cache(100);
|
||||
|
||||
// clang-format off
|
||||
cache.hit_callback([](auto& key, auto& value) {
|
||||
std::clog << "Hit for entry ("
|
||||
<< key << ", " << value << ")"
|
||||
<< std::endl;
|
||||
});
|
||||
|
||||
cache.miss_callback([](auto& key) {
|
||||
std::clog << "Miss for " << key<< std::endl;
|
||||
});
|
||||
|
||||
cache.access_callback([](auto& key, bool was_hit) {
|
||||
std::clog << "Access for " << key
|
||||
<< " was a " << (was_hit ? "hit" : "miss")
|
||||
<< std::endl;
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
auto value = fibonacci(n, cache);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
std::cout << fibonacci(10) << std::endl;
|
||||
}
|
||||
55
src/3rdParty/lru-cache/examples/fibonacci-basic.cpp
vendored
Normal file
55
src/3rdParty/lru-cache/examples/fibonacci-basic.cpp
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using Cache = LRU::Cache<int, int>;
|
||||
|
||||
int fibonacci(int n, Cache& cache) {
|
||||
if (n < 2) return 1;
|
||||
|
||||
// We internally keep track of the last accessed key, meaning a
|
||||
// `contains(key)` + `lookup(key)` sequence will involve only a single hash
|
||||
// table lookup.
|
||||
if (cache.contains(n)) return cache[n];
|
||||
|
||||
auto value = fibonacci(n - 1, cache) + fibonacci(n - 2, cache);
|
||||
|
||||
// Caches are 100% move-aware and we have implemented
|
||||
// `unordered_map` style emplacement and insertion.
|
||||
cache.emplace(n, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int fibonacci(int n) {
|
||||
// Use a capacity of 100 (after 100 insertions, the next insertion will evict
|
||||
// the least-recently accessed element). The default capacity is 128. Note
|
||||
// that for fibonacci, a capacity of 2 is sufficient (and ideal).
|
||||
Cache cache(100);
|
||||
return fibonacci(n, cache);
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
std::cout << fibonacci(32) << std::endl;
|
||||
}
|
||||
57
src/3rdParty/lru-cache/examples/fibonacci-timed.cpp
vendored
Normal file
57
src/3rdParty/lru-cache/examples/fibonacci-timed.cpp
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using Cache = LRU::TimedCache<int, int>;
|
||||
|
||||
int fibonacci(int n, Cache& cache) {
|
||||
if (n < 2) return 1;
|
||||
|
||||
// We internally keep track of the last accessed key, meaning a
|
||||
// `contains(key)` + `lookup(key)` sequence will involve only a single hash
|
||||
// table lookup.
|
||||
if (cache.contains(n)) return cache[n];
|
||||
|
||||
auto value = fibonacci(n - 1, cache) + fibonacci(n - 2, cache);
|
||||
|
||||
// Caches are 100% move-aware and we have implemented
|
||||
// `unordered_map` style emplacement and insertion.
|
||||
cache.emplace(n, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int fibonacci(int n) {
|
||||
// Use a time to live of 100ms. This means that 100ms after insertion, a key
|
||||
// will be said to have "expired" and `contains(key)` will return false.
|
||||
Cache cache(100ms);
|
||||
return fibonacci(n, cache);
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
std::cout << fibonacci(32) << std::endl;
|
||||
}
|
||||
47
src/3rdParty/lru-cache/examples/lowercase.cpp
vendored
Normal file
47
src/3rdParty/lru-cache/examples/lowercase.cpp
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#include "lru/lowercase.hpp"
|
||||
|
||||
void print(lru::tag::basic_cache) {
|
||||
std::cout << "basic cache" << '\n';
|
||||
}
|
||||
|
||||
void print(lru::tag::timed_cache) {
|
||||
std::cout << "timed cache" << '\n';
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
lru::cache<int, int> cache;
|
||||
lru::timed_cache<int, int> timed_cache(100ms);
|
||||
|
||||
print(cache.tag());
|
||||
print(timed_cache.tag());
|
||||
|
||||
lru::cache<int, int>::ordered_const_iterator iterator(cache.begin());
|
||||
|
||||
lru::statistics<int> stats;
|
||||
}
|
||||
76
src/3rdParty/lru-cache/examples/statistics.cpp
vendored
Normal file
76
src/3rdParty/lru-cache/examples/statistics.cpp
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using Cache = LRU::Cache<std::uint64_t, std::uint64_t>;
|
||||
|
||||
std::uint64_t fibonacci(std::uint64_t n, Cache& cache) {
|
||||
if (n < 2) return 1;
|
||||
|
||||
// We std::uint64_ternally keep track of the last accessed key, meaning a
|
||||
// `contains(key)` + `lookup(key)` sequence will involve only a single hash
|
||||
// table lookup.
|
||||
if (cache.contains(n)) return cache[n];
|
||||
|
||||
auto value = fibonacci(n - 1, cache) + fibonacci(n - 2, cache);
|
||||
|
||||
// Caches are 100% move-aware and we have implemented
|
||||
// `unordered_map` style emplacement and insertion.
|
||||
cache.emplace(n, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::uint64_t fibonacci(std::uint64_t n) {
|
||||
// Use a capacity of 100 (after 100 insertions, the next insertion will evict
|
||||
// the least-recently inserted element). The default capacity is 128. Note
|
||||
// that for fibonacci, a capacity of 2 is sufficient (and ideal).
|
||||
Cache cache(100);
|
||||
cache.monitor(2, 3, 4, 5);
|
||||
auto value = fibonacci(n, cache);
|
||||
|
||||
for (auto i : {2, 3, 4, 5}) {
|
||||
auto stats = cache.stats().stats_for(i);
|
||||
// clang-format off
|
||||
std::cout << "Statistics for " << i << ": "
|
||||
<< stats.hits << " hit(s), "
|
||||
<< stats.misses << " miss(es)."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// You'll notice we'll always have n - 1 misses, for each time we access
|
||||
// one of the numbers in [0, n] for the first time.
|
||||
std::cout << "Overall: "
|
||||
<< cache.stats().total_hits() << " hit(s), "
|
||||
<< cache.stats().total_misses() << " miss(es)."
|
||||
<< std::endl;
|
||||
// clang-format on
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
// The last number that fits into a 64 bit unsigned number
|
||||
std::cout << fibonacci(92) << std::endl;
|
||||
}
|
||||
45
src/3rdParty/lru-cache/examples/wrap.cpp
vendored
Normal file
45
src/3rdParty/lru-cache/examples/wrap.cpp
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
int f(int x) {
|
||||
std::this_thread::sleep_for(1s);
|
||||
return x;
|
||||
}
|
||||
|
||||
auto main() -> int {
|
||||
// Use a time-to-live of 2 minutes and a
|
||||
// capacity of 128 for an LRU::TimedCache
|
||||
auto wrapped = LRU::timed_wrap(f, 2min, 128);
|
||||
|
||||
std::cout << "Slow the first time ..." << '\n';
|
||||
wrapped(42);
|
||||
|
||||
std::cout << "Fast the second time!" << '\n';
|
||||
wrapped(42);
|
||||
}
|
||||
40
src/3rdParty/lru-cache/include/lru/cache-tags.hpp
vendored
Normal file
40
src/3rdParty/lru-cache/include/lru/cache-tags.hpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_CACHE_TAGS_HPP
|
||||
#define LRU_CACHE_TAGS_HPP
|
||||
|
||||
namespace LRU {
|
||||
namespace Tag {
|
||||
struct BasicCache {};
|
||||
struct TimedCache {};
|
||||
} // namespace Tag
|
||||
|
||||
namespace Lowercase {
|
||||
namespace tag {
|
||||
using basic_cache = ::LRU::Tag::BasicCache;
|
||||
using timed_cache = ::LRU::Tag::TimedCache;
|
||||
} // namespace tag
|
||||
} // namespace Lowercase
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_CACHE_TAGS_HPP
|
||||
207
src/3rdParty/lru-cache/include/lru/cache.hpp
vendored
Normal file
207
src/3rdParty/lru-cache/include/lru/cache.hpp
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_CACHE_HPP
|
||||
#define LRU_CACHE_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <lru/cache-tags.hpp>
|
||||
#include <lru/error.hpp>
|
||||
#include <lru/internal/base-cache.hpp>
|
||||
#include <lru/internal/information.hpp>
|
||||
#include <lru/internal/last-accessed.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename HashFunction,
|
||||
typename KeyEqual>
|
||||
using UntimedCacheBase = Internal::BaseCache<Key,
|
||||
Value,
|
||||
Internal::Information,
|
||||
HashFunction,
|
||||
KeyEqual,
|
||||
Tag::BasicCache>;
|
||||
} // namespace Internal
|
||||
|
||||
/// A basic LRU cache implementation.
|
||||
///
|
||||
/// An LRU cache is a fixed-size cache that remembers the order in which
|
||||
/// elements were inserted into it. When the size of the cache exceeds its
|
||||
/// capacity, the "least-recently-used" (LRU) element is erased. In our
|
||||
/// implementation, usage is defined as insertion, but not lookup. That is,
|
||||
/// looking up an element does not move it to the "front" of the cache (making
|
||||
/// the operation faster). Only insertions (and erasures) can change the order
|
||||
/// of elements. The capacity of the cache can be modified at any time.
|
||||
///
|
||||
/// \see LRU::TimedCache
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename HashFunction = std::hash<Key>,
|
||||
typename KeyEqual = std::equal_to<Key>>
|
||||
class Cache
|
||||
: public Internal::UntimedCacheBase<Key, Value, HashFunction, KeyEqual> {
|
||||
private:
|
||||
using super = Internal::UntimedCacheBase<Key, Value, HashFunction, KeyEqual>;
|
||||
using PRIVATE_BASE_CACHE_MEMBERS;
|
||||
|
||||
public:
|
||||
using PUBLIC_BASE_CACHE_MEMBERS;
|
||||
using typename super::size_t;
|
||||
|
||||
/// \copydoc BaseCache::BaseCache(size_t,const HashFunction&,const KeyEqual&)
|
||||
/// \detailss The capacity defaults to an internal constant, currently 128.
|
||||
explicit Cache(size_t capacity = Internal::DEFAULT_CAPACITY,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(capacity, hash, equal) {
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache(size_t,Iterator,Iterator,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename Iterator>
|
||||
Cache(size_t capacity,
|
||||
Iterator begin,
|
||||
Iterator end,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(capacity, begin, end, hash, equal) {
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache(Iterator,Iterator,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename Iterator>
|
||||
Cache(Iterator begin,
|
||||
Iterator end,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(begin, end, hash, equal) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param capacity The capacity of the cache.
|
||||
/// \param range A range to construct the cache with.
|
||||
/// \param hash The hash function to use for the internal map.
|
||||
/// \param key_equal The key equality function to use for the internal map.
|
||||
template <typename Range, typename = Internal::enable_if_range<Range>>
|
||||
Cache(size_t capacity,
|
||||
Range&& range,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(capacity, std::forward<Range>(range), hash, equal) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param range A range to construct the cache with.
|
||||
/// \param hash The hash function to use for the internal map.
|
||||
/// \param key_equal The key equality function to use for the internal map.
|
||||
template <typename Range, typename = Internal::enable_if_range<Range>>
|
||||
explicit Cache(Range&& range,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(std::forward<Range>(range), hash, equal) {
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache(InitializerList,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
Cache(InitializerList list,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual()) // NOLINT(runtime/explicit)
|
||||
: super(list, hash, equal) {
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache(size_t,InitializerList,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
Cache(size_t capacity,
|
||||
InitializerList list,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual()) // NOLINT(runtime/explicit)
|
||||
: super(capacity, list, hash, equal) {
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::find(const Key&)
|
||||
UnorderedIterator find(const Key& key) override {
|
||||
auto iterator = _map.find(key);
|
||||
if (iterator != _map.end()) {
|
||||
_register_hit(key, iterator->second.value);
|
||||
_move_to_front(iterator->second.order);
|
||||
_last_accessed = iterator;
|
||||
} else {
|
||||
_register_miss(key);
|
||||
}
|
||||
|
||||
return {*this, iterator};
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::find(const Key&) const
|
||||
UnorderedConstIterator find(const Key& key) const override {
|
||||
auto iterator = _map.find(key);
|
||||
if (iterator != _map.end()) {
|
||||
_register_hit(key, iterator->second.value);
|
||||
_move_to_front(iterator->second.order);
|
||||
_last_accessed = iterator;
|
||||
} else {
|
||||
_register_miss(key);
|
||||
}
|
||||
|
||||
return {*this, iterator};
|
||||
}
|
||||
|
||||
/// \returns The most-recently inserted element.
|
||||
const Key& front() const noexcept {
|
||||
if (is_empty()) {
|
||||
throw LRU::Error::EmptyCache("front");
|
||||
} else {
|
||||
// The queue is reversed for natural order of iteration.
|
||||
return _order.back();
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns The least-recently inserted element.
|
||||
const Key& back() const noexcept {
|
||||
if (is_empty()) {
|
||||
throw LRU::Error::EmptyCache("back");
|
||||
} else {
|
||||
// The queue is reversed for natural order of iteration.
|
||||
return _order.front();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace Lowercase {
|
||||
template <typename... Ts>
|
||||
using cache = Cache<Ts...>;
|
||||
} // namespace Lowercase
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_CACHE_HPP
|
||||
134
src/3rdParty/lru-cache/include/lru/entry.hpp
vendored
Normal file
134
src/3rdParty/lru-cache/include/lru/entry.hpp
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_PAIR_HPP
|
||||
#define LRU_PAIR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace LRU {
|
||||
|
||||
/// A entry of references to the key and value of an entry in a cache.
|
||||
///
|
||||
/// Instances of this class are usually the result of dereferencing an iterator.
|
||||
///
|
||||
/// \tparam Key The key type of the pair.
|
||||
/// \tparam Value The value type of the pair.
|
||||
template <typename Key, typename Value>
|
||||
struct Entry final {
|
||||
using KeyType = Key;
|
||||
using ValueType = Value;
|
||||
using first_type = Key;
|
||||
using second_type = Value;
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param key The key of the entry.
|
||||
/// \param value The value of the entry.
|
||||
Entry(const Key& key, Value& value) : first(key), second(value) {
|
||||
}
|
||||
|
||||
/// Generalized copy constructor.
|
||||
///
|
||||
/// Mainly for conversion from non-const values to const values.
|
||||
///
|
||||
/// \param other The entry to construct from.
|
||||
template <typename AnyKey,
|
||||
typename AnyValue,
|
||||
typename =
|
||||
std::enable_if_t<(std::is_convertible<AnyKey, Key>::value &&
|
||||
std::is_convertible<AnyValue, Value>::value)>>
|
||||
Entry(const Entry<AnyKey, AnyValue>& other)
|
||||
: first(other.first), second(other.second) {
|
||||
}
|
||||
|
||||
/// Compares two entrys for equality.
|
||||
///
|
||||
/// \param first The first entry to compare.
|
||||
/// \param second The second entry to compare.
|
||||
/// \returns True if the firest entry equals the second, else false.
|
||||
template <typename Pair, typename = typename Pair::first_type>
|
||||
friend bool operator==(const Entry& first, const Pair& second) noexcept {
|
||||
return first.first == second.first && first.second == second.second;
|
||||
}
|
||||
|
||||
/// Compares two entrys for equality.
|
||||
///
|
||||
/// \param first The first entry to compare.
|
||||
/// \param second The second entry to compare.
|
||||
/// \returns True if the first entry equals the second, else false.
|
||||
template <typename Pair, typename = typename Pair::first_type>
|
||||
friend bool operator==(const Pair& first, const Entry& second) noexcept {
|
||||
return second == first;
|
||||
}
|
||||
|
||||
/// Compares two entrys for inequality.
|
||||
///
|
||||
/// \param first The first entry to compare.
|
||||
/// \param second The second entry to compare.
|
||||
/// \returns True if the first entry does not equal the second, else false.
|
||||
template <typename Pair, typename = typename Pair::first_type>
|
||||
friend bool operator!=(const Entry& first, const Pair& second) noexcept {
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
/// Compares two entrys for inequality.
|
||||
///
|
||||
/// \param first The first entry to compare.
|
||||
/// \param second The second entry to compare.fdas
|
||||
/// \returns True if the first entry does not equal the second, else false.
|
||||
template <typename Pair, typename = typename Pair::first_type>
|
||||
friend bool operator!=(const Pair& first, const Entry& second) noexcept {
|
||||
return second != first;
|
||||
}
|
||||
|
||||
/// \returns A `std::pair` instance with the key and value of this entry.
|
||||
operator std::pair<const Key&, Value&>() noexcept {
|
||||
return {first, second};
|
||||
}
|
||||
|
||||
/// \returns The key of the entry (`first`).
|
||||
const Key& key() const noexcept {
|
||||
return first;
|
||||
}
|
||||
|
||||
/// \returns The value of the entry (`second`).
|
||||
Value& value() noexcept {
|
||||
return second;
|
||||
}
|
||||
|
||||
/// \returns The value of the entry (`second`).
|
||||
const Value& value() const noexcept {
|
||||
return second;
|
||||
}
|
||||
|
||||
/// The key of the entry.
|
||||
const Key& first;
|
||||
|
||||
/// The value of the entry.
|
||||
Value& second;
|
||||
};
|
||||
} // namespace LRU
|
||||
|
||||
|
||||
#endif // LRU_PAIR_HPP
|
||||
107
src/3rdParty/lru-cache/include/lru/error.hpp
vendored
Normal file
107
src/3rdParty/lru-cache/include/lru/error.hpp
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_ERRORS_HPP
|
||||
#define LRU_INTERNAL_ERRORS_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace LRU {
|
||||
namespace Error {
|
||||
|
||||
/// Exception thrown when the value of an invalid key was requested.
|
||||
struct KeyNotFound : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
|
||||
KeyNotFound() : super("Failed to find key") {
|
||||
}
|
||||
|
||||
explicit KeyNotFound(const std::string& key)
|
||||
: super("Failed to find key: " + key) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception thrown when the value of an expired key was requested.
|
||||
struct KeyExpired : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
|
||||
explicit KeyExpired(const std::string& key)
|
||||
: super("Key found, but expired: " + key) {
|
||||
}
|
||||
|
||||
KeyExpired() : super("Key found, but expired") {
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception thrown when requesting the front or end key of an empty cache.
|
||||
struct EmptyCache : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
explicit EmptyCache(const std::string& what_was_expected)
|
||||
: super("Requested " + what_was_expected + " of empty cache") {
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception thrown when attempting to convert an invalid unordered iterator to
|
||||
/// an ordered iterator.
|
||||
struct InvalidIteratorConversion : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
InvalidIteratorConversion()
|
||||
: super("Cannot convert past-the-end unordered to ordered iterator") {
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception thrown when attempting to erase the past-the-end iterator.
|
||||
struct InvalidIterator : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
InvalidIterator() : super("Past-the-end iterator is invalid here") {
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception thrown when requesting statistics about an unmonitored key.
|
||||
struct UnmonitoredKey : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
UnmonitoredKey() : super("Requested statistics for unmonitored key") {
|
||||
}
|
||||
};
|
||||
|
||||
/// Exception thrown when requesting the statistics object of a cache when none
|
||||
/// was registered.
|
||||
struct NotMonitoring : public std::runtime_error {
|
||||
using super = std::runtime_error;
|
||||
NotMonitoring() : super("Statistics monitoring not enabled for this cache") {
|
||||
}
|
||||
};
|
||||
|
||||
namespace Lowercase {
|
||||
using key_not_found = KeyNotFound;
|
||||
using key_expired = KeyExpired;
|
||||
using empty_cache = EmptyCache;
|
||||
using invalid_iterator_conversion = InvalidIteratorConversion;
|
||||
using invalid_iterator = InvalidIterator;
|
||||
using unmonitored_key = UnmonitoredKey;
|
||||
using not_monitoring = NotMonitoring;
|
||||
} // namespace Lowercase
|
||||
|
||||
} // namespace Error
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_INTERNAL_ERRORS_HPP
|
||||
76
src/3rdParty/lru-cache/include/lru/insertion-result.hpp
vendored
Normal file
76
src/3rdParty/lru-cache/include/lru/insertion-result.hpp
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INSERTION_RESULT_HPP
|
||||
#define LRU_INSERTION_RESULT_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace LRU {
|
||||
|
||||
/// The result of an insertion into a cache.
|
||||
///
|
||||
/// This is a semantically nicer alternative to a generic `std::pair`, as is
|
||||
/// returned by `std::unordered_map` or so. It still has the same static
|
||||
/// interface as the `std::pair` (with `first` and `second` members), but adds
|
||||
/// nicer `was_inserted()` and `iterator()` accessors.
|
||||
///
|
||||
/// \tparam Iterator The class of the iterator contained in the result.
|
||||
template <typename Iterator>
|
||||
struct InsertionResult final {
|
||||
using IteratorType = Iterator;
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param result Whether the result was successful.
|
||||
/// \param iterator The iterator pointing to the inserted or updated key.
|
||||
InsertionResult(bool result, Iterator iterator)
|
||||
: first(result), second(iterator) {
|
||||
}
|
||||
|
||||
/// \returns True if the key was newly inserted, false if it was only updated.
|
||||
bool was_inserted() const noexcept {
|
||||
return first;
|
||||
}
|
||||
|
||||
/// \returns The iterator pointing to the inserted or updated key.
|
||||
Iterator iterator() const noexcept {
|
||||
return second;
|
||||
}
|
||||
|
||||
/// \copydoc was_inserted
|
||||
explicit operator bool() const noexcept {
|
||||
return was_inserted();
|
||||
}
|
||||
|
||||
/// Whether the result was successful.
|
||||
bool first;
|
||||
|
||||
/// The iterator pointing to the inserted or updated key.
|
||||
Iterator second;
|
||||
};
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
|
||||
#endif // LRU_INSERTION_RESULT_HPP
|
||||
1588
src/3rdParty/lru-cache/include/lru/internal/base-cache.hpp
vendored
Normal file
1588
src/3rdParty/lru-cache/include/lru/internal/base-cache.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
216
src/3rdParty/lru-cache/include/lru/internal/base-iterator.hpp
vendored
Normal file
216
src/3rdParty/lru-cache/include/lru/internal/base-iterator.hpp
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_BASE_ITERATOR_HPP
|
||||
#define LRU_INTERNAL_BASE_ITERATOR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <lru/entry.hpp>
|
||||
#include <lru/internal/optional.hpp>
|
||||
|
||||
#define PUBLIC_BASE_ITERATOR_MEMBERS \
|
||||
typename super::Entry; \
|
||||
using typename super::KeyType; \
|
||||
using typename super::ValueType;
|
||||
|
||||
#define PRIVATE_BASE_ITERATOR_MEMBERS \
|
||||
super::_iterator; \
|
||||
using super::_entry; \
|
||||
using super::_cache;
|
||||
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// The base class for all (ordered and unordered) iterators.
|
||||
///
|
||||
/// All iterators over our LRU caches store a reference to the cache they point
|
||||
/// into, an underlying iterator they adapt (e.g. a map iterator or list
|
||||
/// iterator) as well as a entry, a reference to which is returned when
|
||||
/// dereferencing the iterator.
|
||||
///
|
||||
/// \tparam IteratorTag A standard iterator category tag.
|
||||
/// \tparam Key The key type over which instances of the iterator iterate.
|
||||
/// \tparam Value The value type over which instances of the iterator iterate.
|
||||
/// \tparam Cache The type of the cache instances of the iterator point into.
|
||||
/// \tparam UnderlyingIterator The underlying iterator class used to implement
|
||||
/// the iterator.
|
||||
template <typename IteratorTag,
|
||||
typename Key,
|
||||
typename Value,
|
||||
typename Cache,
|
||||
typename UnderlyingIterator>
|
||||
class BaseIterator : public std::iterator<IteratorTag, LRU::Entry<Key, Value>> {
|
||||
public:
|
||||
using KeyType = Key;
|
||||
using ValueType =
|
||||
std::conditional_t<std::is_const<Cache>::value, const Value, Value>;
|
||||
using Entry = LRU::Entry<KeyType, ValueType>;
|
||||
|
||||
/// Default constructor.
|
||||
BaseIterator() noexcept : _cache(nullptr) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param cache The cache this iterator points into.
|
||||
/// \param iterator The underlying iterator to adapt.
|
||||
BaseIterator(Cache& cache, const UnderlyingIterator& iterator) noexcept
|
||||
: _iterator(iterator), _cache(&cache) {
|
||||
}
|
||||
|
||||
/// Copy constructor.
|
||||
///
|
||||
/// Differs from the default copy constructor in that it does not copy the
|
||||
/// entry.
|
||||
///
|
||||
/// \param other The base iterator to copy.
|
||||
BaseIterator(const BaseIterator& other) noexcept
|
||||
: _iterator(other._iterator), _cache(other._cache) {
|
||||
// Note: we do not copy the entry, as it would require a new allocation.
|
||||
// Since iterators are often taken by value, this may incur a high cost.
|
||||
// As such we delay the retrieval of the entry to the first call to entry().
|
||||
}
|
||||
|
||||
/// Copy assignment operator.
|
||||
///
|
||||
/// Differs from the default copy assignment
|
||||
/// operator in that it does not copy the entry.
|
||||
///
|
||||
/// \param other The base iterator to copy.
|
||||
/// \return The base iterator instance.
|
||||
BaseIterator& operator=(const BaseIterator& other) noexcept {
|
||||
if (this != &other) {
|
||||
_iterator = other._iterator;
|
||||
_cache = other._cache;
|
||||
_entry.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Move constructor.
|
||||
BaseIterator(BaseIterator&& other) noexcept = default;
|
||||
|
||||
/// Move assignment operator.
|
||||
BaseIterator& operator=(BaseIterator&& other) noexcept = default;
|
||||
|
||||
/// Generalized copy constructor.
|
||||
///
|
||||
/// Mainly necessary for non-const to const conversion.
|
||||
///
|
||||
/// \param other The base iterator to copy from.
|
||||
template <typename AnyIteratorTag,
|
||||
typename AnyKeyType,
|
||||
typename AnyValueType,
|
||||
typename AnyCacheType,
|
||||
typename AnyUnderlyingIteratorType>
|
||||
BaseIterator(const BaseIterator<AnyIteratorTag,
|
||||
AnyKeyType,
|
||||
AnyValueType,
|
||||
AnyCacheType,
|
||||
AnyUnderlyingIteratorType>& other)
|
||||
: _iterator(other._iterator), _entry(other._entry), _cache(other._cache) {
|
||||
}
|
||||
|
||||
/// Generalized move constructor.
|
||||
///
|
||||
/// Mainly necessary for non-const to const conversion.
|
||||
///
|
||||
/// \param other The base iterator to move into this one.
|
||||
template <typename AnyIteratorTag,
|
||||
typename AnyKeyType,
|
||||
typename AnyValueType,
|
||||
typename AnyCacheType,
|
||||
typename AnyUnderlyingIteratorType>
|
||||
BaseIterator(BaseIterator<AnyIteratorTag,
|
||||
AnyKeyType,
|
||||
AnyValueType,
|
||||
AnyCacheType,
|
||||
AnyUnderlyingIteratorType>&& other) noexcept
|
||||
: _iterator(std::move(other._iterator))
|
||||
, _entry(std::move(other._entry))
|
||||
, _cache(std::move(other._cache)) {
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
virtual ~BaseIterator() = default;
|
||||
|
||||
/// Swaps this base iterator with another one.
|
||||
///
|
||||
/// \param other The other iterator to swap with.
|
||||
void swap(BaseIterator& other) noexcept {
|
||||
// Enable ADL
|
||||
using std::swap;
|
||||
|
||||
swap(_iterator, other._iterator);
|
||||
swap(_entry, other._entry);
|
||||
swap(_cache, other._cache);
|
||||
}
|
||||
|
||||
/// Swaps two base iterator.
|
||||
///
|
||||
/// \param first The first iterator to swap.
|
||||
/// \param second The second iterator to swap.
|
||||
friend void swap(BaseIterator& first, BaseIterator& second) noexcept {
|
||||
first.swap(second);
|
||||
}
|
||||
|
||||
/// \returns A reference to the current entry pointed to by the iterator.
|
||||
virtual Entry& operator*() noexcept = 0;
|
||||
|
||||
/// \returns A pointer to the current entry pointed to by the iterator.
|
||||
Entry* operator->() noexcept {
|
||||
return &(**this);
|
||||
}
|
||||
|
||||
/// \copydoc operator*()
|
||||
virtual Entry& entry() = 0;
|
||||
|
||||
/// \returns A reference to the value of the entry currently pointed to by the
|
||||
/// iterator.
|
||||
virtual ValueType& value() = 0;
|
||||
|
||||
/// \returns A reference to the key of the entry currently pointed to by the
|
||||
/// iterator.
|
||||
virtual const Key& key() = 0;
|
||||
|
||||
protected:
|
||||
template <typename, typename, typename, typename, typename>
|
||||
friend class BaseIterator;
|
||||
|
||||
/// The underlying iterator this iterator class adapts.
|
||||
UnderlyingIterator _iterator;
|
||||
|
||||
/// The entry optionally being stored.
|
||||
Optional<Entry> _entry;
|
||||
|
||||
/// A pointer to the cache this iterator points into.
|
||||
/// Pointer and not reference because it's cheap to copy.
|
||||
/// Pointer and not `std::reference_wrapper` because the class needs to be
|
||||
/// default-constructible.
|
||||
Cache* _cache;
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_INTERNAL_BASE_ITERATOR_HPP
|
||||
338
src/3rdParty/lru-cache/include/lru/internal/base-ordered-iterator.hpp
vendored
Normal file
338
src/3rdParty/lru-cache/include/lru/internal/base-ordered-iterator.hpp
vendored
Normal file
@@ -0,0 +1,338 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef BASE_ORDERED_ITERATOR_HPP
|
||||
#define BASE_ORDERED_ITERATOR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include <lru/entry.hpp>
|
||||
#include <lru/error.hpp>
|
||||
#include <lru/internal/base-iterator.hpp>
|
||||
#include <lru/internal/base-unordered-iterator.hpp>
|
||||
#include <lru/internal/definitions.hpp>
|
||||
#include <lru/internal/optional.hpp>
|
||||
#include <lru/iterator-tags.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
template <typename Key, typename Value, typename Cache>
|
||||
using BaseForBaseOrderedIterator =
|
||||
BaseIterator<std::bidirectional_iterator_tag,
|
||||
Key,
|
||||
Value,
|
||||
Cache,
|
||||
typename Queue<Key>::const_iterator>;
|
||||
|
||||
/// The base class for all const and non-const ordered iterators.
|
||||
///
|
||||
/// Ordered iterators are bidirectional iterators that iterate over the keys of
|
||||
/// a cache in the order in which they were inserted into the cache. As they
|
||||
/// only iterate over the keys, they must perform hash lookups to retrieve the
|
||||
/// value the first time they are dereferenced. This makes them slightly less
|
||||
/// efficient than unordered iterators. However, they also have the additional
|
||||
/// property that they may be constructed from unordered iterators, and that
|
||||
/// they can be decremented.
|
||||
///
|
||||
/// \tparam Key The key type over which instances of the iterator iterate.
|
||||
/// \tparam Value The value type over which instances of the iterator iterate.
|
||||
/// \tparam Cache The type of the cache instances of the iterator point into.
|
||||
template <typename Key, typename Value, typename Cache>
|
||||
class BaseOrderedIterator
|
||||
: public BaseForBaseOrderedIterator<Key, Value, Cache> {
|
||||
protected:
|
||||
using super = BaseForBaseOrderedIterator<Key, Value, Cache>;
|
||||
using PRIVATE_BASE_ITERATOR_MEMBERS;
|
||||
using UnderlyingIterator = typename Queue<Key>::const_iterator;
|
||||
|
||||
public:
|
||||
using Tag = LRU::Tag::OrderedIterator;
|
||||
using PUBLIC_BASE_ITERATOR_MEMBERS;
|
||||
|
||||
/// Constructor.
|
||||
BaseOrderedIterator() noexcept = default;
|
||||
|
||||
/// \copydoc BaseIterator::BaseIterator(Cache,UnderlyingIterator)
|
||||
BaseOrderedIterator(Cache& cache, UnderlyingIterator iterator)
|
||||
: super(cache, iterator) {
|
||||
}
|
||||
|
||||
/// Generalized copy constructor.
|
||||
///
|
||||
/// \param other The ordered iterator to contruct from.
|
||||
template <typename AnyKey, typename AnyValue, typename AnyCache>
|
||||
BaseOrderedIterator(
|
||||
const BaseOrderedIterator<AnyKey, AnyValue, AnyCache>& other)
|
||||
: super(other) {
|
||||
}
|
||||
|
||||
/// Generalized move constructor.
|
||||
///
|
||||
/// \param other The ordered iterator to move into this one.
|
||||
template <typename AnyKey, typename AnyValue, typename AnyCache>
|
||||
BaseOrderedIterator(BaseOrderedIterator<AnyKey, AnyValue, AnyCache>&& other)
|
||||
: super(std::move(other)) {
|
||||
}
|
||||
|
||||
/// Generalized conversion copy constructor.
|
||||
///
|
||||
/// \param unordered_iterator The unordered iterator to construct from.
|
||||
template <
|
||||
typename AnyCache,
|
||||
typename UnderlyingIterator,
|
||||
typename = std::enable_if_t<
|
||||
std::is_same<std::decay_t<AnyCache>, std::decay_t<Cache>>::value>>
|
||||
BaseOrderedIterator(const BaseUnorderedIterator<AnyCache, UnderlyingIterator>&
|
||||
unordered_iterator) {
|
||||
// Atomicity
|
||||
_throw_if_at_invalid(unordered_iterator);
|
||||
_cache = unordered_iterator._cache;
|
||||
_iterator = unordered_iterator._iterator->second.order;
|
||||
}
|
||||
|
||||
/// Generalized conversion move constructor.
|
||||
///
|
||||
/// \param unordered_iterator The unordered iterator to move-construct from.
|
||||
template <
|
||||
typename AnyCache,
|
||||
typename UnderlyingIterator,
|
||||
typename = std::enable_if_t<
|
||||
std::is_same<std::decay_t<AnyCache>, std::decay_t<Cache>>::value>>
|
||||
BaseOrderedIterator(BaseUnorderedIterator<AnyCache, UnderlyingIterator>&&
|
||||
unordered_iterator) {
|
||||
// Atomicity
|
||||
_throw_if_at_invalid(unordered_iterator);
|
||||
_cache = std::move(unordered_iterator._cache);
|
||||
_entry = std::move(unordered_iterator._entry);
|
||||
_iterator = std::move(unordered_iterator._iterator->second.order);
|
||||
}
|
||||
|
||||
/// Copy constructor.
|
||||
BaseOrderedIterator(const BaseOrderedIterator& other) = default;
|
||||
|
||||
/// Move constructor.
|
||||
BaseOrderedIterator(BaseOrderedIterator&& other) = default;
|
||||
|
||||
/// Copy assignment operator.
|
||||
BaseOrderedIterator& operator=(const BaseOrderedIterator& other) = default;
|
||||
|
||||
/// Move assignment operator.
|
||||
BaseOrderedIterator& operator=(BaseOrderedIterator&& other) = default;
|
||||
|
||||
/// Destructor.
|
||||
virtual ~BaseOrderedIterator() = default;
|
||||
|
||||
/// Checks for equality between this iterator and another ordered iterator.
|
||||
///
|
||||
/// \param other The other ordered iterator.
|
||||
/// \returns True if both iterators point to the same entry, else false.
|
||||
bool operator==(const BaseOrderedIterator& other) const noexcept {
|
||||
return this->_iterator == other._iterator;
|
||||
}
|
||||
|
||||
/// Checks for inequality between this iterator another ordered iterator.
|
||||
///
|
||||
/// \param other The other ordered iterator.
|
||||
/// \returns True if the iterators point to different entries, else false.
|
||||
bool operator!=(const BaseOrderedIterator& other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/// Checks for inequality between this iterator and another unordered
|
||||
/// iterator.
|
||||
///
|
||||
/// \param other The other unordered iterator.
|
||||
/// \returns True if both iterators point to the end of the same cache, else
|
||||
/// the result of comparing with the unordered iterator, converted to an
|
||||
/// ordered iterator.
|
||||
template <typename AnyCache, typename AnyUnderlyingIterator>
|
||||
bool operator==(
|
||||
const BaseUnorderedIterator<AnyCache, AnyUnderlyingIterator>& other) const
|
||||
noexcept {
|
||||
if (this->_cache != other._cache) return false;
|
||||
|
||||
// The past-the-end iterators of the same cache should compare equal.
|
||||
// This is an exceptional guarantee we make. This is also the reason
|
||||
// why we can't rely on the conversion from unordered to ordered iterators
|
||||
// because construction of an ordered iterator from the past-the-end
|
||||
// unordered iterator will fail (with an InvalidIteratorConversion error)
|
||||
if (other == other._cache->unordered_end()) {
|
||||
return *this == this->_cache->ordered_end();
|
||||
}
|
||||
|
||||
// Will call the other overload
|
||||
return *this == static_cast<BaseOrderedIterator>(other);
|
||||
}
|
||||
|
||||
/// Checks for equality between an unordered iterator and an ordered iterator.
|
||||
///
|
||||
/// \param first The unordered iterator.
|
||||
/// \param second The ordered iterator.
|
||||
/// \returns True if both iterators point to the end of the same cache, else
|
||||
/// the result of comparing with the unordered iterator, converted to an
|
||||
/// ordered iterator.
|
||||
template <typename AnyCache, typename AnyUnderlyingIterator>
|
||||
friend bool operator==(
|
||||
const BaseUnorderedIterator<AnyCache, AnyUnderlyingIterator>& first,
|
||||
const BaseOrderedIterator& second) noexcept {
|
||||
return second == first;
|
||||
}
|
||||
|
||||
/// Checks for inequality between an unordered
|
||||
/// iterator and an ordered iterator.
|
||||
///
|
||||
/// \param first The ordered iterator.
|
||||
/// \param second The unordered iterator.
|
||||
/// \returns True if the iterators point to different entries, else false.
|
||||
template <typename AnyCache, typename AnyUnderlyingIterator>
|
||||
friend bool
|
||||
operator!=(const BaseOrderedIterator& first,
|
||||
const BaseUnorderedIterator<AnyCache, AnyUnderlyingIterator>&
|
||||
second) noexcept {
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
/// Checks for inequality between an unordered
|
||||
/// iterator and an ordered iterator.
|
||||
///
|
||||
/// \param first The unordered iterator.
|
||||
/// \param second The ordered iterator.
|
||||
/// \returns True if the iterators point to different entries, else false.
|
||||
template <typename AnyCache, typename AnyUnderlyingIterator>
|
||||
friend bool operator!=(
|
||||
const BaseUnorderedIterator<AnyCache, AnyUnderlyingIterator>& first,
|
||||
const BaseOrderedIterator& second) noexcept {
|
||||
return second != first;
|
||||
}
|
||||
|
||||
/// Increments the iterator to the next entry.
|
||||
///
|
||||
/// If the iterator already pointed to the end any number of increments
|
||||
/// before, behavior is undefined.
|
||||
///
|
||||
/// \returns The resulting iterator.
|
||||
BaseOrderedIterator& operator++() {
|
||||
++_iterator;
|
||||
_entry.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Increments the iterator and returns a copy of the previous one.
|
||||
///
|
||||
/// If the iterator already pointed to the end any number of increments
|
||||
/// before, behavior is undefined.
|
||||
///
|
||||
/// \returns A copy of the previous iterator.
|
||||
BaseOrderedIterator operator++(int) {
|
||||
auto previous = *this;
|
||||
++*this;
|
||||
return previous;
|
||||
}
|
||||
|
||||
/// Decrements the iterator to the previous entry.
|
||||
///
|
||||
/// \returns The resulting iterator.
|
||||
BaseOrderedIterator& operator--() {
|
||||
--_iterator;
|
||||
_entry.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Decrements the iterator and returns a copy of the previous entry.
|
||||
///
|
||||
/// \returns The previous iterator.
|
||||
BaseOrderedIterator operator--(int) {
|
||||
auto previous = *this;
|
||||
--*this;
|
||||
return previous;
|
||||
}
|
||||
|
||||
Entry& operator*() noexcept override {
|
||||
return _maybe_lookup();
|
||||
}
|
||||
|
||||
/// \returns A reference to the entry the iterator points to.
|
||||
/// \details If the iterator is invalid, behavior is undefined.
|
||||
Entry& entry() override {
|
||||
_cache->throw_if_invalid(*this);
|
||||
return _maybe_lookup();
|
||||
}
|
||||
|
||||
/// \returns A reference to the value the iterator points to.
|
||||
/// \details If the iterator is invalid, behavior is undefined.
|
||||
Value& value() override {
|
||||
return entry().value();
|
||||
}
|
||||
|
||||
/// \returns A reference to the key the iterator points to.
|
||||
/// \details If the iterator is invalid, behavior is undefined.
|
||||
const Key& key() override {
|
||||
// No lookup required
|
||||
_cache->throw_if_invalid(*this);
|
||||
return *_iterator;
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename, typename, typename>
|
||||
friend class BaseOrderedIterator;
|
||||
|
||||
/// Looks up the entry for a key if this was not done already.
|
||||
///
|
||||
/// \returns The entry, which was possibly newly looked up.
|
||||
Entry& _maybe_lookup() {
|
||||
if (!_entry.has_value()) {
|
||||
_lookup();
|
||||
}
|
||||
|
||||
return *_entry;
|
||||
}
|
||||
|
||||
/// Looks up the entry for a key and sets the internal entry member.
|
||||
void _lookup() {
|
||||
auto iterator = _cache->_map.find(*_iterator);
|
||||
_entry.emplace(iterator->first, iterator->second.value);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Throws an exception if the given unordered iterator is invalid.
|
||||
///
|
||||
/// \param unordered_iterator The iterator to check.
|
||||
/// \throws LRU::Error::InvalidIteratorConversion if the iterator is invalid.
|
||||
template <typename UnorderedIterator>
|
||||
void _throw_if_at_invalid(const UnorderedIterator& unordered_iterator) {
|
||||
// For atomicity of the copy assignment, we assign the cache pointer only
|
||||
// after this check in the copy/move constructor and use the iterator's
|
||||
// cache. If an exception is thrown, the state of the ordered iterator is
|
||||
// unchanged compared to before the assignment.
|
||||
if (unordered_iterator == unordered_iterator._cache->unordered_end()) {
|
||||
throw LRU::Error::InvalidIteratorConversion();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // BASE_ORDERED_ITERATOR_HPP
|
||||
216
src/3rdParty/lru-cache/include/lru/internal/base-unordered-iterator.hpp
vendored
Normal file
216
src/3rdParty/lru-cache/include/lru/internal/base-unordered-iterator.hpp
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef BASE_UNORDERED_ITERATOR_HPP
|
||||
#define BASE_UNORDERED_ITERATOR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include <lru/entry.hpp>
|
||||
#include <lru/internal/base-iterator.hpp>
|
||||
#include <lru/internal/definitions.hpp>
|
||||
#include <lru/internal/optional.hpp>
|
||||
#include <lru/iterator-tags.hpp>
|
||||
|
||||
|
||||
namespace LRU {
|
||||
|
||||
// Forward declaration.
|
||||
template <typename, typename, typename, typename, typename>
|
||||
class TimedCache;
|
||||
|
||||
namespace Internal {
|
||||
template <typename Cache, typename UnderlyingIterator>
|
||||
using BaseForBaseUnorderedIterator =
|
||||
BaseIterator<std::forward_iterator_tag,
|
||||
decltype(UnderlyingIterator()->first),
|
||||
decltype(UnderlyingIterator()->second.value),
|
||||
Cache,
|
||||
UnderlyingIterator>;
|
||||
|
||||
/// The base class for all const and non-const unordered iterators.
|
||||
///
|
||||
/// An unordered iterator is a wrapper around an `unordered_map` iterator with
|
||||
/// ForwardIterator category. As such, it is (nearly) as fast to access the pair
|
||||
/// as through the unordered iterator as through the map iterator directly.
|
||||
/// However, the order of keys is unspecified. For this reason, unordered
|
||||
/// iterators have the special property that they may be used to construct
|
||||
/// ordered iterators, after which the order of insertion is respected.
|
||||
///
|
||||
/// \tparam Cache The type of the cache instances of the iterator point into.
|
||||
/// \tparam UnderlyingIterator The underlying iterator class used to implement
|
||||
/// the iterator.
|
||||
template <typename Cache, typename UnderlyingIterator>
|
||||
class BaseUnorderedIterator
|
||||
: public BaseForBaseUnorderedIterator<Cache, UnderlyingIterator> {
|
||||
protected:
|
||||
using super = BaseForBaseUnorderedIterator<Cache, UnderlyingIterator>;
|
||||
using PRIVATE_BASE_ITERATOR_MEMBERS;
|
||||
// These are the key and value types the BaseIterator extracts
|
||||
using Key = typename super::KeyType;
|
||||
using Value = typename super::ValueType;
|
||||
|
||||
public:
|
||||
using Tag = LRU::Tag::UnorderedIterator;
|
||||
using PUBLIC_BASE_ITERATOR_MEMBERS;
|
||||
|
||||
/// Constructor.
|
||||
BaseUnorderedIterator() noexcept = default;
|
||||
|
||||
/// \copydoc BaseIterator::BaseIterator(Cache,UnderlyingIterator)
|
||||
explicit BaseUnorderedIterator(Cache& cache,
|
||||
const UnderlyingIterator& iterator) noexcept
|
||||
: super(cache, iterator) {
|
||||
}
|
||||
|
||||
/// Generalized copy constructor.
|
||||
///
|
||||
/// Useful mainly for non-const to const conversion.
|
||||
///
|
||||
/// \param other The iterator to copy from.
|
||||
template <typename AnyCache, typename AnyUnderlyingIterator>
|
||||
BaseUnorderedIterator(
|
||||
const BaseUnorderedIterator<AnyCache, AnyUnderlyingIterator>&
|
||||
other) noexcept
|
||||
: super(other) {
|
||||
}
|
||||
|
||||
/// Copy constructor.
|
||||
BaseUnorderedIterator(const BaseUnorderedIterator& other) noexcept = default;
|
||||
|
||||
/// Move constructor.
|
||||
BaseUnorderedIterator(BaseUnorderedIterator&& other) noexcept = default;
|
||||
|
||||
/// Copy assignment operator.
|
||||
BaseUnorderedIterator&
|
||||
operator=(const BaseUnorderedIterator& other) noexcept = default;
|
||||
|
||||
/// Move assignment operator.
|
||||
template <typename AnyCache, typename AnyUnderlyingIterator>
|
||||
BaseUnorderedIterator&
|
||||
operator=(BaseUnorderedIterator<AnyCache, AnyUnderlyingIterator>
|
||||
unordered_iterator) noexcept {
|
||||
swap(unordered_iterator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
virtual ~BaseUnorderedIterator() = default;
|
||||
|
||||
/// Compares this iterator for equality with another unordered iterator.
|
||||
///
|
||||
/// \param other Another unordered iterator.
|
||||
/// \returns True if both iterators point to the same entry, else false.
|
||||
template <typename AnyCache, typename AnyIterator>
|
||||
bool
|
||||
operator==(const BaseUnorderedIterator<AnyCache, AnyIterator>& other) const
|
||||
noexcept {
|
||||
return this->_iterator == other._iterator;
|
||||
}
|
||||
|
||||
/// Compares this iterator for inequality with another unordered iterator.
|
||||
///
|
||||
/// \param other Another unordered iterator.
|
||||
/// \returns True if the iterators point to different entries, else false.
|
||||
template <typename AnyCache, typename AnyIterator>
|
||||
bool
|
||||
operator!=(const BaseUnorderedIterator<AnyCache, AnyIterator>& other) const
|
||||
noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/// Increments the iterator to the next entry.
|
||||
///
|
||||
/// If the iterator already pointed to the end any number of increments
|
||||
/// before, behavior is undefined.
|
||||
///
|
||||
/// \returns The resulting iterator.
|
||||
BaseUnorderedIterator& operator++() {
|
||||
++_iterator;
|
||||
_entry.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Increments the iterator and returns a copy of the previous one.
|
||||
///
|
||||
/// If the iterator already pointed to the end any number of increments
|
||||
/// before, behavior is undefined.
|
||||
///
|
||||
/// \returns A copy of the previous iterator.
|
||||
BaseUnorderedIterator operator++(int) {
|
||||
auto previous = *this;
|
||||
++*this;
|
||||
return previous;
|
||||
}
|
||||
|
||||
/// \copydoc BaseIterator::operator*
|
||||
/// \details If the iterator is invalid, behavior is undefined. No exception
|
||||
/// handling is performed.
|
||||
Entry& operator*() noexcept override {
|
||||
if (!_entry.has_value()) {
|
||||
_entry.emplace(_iterator->first, _iterator->second.value);
|
||||
}
|
||||
|
||||
return *_entry;
|
||||
}
|
||||
|
||||
/// \returns A reference to the entry the iterator points to.
|
||||
/// \throws LRU::Error::InvalidIterator if the iterator is the end iterator.
|
||||
/// \throws LRU::Error::KeyExpired if the key pointed to by the iterator has
|
||||
/// expired.
|
||||
Entry& entry() override {
|
||||
if (!_entry.has_value()) {
|
||||
_entry.emplace(_iterator->first, _iterator->second.value);
|
||||
}
|
||||
|
||||
_cache->throw_if_invalid(*this);
|
||||
return *_entry;
|
||||
}
|
||||
|
||||
/// \returns A reference to the key the iterator points to.
|
||||
/// \throws LRU::Error::InvalidIterator if the iterator is the end iterator.
|
||||
/// \throws LRU::Error::KeyExpired if the key pointed to by the iterator has
|
||||
/// expired.
|
||||
const Key& key() override {
|
||||
return entry().key();
|
||||
}
|
||||
|
||||
/// \returns A reference to the value the iterator points to.
|
||||
/// \throws LRU::Error::InvalidIterator if the iterator is the end iterator.
|
||||
/// \throws LRU::Error::KeyExpired if the key pointed to by the iterator has
|
||||
/// expired.
|
||||
Value& value() override {
|
||||
return entry().value();
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename, typename, typename>
|
||||
friend class BaseOrderedIterator;
|
||||
|
||||
template <typename, typename, typename, typename, typename>
|
||||
friend class LRU::TimedCache;
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // BASE_UNORDERED_ITERATOR_HPP
|
||||
159
src/3rdParty/lru-cache/include/lru/internal/callback-manager.hpp
vendored
Normal file
159
src/3rdParty/lru-cache/include/lru/internal/callback-manager.hpp
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_CALLBACK_MANAGER_HPP
|
||||
#define LRU_INTERNAL_CALLBACK_MANAGER_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <lru/entry.hpp>
|
||||
#include <lru/internal/optional.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// Manages hit, miss and access callbacks for a cache.
|
||||
///
|
||||
/// The callback manager implements the "publisher" of the observer pattern we
|
||||
/// implement. It stores and calls three kinds of callbacks:
|
||||
/// 1. Hit callbacks, taking a key and value after a cache hit.
|
||||
/// 2. Miss callbacks, taking only a key, that was not found in a cache.
|
||||
/// 3. Access callbacks, taking a key and a boolean indicating a hit or a miss.
|
||||
///
|
||||
/// Callbacks can be added, accessed and cleared.
|
||||
template <typename Key, typename Value>
|
||||
class CallbackManager {
|
||||
public:
|
||||
using HitCallback = std::function<void(const Key&, const Value&)>;
|
||||
using MissCallback = std::function<void(const Key&)>;
|
||||
using AccessCallback = std::function<void(const Key&, bool)>;
|
||||
|
||||
using HitCallbackContainer = std::vector<HitCallback>;
|
||||
using MissCallbackContainer = std::vector<MissCallback>;
|
||||
using AccessCallbackContainer = std::vector<AccessCallback>;
|
||||
|
||||
/// Calls all callbacks registered for a hit, with the given key and value.
|
||||
///
|
||||
/// \param key The key for which a cache hit ocurred.
|
||||
/// \param value The value that was found for the key.
|
||||
void hit(const Key& key, const Value& value) {
|
||||
_call_each(_hit_callbacks, key, value);
|
||||
_call_each(_access_callbacks, key, true);
|
||||
}
|
||||
|
||||
/// Calls all callbacks registered for a miss, with the given key.
|
||||
///
|
||||
/// \param key The key for which a cache miss ocurred.
|
||||
void miss(const Key& key) {
|
||||
_call_each(_miss_callbacks, key);
|
||||
_call_each(_access_callbacks, key, false);
|
||||
}
|
||||
|
||||
/// Registers a new hit callback.
|
||||
///
|
||||
/// \param hit_callback The hit callback function to register with the
|
||||
/// manager.
|
||||
template <typename Callback>
|
||||
void hit_callback(Callback&& hit_callback) {
|
||||
_hit_callbacks.emplace_back(std::forward<Callback>(hit_callback));
|
||||
}
|
||||
|
||||
/// Registers a new miss callback.
|
||||
///
|
||||
/// \param miss_callback The miss callback function to register with the
|
||||
/// manager.
|
||||
template <typename Callback>
|
||||
void miss_callback(Callback&& miss_callback) {
|
||||
_miss_callbacks.emplace_back(std::forward<Callback>(miss_callback));
|
||||
}
|
||||
|
||||
/// Registers a new access callback.
|
||||
///
|
||||
/// \param access_callback The access callback function to register with the
|
||||
/// manager.
|
||||
template <typename Callback>
|
||||
void access_callback(Callback&& access_callback) {
|
||||
_access_callbacks.emplace_back(std::forward<Callback>(access_callback));
|
||||
}
|
||||
|
||||
/// Clears all hit callbacks.
|
||||
void clear_hit_callbacks() {
|
||||
_hit_callbacks.clear();
|
||||
}
|
||||
|
||||
/// Clears all miss callbacks.
|
||||
void clear_miss_callbacks() {
|
||||
_miss_callbacks.clear();
|
||||
}
|
||||
|
||||
/// Clears all access callbacks.
|
||||
void clear_access_callbacks() {
|
||||
_access_callbacks.clear();
|
||||
}
|
||||
|
||||
/// Clears all callbacks.
|
||||
void clear() {
|
||||
clear_hit_callbacks();
|
||||
clear_miss_callbacks();
|
||||
clear_access_callbacks();
|
||||
}
|
||||
|
||||
/// \returns All hit callbacks.
|
||||
const HitCallbackContainer& hit_callbacks() const noexcept {
|
||||
return _hit_callbacks;
|
||||
}
|
||||
|
||||
/// \returns All miss callbacks.
|
||||
const MissCallbackContainer& miss_callbacks() const noexcept {
|
||||
return _miss_callbacks;
|
||||
}
|
||||
|
||||
/// \returns All access callbacks.
|
||||
const AccessCallbackContainer& access_callbacks() const noexcept {
|
||||
return _access_callbacks;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Calls each function in the given container with the given arguments.
|
||||
///
|
||||
/// \param callbacks The container of callbacks to call.
|
||||
/// \param args The arguments to call the callbacks with.
|
||||
template <typename CallbackContainer, typename... Args>
|
||||
void _call_each(const CallbackContainer& callbacks, Args&&... args) {
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/// The container of hit callbacks registered.
|
||||
HitCallbackContainer _hit_callbacks;
|
||||
|
||||
/// The container of miss callbacks registered.
|
||||
MissCallbackContainer _miss_callbacks;
|
||||
|
||||
/// The container of access callbacks registered.
|
||||
AccessCallbackContainer _access_callbacks;
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_INTERNAL_CALLBACK_MANAGER_HPP
|
||||
88
src/3rdParty/lru-cache/include/lru/internal/definitions.hpp
vendored
Normal file
88
src/3rdParty/lru-cache/include/lru/internal/definitions.hpp
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_DEFINITIONS_HPP
|
||||
#define LRU_INTERNAL_DEFINITIONS_HPP
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// The default capacity for all caches.
|
||||
const std::size_t DEFAULT_CAPACITY = 128;
|
||||
|
||||
/// The reference type use to store keys in the order queue.
|
||||
template <typename T>
|
||||
using Reference = std::reference_wrapper<T>;
|
||||
|
||||
/// Compares two References for equality.
|
||||
///
|
||||
/// This is necessary because `std::reference_wrapper` does not define any
|
||||
/// operator overloads. We do need them, however (e.g. for container
|
||||
/// comparison).
|
||||
///
|
||||
/// \param first The first reference to compare.
|
||||
/// \param second The second reference to compare.
|
||||
template <typename T, typename U>
|
||||
bool operator==(const Reference<T>& first, const Reference<U>& second) {
|
||||
return first.get() == second.get();
|
||||
}
|
||||
|
||||
/// Compares two References for inequality.
|
||||
///
|
||||
/// This is necessary because `std::reference_wrapper` does not define any
|
||||
/// operator overloads. We do need them, however (e.g. for container
|
||||
/// comparison).
|
||||
///
|
||||
/// \param first The first reference to compare.
|
||||
/// \param second The second reference to compare.
|
||||
template <typename T, typename U>
|
||||
bool operator!=(const Reference<T>& first, const Reference<U>& second) {
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
/// The default queue type used internally.
|
||||
template <typename T>
|
||||
using Queue = std::list<Reference<T>>;
|
||||
|
||||
/// The default map type used internally.
|
||||
template <typename Key,
|
||||
typename Information,
|
||||
typename HashFunction,
|
||||
typename KeyEqual>
|
||||
using Map = std::unordered_map<Key, Information, HashFunction, KeyEqual>;
|
||||
|
||||
/// The default clock used internally.
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
/// The default timestamp (time point) used internally.
|
||||
using Timestamp = Clock::time_point;
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
|
||||
#endif // LRU_INTERNAL_DEFINITIONS_HPP
|
||||
62
src/3rdParty/lru-cache/include/lru/internal/hash.hpp
vendored
Normal file
62
src/3rdParty/lru-cache/include/lru/internal/hash.hpp
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_HASH_HPP
|
||||
#define LRU_INTERNAL_HASH_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
/// `std::hash` specialization to allow storing tuples as keys
|
||||
/// in `std::unordered_map`.
|
||||
///
|
||||
/// Essentially hashes all tuple elements and jumbles the
|
||||
/// individual hashes together.
|
||||
namespace std {
|
||||
template <typename... Ts>
|
||||
struct hash<std::tuple<Ts...>> {
|
||||
using argument_type = std::tuple<Ts...>;
|
||||
using result_type = std::size_t;
|
||||
|
||||
result_type operator()(const argument_type& argument) const {
|
||||
return hash_tuple(argument, std::make_index_sequence<sizeof...(Ts)>());
|
||||
}
|
||||
|
||||
private:
|
||||
template <std::size_t I, std::size_t... Is>
|
||||
result_type
|
||||
hash_tuple(const argument_type& tuple, std::index_sequence<I, Is...>) const {
|
||||
auto value = std::get<I>(tuple);
|
||||
auto current = std::hash<decltype(value)>{}(value);
|
||||
auto seed = hash_tuple(tuple, std::index_sequence<Is...>());
|
||||
|
||||
// http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
|
||||
return current + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
result_type hash_tuple(const argument_type&, std::index_sequence<>) const {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
#endif // LRU_INTERNAL_HASH_HPP
|
||||
145
src/3rdParty/lru-cache/include/lru/internal/information.hpp
vendored
Normal file
145
src/3rdParty/lru-cache/include/lru/internal/information.hpp
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_INFORMATION_HPP
|
||||
#define LRU_INTERNAL_INFORMATION_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <lru/internal/definitions.hpp>
|
||||
#include <lru/internal/utility.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// The value type of internal maps, used to store a value and iterator.
|
||||
///
|
||||
/// This information object is the basis of an LRU cache, which must associated
|
||||
/// a value and such an order iterator with a key, such that the iterator may be
|
||||
/// moved to the front of the order when the key is updated with a new value.
|
||||
///
|
||||
/// \tparam Key The key type of the information.
|
||||
/// \tparam Value The value type of the information.
|
||||
template <typename Key, typename Value>
|
||||
struct Information {
|
||||
using KeyType = Key;
|
||||
using ValueType = Value;
|
||||
using QueueIterator = typename Internal::Queue<const Key>::const_iterator;
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param value_ The value for the information.
|
||||
/// \param order_ The order iterator for the information.
|
||||
explicit Information(const Value& value_,
|
||||
QueueIterator order_ = QueueIterator())
|
||||
: value(value_), order(order_) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param order_ The order iterator for the information.
|
||||
/// \param value_arguments Any number of arguments to perfectly forward to the
|
||||
/// value type's constructor.
|
||||
// template <typename... ValueArguments>
|
||||
// Information(QueueIterator order_, ValueArguments&&... value_arguments)
|
||||
// : value(std::forward<ValueArguments>(value_arguments)...), order(order_) {
|
||||
// }
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param order_ The order iterator for the information.
|
||||
/// \param value_arguments A tuple of arguments to perfectly forward to the
|
||||
/// value type's constructor.
|
||||
///
|
||||
template <typename... ValueArguments>
|
||||
explicit Information(const std::tuple<ValueArguments...>& value_arguments,
|
||||
QueueIterator order_ = QueueIterator())
|
||||
: Information(
|
||||
order_, value_arguments, Internal::tuple_indices(value_arguments)) {
|
||||
}
|
||||
|
||||
/// Copy constructor.
|
||||
Information(const Information& other) = default;
|
||||
|
||||
/// Move constructor.
|
||||
Information(Information&& other) = default;
|
||||
|
||||
/// Copy assignment operator.
|
||||
Information& operator=(const Information& other) = default;
|
||||
|
||||
/// Move assignment operator.
|
||||
Information& operator=(Information&& other) = default;
|
||||
|
||||
/// Destructor.
|
||||
virtual ~Information() = default;
|
||||
|
||||
/// Compares the information for equality with another information object.
|
||||
///
|
||||
/// \param other The other information object to compare to.
|
||||
/// \returns True if key and value (not the iterator itself) of the two
|
||||
/// information objects are equal, else false.
|
||||
virtual bool operator==(const Information& other) const noexcept {
|
||||
if (this == &other) return true;
|
||||
if (this->value != other.value) return false;
|
||||
// We do not compare the iterator (because otherwise two containers
|
||||
// holding information would never be equal). We also do not compare
|
||||
// the key stored in the iterator, because keys will always have been
|
||||
// compared before this operator is called.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Compares the information for inequality with another information object.
|
||||
///
|
||||
/// \param other The other information object to compare for.
|
||||
/// \returns True if key and value (not the iterator itself) of the two
|
||||
/// information objects are unequal, else false.
|
||||
virtual bool operator!=(const Information& other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/// The value of the information.
|
||||
Value value;
|
||||
|
||||
/// The order iterator of the information.
|
||||
QueueIterator order;
|
||||
|
||||
private:
|
||||
/// Implementation for the constructor taking a tuple of arguments for the
|
||||
/// value.
|
||||
///
|
||||
/// \param order_ The order iterator for the information.
|
||||
/// \param value_argument The tuple of arguments to perfectly forward to the
|
||||
/// value type's constructor.
|
||||
/// \param _ An index sequence to access the elements of the tuple
|
||||
template <typename... ValueArguments, std::size_t... Indices>
|
||||
Information(const QueueIterator& order_,
|
||||
const std::tuple<ValueArguments...>& value_argument,
|
||||
std::index_sequence<Indices...> _)
|
||||
: value(std::forward<ValueArguments>(std::get<Indices>(value_argument))...)
|
||||
, order(order_) {
|
||||
}
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_INTERNAL_INFORMATION_HPP
|
||||
254
src/3rdParty/lru-cache/include/lru/internal/last-accessed.hpp
vendored
Normal file
254
src/3rdParty/lru-cache/include/lru/internal/last-accessed.hpp
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_LAST_ACCESSED_HPP
|
||||
#define LRU_INTERNAL_LAST_ACCESSED_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
||||
#include <lru/internal/utility.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// Provides a simple iterator-compatible pointer object for a key and
|
||||
/// information.
|
||||
///
|
||||
/// The easisest idea for this class, theoretically, would be to just store an s
|
||||
/// iterator to the internal cache map (i.e. template the class on the iterator
|
||||
/// type). However, the major trouble with that approach is that this class
|
||||
/// should be 100% *mutable*, as in "always non-const", so that keys and
|
||||
/// informations
|
||||
/// we store for fast access can be (quickly) retrieved as either const or
|
||||
/// non-const (iterators for example). This is not possible, since the
|
||||
/// const-ness of `const_iterators` are not the usual idea of const in C++,
|
||||
/// meaning especially it cannot be cast away with a `const_cast` as is required
|
||||
/// for the mutability. As such, we *must* store the plain keys and
|
||||
/// informations.
|
||||
/// This, however, means that iterators cannot be stored efficiently, since a
|
||||
/// new hash table lookup would be required to go from a key to its iterator.
|
||||
/// However, since the main use case of this class is to avoid a second lookup
|
||||
/// in the usual `if (cache.contains(key)) return cache.lookup(key)`, which is
|
||||
/// not an issue for iterators since they can be compared to the `end` iterator
|
||||
/// in constant time (equivalent to the call to `contains()`).
|
||||
///
|
||||
/// WARNING: This class stores *pointers* to keys and informations. As such
|
||||
/// lifetime
|
||||
/// of the pointed-to objects must be cared for by the user of this class.
|
||||
///
|
||||
/// \tparam Key The type of key being accessed.
|
||||
/// \tparam InformationType The type of information being accessed.
|
||||
/// \tparam KeyEqual The type of the key comparison function.
|
||||
template <typename Key,
|
||||
typename InformationType,
|
||||
typename KeyEqual = std::equal_to<Key>>
|
||||
class LastAccessed {
|
||||
public:
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param key_equal The function to compare keys with.
|
||||
explicit LastAccessed(const KeyEqual& key_equal = KeyEqual())
|
||||
: _key(nullptr)
|
||||
, _information(nullptr)
|
||||
, _is_valid(false)
|
||||
, _key_equal(key_equal) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param key The key to store a reference to.
|
||||
/// \param information The information to store a reference to.
|
||||
/// \param key_equal The function to compare keys with.
|
||||
LastAccessed(const Key& key,
|
||||
const InformationType& information,
|
||||
const KeyEqual& key_equal = KeyEqual())
|
||||
: _key(const_cast<Key*>(&key))
|
||||
, _information(const_cast<InformationType*>(&information))
|
||||
, _is_valid(true)
|
||||
, _key_equal(key_equal) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param iterator An iterator pointing to a key and information to use for
|
||||
/// constructing the instance.
|
||||
/// \param key_equal The function to compare keys with.
|
||||
template <typename Iterator>
|
||||
explicit LastAccessed(Iterator iterator,
|
||||
const KeyEqual& key_equal = KeyEqual())
|
||||
: LastAccessed(iterator->first, iterator->second, key_equal) {
|
||||
}
|
||||
|
||||
/// Copy assignment operator for iterators.
|
||||
///
|
||||
/// \param iterator An iterator pointing to a key and value to use for the
|
||||
/// `LastAccessed` instance.
|
||||
/// \return The resulting `LastAccessed` instance.
|
||||
template <typename Iterator>
|
||||
LastAccessed& operator=(Iterator iterator) {
|
||||
_key = const_cast<Key*>(&(iterator->first));
|
||||
_information = const_cast<InformationType*>(&(iterator->second));
|
||||
_is_valid = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Compares a `LastAccessed` object for equality with a key.
|
||||
///
|
||||
/// \param last_accessed The `LastAccessed` instance to compare.
|
||||
/// \param key The key instance to compare.
|
||||
/// \returns True if the key of the `LastAccessed` object's key equals the
|
||||
/// given key, else false.
|
||||
friend bool
|
||||
operator==(const LastAccessed& last_accessed, const Key& key) noexcept {
|
||||
if (!last_accessed._is_valid) return false;
|
||||
return last_accessed._key_equal(key, last_accessed.key());
|
||||
}
|
||||
|
||||
/// \copydoc operator==(const LastAccessed&,const Key&)
|
||||
friend bool
|
||||
operator==(const Key& key, const LastAccessed& last_accessed) noexcept {
|
||||
return last_accessed == key;
|
||||
}
|
||||
|
||||
/// Compares a `LastAccessed` object for equality with an iterator.
|
||||
///
|
||||
/// \param last_accessed The `LastAccessed` instance to compare.
|
||||
/// \param iterator The iterator to compare with.
|
||||
/// \returns True if the `LastAccessed` object's key equals that of the
|
||||
/// iterator, else false.
|
||||
template <typename Iterator, typename = enable_if_iterator<Iterator>>
|
||||
friend bool
|
||||
operator==(const LastAccessed& last_accessed, Iterator iterator) noexcept {
|
||||
/// Fast comparisons to an iterator (not relying on implicit conversion)
|
||||
return last_accessed == iterator->first;
|
||||
}
|
||||
|
||||
/// \copydoc operator==(const LastAccessed&,Iterator)
|
||||
template <typename Iterator, typename = enable_if_iterator<Iterator>>
|
||||
friend bool
|
||||
operator==(Iterator iterator, const LastAccessed& last_accessed) noexcept {
|
||||
return last_accessed == iterator;
|
||||
}
|
||||
|
||||
/// Compares a `LastAccessed` object for inequality with something.
|
||||
///
|
||||
/// \param last_accessed The `LastAccessed` instance to compare.
|
||||
/// \param other Something else to compare to.
|
||||
/// \returns True if the key of the `LastAccessed` object's key does not equal
|
||||
/// the given other object's key, else false.
|
||||
template <typename T>
|
||||
friend bool
|
||||
operator!=(const LastAccessed& last_accessed, const T& other) noexcept {
|
||||
return !(last_accessed == other);
|
||||
}
|
||||
|
||||
/// \copydoc operator!=(const LastAccessed&,const T&)
|
||||
template <typename T>
|
||||
friend bool
|
||||
operator!=(const T& other, const LastAccessed& last_accessed) noexcept {
|
||||
return !(other == last_accessed);
|
||||
}
|
||||
|
||||
/// \returns The last accessed key.
|
||||
Key& key() noexcept {
|
||||
assert(is_valid());
|
||||
return *_key;
|
||||
}
|
||||
|
||||
/// \returns The last accessed key.
|
||||
const Key& key() const noexcept {
|
||||
assert(is_valid());
|
||||
return *_key;
|
||||
}
|
||||
|
||||
/// \returns The last accessed information.
|
||||
InformationType& information() noexcept {
|
||||
assert(is_valid());
|
||||
return *_information;
|
||||
}
|
||||
|
||||
/// \returns The last accessed information.
|
||||
const InformationType& information() const noexcept {
|
||||
assert(is_valid());
|
||||
return *_information;
|
||||
}
|
||||
|
||||
/// \returns The last accessed information.
|
||||
auto& iterator() noexcept {
|
||||
assert(is_valid());
|
||||
return _information->order;
|
||||
}
|
||||
|
||||
/// \returns The last accessed value.
|
||||
auto& value() noexcept {
|
||||
assert(is_valid());
|
||||
return _information->value;
|
||||
}
|
||||
|
||||
/// \returns The last accessed value.
|
||||
const auto& value() const noexcept {
|
||||
assert(is_valid());
|
||||
return _information->value;
|
||||
}
|
||||
|
||||
/// \returns True if the key and information of the instance may be accessed,
|
||||
/// else false.
|
||||
bool is_valid() const noexcept {
|
||||
return _is_valid;
|
||||
}
|
||||
|
||||
/// \copydoc is_valid()
|
||||
explicit operator bool() const noexcept {
|
||||
return is_valid();
|
||||
}
|
||||
|
||||
/// Invalidates the instance.
|
||||
void invalidate() noexcept {
|
||||
_is_valid = false;
|
||||
_key = nullptr;
|
||||
_information = nullptr;
|
||||
}
|
||||
|
||||
/// \returns The key comparison function used.
|
||||
const KeyEqual& key_equal() const noexcept {
|
||||
return _key_equal;
|
||||
}
|
||||
|
||||
private:
|
||||
/// A pointer to the key that was last accessed (if any).
|
||||
Key* _key;
|
||||
|
||||
/// A pointer to the information that was last accessed (if any).
|
||||
InformationType* _information;
|
||||
|
||||
/// True if the key and information pointers are valid, else false.
|
||||
bool _is_valid;
|
||||
|
||||
/// The function used to compare keys.
|
||||
KeyEqual _key_equal;
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_INTERNAL_LAST_ACCESSED_HPP
|
||||
207
src/3rdParty/lru-cache/include/lru/internal/optional.hpp
vendored
Normal file
207
src/3rdParty/lru-cache/include/lru/internal/optional.hpp
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_OPTIONAL_HPP
|
||||
#define LRU_INTERNAL_OPTIONAL_HPP
|
||||
|
||||
#ifndef __has_include
|
||||
#define USE_LRU_OPTIONAL
|
||||
#elif __has_include(<optional>)
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
template <typename T>
|
||||
using Optional = std::optional<T>;
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#else
|
||||
#define USE_LRU_OPTIONAL
|
||||
#endif
|
||||
|
||||
#ifdef USE_LRU_OPTIONAL
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
// A roll-your-own replacement of `std::optional`.
|
||||
//
|
||||
// This class is only to be used if `std::optional` is unavailable. It
|
||||
// implements an optional type simply on top of a `unique_ptr`. It is
|
||||
// API-compatible with `std::optional`, as required for our purposes.
|
||||
template <typename T>
|
||||
class Optional {
|
||||
public:
|
||||
/// Constructor.
|
||||
Optional() = default;
|
||||
|
||||
/// Copy constructor.
|
||||
///
|
||||
/// \param other The other optional object to copy from.
|
||||
Optional(const Optional& other) {
|
||||
if (other) emplace(*other);
|
||||
}
|
||||
|
||||
/// Generalized copy constructor.
|
||||
///
|
||||
/// \param other The other optional object to copy from.
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_convertible<T, U>::value>>
|
||||
Optional(const Optional<U>& other) {
|
||||
if (other) emplace(*other);
|
||||
}
|
||||
|
||||
/// Move constructor.
|
||||
///
|
||||
/// \param other The other optional object to move into this one.
|
||||
Optional(Optional&& other) noexcept {
|
||||
swap(other);
|
||||
}
|
||||
|
||||
/// Generalized move constructor.
|
||||
///
|
||||
/// \param other The other optional object to move into this one.
|
||||
template <typename U,
|
||||
typename = std::enable_if_t<std::is_convertible<T, U>::value>>
|
||||
Optional(Optional<U>&& other) noexcept {
|
||||
if (other) {
|
||||
_value = std::make_unique<T>(std::move(*other));
|
||||
}
|
||||
}
|
||||
|
||||
/// Assignment operator.
|
||||
///
|
||||
/// \param other The other object to assign from.
|
||||
/// \returns The resulting optional instance.
|
||||
Optional& operator=(Optional other) noexcept {
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Swaps the contents of this optional with another one.
|
||||
///
|
||||
/// \param other The other optional to swap with.
|
||||
void swap(Optional& other) {
|
||||
_value.swap(other._value);
|
||||
}
|
||||
|
||||
/// Swaps the contents of two optionals.
|
||||
///
|
||||
/// \param first The first optional to swap.
|
||||
/// \param second The second optional to swap.
|
||||
friend void swap(Optional& first, Optional& second) /* NOLINT */ {
|
||||
first.swap(second);
|
||||
}
|
||||
|
||||
/// \returns True if the `Optional` has a value, else false.
|
||||
bool has_value() const noexcept {
|
||||
return static_cast<bool>(_value);
|
||||
}
|
||||
|
||||
/// \copydoc has_value()
|
||||
explicit operator bool() const noexcept {
|
||||
return has_value();
|
||||
}
|
||||
|
||||
/// \returns A pointer to the current value. Behavior is undefined if the
|
||||
/// optional has no value.
|
||||
T* operator->() {
|
||||
return _value.get();
|
||||
}
|
||||
|
||||
/// \returns A const pointer to the current value. Behavior is undefined if
|
||||
/// the `Optional` has no value.
|
||||
const T* operator->() const {
|
||||
return _value.get();
|
||||
}
|
||||
|
||||
/// \returns A const reference to the current value. Behavior is undefined if
|
||||
/// the `Optional` has no value.
|
||||
const T& operator*() const {
|
||||
return *_value;
|
||||
}
|
||||
|
||||
/// \returns A reference to the current value. Behavior is undefined if
|
||||
/// the `Optional` has no value.
|
||||
T& operator*() {
|
||||
return *_value;
|
||||
}
|
||||
|
||||
/// \returns A reference to the current value.
|
||||
/// \throws std::runtime_error If the `Optional` currently has no value.
|
||||
T& value() {
|
||||
if (!has_value()) {
|
||||
// Actually std::bad_optional_access
|
||||
throw std::runtime_error("optional has no value");
|
||||
}
|
||||
|
||||
return *_value;
|
||||
}
|
||||
|
||||
/// \returns A const reference to the current value.
|
||||
/// \throws std::runtime_error If the `Optional` currently has no value.
|
||||
const T& value() const {
|
||||
if (!has_value()) {
|
||||
// Actually std::bad_optional_access
|
||||
throw std::runtime_error("optional has no value");
|
||||
}
|
||||
|
||||
return *_value;
|
||||
}
|
||||
|
||||
/// \returns The current value, or the given argument if there is no value.
|
||||
/// \param default_value The value to return if this `Optional` currently has
|
||||
/// no value.
|
||||
template <class U>
|
||||
T value_or(U&& default_value) const {
|
||||
return *this ? **this : static_cast<T>(std::forward<U>(default_value));
|
||||
}
|
||||
|
||||
/// Resets the `Optional` to have no value.
|
||||
void reset() noexcept {
|
||||
_value.reset();
|
||||
}
|
||||
|
||||
/// Constructs the `Optional`'s value with the given arguments.
|
||||
///
|
||||
/// \param args Arguments to perfeclty forward to the value's constructor.
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
_value = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename>
|
||||
friend class Optional;
|
||||
|
||||
/// The value, as we implement it.
|
||||
std::unique_ptr<T> _value;
|
||||
};
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif
|
||||
|
||||
#endif // LRU_INTERNAL_OPTIONAL_HPP
|
||||
150
src/3rdParty/lru-cache/include/lru/internal/statistics-mutator.hpp
vendored
Normal file
150
src/3rdParty/lru-cache/include/lru/internal/statistics-mutator.hpp
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_STATISTICS_MUTATOR_HPP
|
||||
#define LRU_STATISTICS_MUTATOR_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <lru/internal/optional.hpp>
|
||||
#include <lru/statistics.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// A mutable proxy interface to a statistics object.
|
||||
///
|
||||
/// The `StatisticsMutator` allows modification of the members of a statistics
|
||||
/// object via a narrow interface, available only to internal classes. The point
|
||||
/// of this is that while we don't want the user to be able to modify the hit or
|
||||
/// miss count on a statistics object (it is "getter-only" in that sense), it's
|
||||
/// also not ideal, from an encapsulation standpoint, to make the cache classes
|
||||
/// (which do need to access and modify the hit and miss counts) friends of the
|
||||
/// statistics. This is especially true since the caches should only need to
|
||||
/// register hits or misses and not have to increment the count of total
|
||||
/// accesses. As such, we really require a "package-level" interface that is not
|
||||
/// visible to the end user, while at the same time providing an interface to
|
||||
/// internal classes. The `StatisticsMutator` is a proxy/adapter class that
|
||||
/// serves exactly this purpose. It is friends with the `Statistics` and can
|
||||
/// thus access its members. At the same time the interface it defines is narrow
|
||||
/// and provides only the necessary interface for the cache classes to register
|
||||
/// hits and misses.
|
||||
template <typename Key>
|
||||
class StatisticsMutator {
|
||||
public:
|
||||
using StatisticsPointer = std::shared_ptr<Statistics<Key>>;
|
||||
|
||||
/// Constructor.
|
||||
StatisticsMutator() noexcept = default;
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param stats A shared pointer lvalue reference.
|
||||
StatisticsMutator(const StatisticsPointer& stats) // NOLINT(runtime/explicit)
|
||||
: _stats(stats) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param stats A shared pointer rvalue reference to move into the
|
||||
/// mutator.
|
||||
StatisticsMutator(StatisticsPointer&& stats) // NOLINT(runtime/explicit)
|
||||
: _stats(std::move(stats)) {
|
||||
}
|
||||
|
||||
/// Registers a hit for the given key with the internal statistics.
|
||||
///
|
||||
/// \param key The key to register a hit for.
|
||||
void register_hit(const Key& key) {
|
||||
assert(has_stats());
|
||||
|
||||
_stats->_total_accesses += 1;
|
||||
_stats->_total_hits += 1;
|
||||
|
||||
auto iterator = _stats->_key_map.find(key);
|
||||
if (iterator != _stats->_key_map.end()) {
|
||||
iterator->second.hits += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a miss for the given key with the internal statistics.
|
||||
///
|
||||
/// \param key The key to register a miss for.
|
||||
void register_miss(const Key& key) {
|
||||
assert(has_stats());
|
||||
|
||||
_stats->_total_accesses += 1;
|
||||
|
||||
auto iterator = _stats->_key_map.find(key);
|
||||
if (iterator != _stats->_key_map.end()) {
|
||||
iterator->second.misses += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns A reference to the statistics object.
|
||||
Statistics<Key>& get() noexcept {
|
||||
assert(has_stats());
|
||||
return *_stats;
|
||||
}
|
||||
|
||||
/// \returns A const reference to the statistics object.
|
||||
const Statistics<Key>& get() const noexcept {
|
||||
assert(has_stats());
|
||||
return *_stats;
|
||||
}
|
||||
|
||||
/// \returns A `shared_ptr` to the statistics object.
|
||||
StatisticsPointer& shared() noexcept {
|
||||
return _stats;
|
||||
}
|
||||
|
||||
/// \returns A const `shared_ptr` to the statistics object.
|
||||
const StatisticsPointer& shared() const noexcept {
|
||||
return _stats;
|
||||
}
|
||||
|
||||
/// \returns True if the mutator has a statistics object, else false.
|
||||
bool has_stats() const noexcept {
|
||||
return _stats != nullptr;
|
||||
}
|
||||
|
||||
/// \copydoc has_stats()
|
||||
explicit operator bool() const noexcept {
|
||||
return has_stats();
|
||||
}
|
||||
|
||||
/// Resets the internal statistics pointer.
|
||||
void reset() {
|
||||
_stats.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
/// A shared pointer to a statistics object.
|
||||
std::shared_ptr<Statistics<Key>> _stats;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_STATISTICS_MUTATOR_HPP
|
||||
116
src/3rdParty/lru-cache/include/lru/internal/timed-information.hpp
vendored
Normal file
116
src/3rdParty/lru-cache/include/lru/internal/timed-information.hpp
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_INTERNAL_TIMED_INFORMATION_HPP
|
||||
#define LRU_INTERNAL_TIMED_INFORMATION_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include <lru/internal/definitions.hpp>
|
||||
#include <lru/internal/information.hpp>
|
||||
#include <lru/internal/utility.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// The information object for timed caches.
|
||||
///
|
||||
/// TimedInformation differs from plain information only in that it stores the
|
||||
/// creation time, to know when a key has expired.
|
||||
///
|
||||
/// \tparam Key The key type of the information.
|
||||
/// \tparam Value The value type of the information.
|
||||
template <typename Key, typename Value>
|
||||
struct TimedInformation : public Information<Key, Value> {
|
||||
using super = Information<Key, Value>;
|
||||
using typename super::QueueIterator;
|
||||
using Timestamp = Internal::Timestamp;
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param value_ The value for the information.
|
||||
/// \param insertion_time_ The insertion timestamp of the key.
|
||||
/// \param order_ The order iterator for the information.
|
||||
TimedInformation(const Value& value_,
|
||||
const Timestamp& insertion_time_,
|
||||
QueueIterator order_ = QueueIterator())
|
||||
: super(value_, order_), insertion_time(insertion_time_) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// Uses the current time as the insertion timestamp.
|
||||
///
|
||||
/// \param value_ The value for the information.
|
||||
/// \param order_ The order iterator for the information.
|
||||
explicit TimedInformation(const Value& value_,
|
||||
QueueIterator order_ = QueueIterator())
|
||||
: TimedInformation(value_, Internal::Clock::now(), order_) {
|
||||
}
|
||||
|
||||
/// \copydoc Information::Information(QueueIterator,ValueArguments&&)
|
||||
template <typename... ValueArguments>
|
||||
TimedInformation(QueueIterator order_, ValueArguments&&... value_argument)
|
||||
: super(std::forward<ValueArguments>(value_argument)..., order_)
|
||||
, insertion_time(Internal::Clock::now()) {
|
||||
}
|
||||
|
||||
/// \copydoc Information::Information(QueueIterator,const
|
||||
/// std::tuple<ValueArguments...>&)
|
||||
template <typename... ValueArguments>
|
||||
explicit TimedInformation(
|
||||
const std::tuple<ValueArguments...>& value_arguments,
|
||||
QueueIterator order_ = QueueIterator())
|
||||
: super(value_arguments, order_), insertion_time(Internal::Clock::now()) {
|
||||
}
|
||||
|
||||
/// Compares this timed information for equality with another one.
|
||||
///
|
||||
/// Additionally to key and value equality, the timed information requires
|
||||
/// that the insertion timestamps be equal.
|
||||
///
|
||||
/// \param other The other timed information.
|
||||
/// \returns True if this information equals the other one, else false.
|
||||
bool operator==(const TimedInformation& other) const noexcept {
|
||||
if (super::operator!=(other)) return false;
|
||||
return this->insertion_time == other.insertion_time;
|
||||
}
|
||||
|
||||
/// Compares this timed information for inequality with another one.
|
||||
///
|
||||
/// \param other The other timed information.
|
||||
/// \returns True if this information does not equal the other one, else
|
||||
/// false.
|
||||
/// \see operator==()
|
||||
bool operator!=(const TimedInformation& other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/// The time at which the key of the information was insterted into a cache.
|
||||
const Timestamp insertion_time;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_INTERNAL_TIMED_INFORMATION_HPP
|
||||
178
src/3rdParty/lru-cache/include/lru/internal/utility.hpp
vendored
Normal file
178
src/3rdParty/lru-cache/include/lru/internal/utility.hpp
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_UTILITY_HPP
|
||||
#define LRU_UTILITY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
|
||||
/// Generates an index sequence for a tuple.
|
||||
///
|
||||
/// \tparam Ts The types of the tuple (to deduce the size).
|
||||
template <typename... Ts>
|
||||
constexpr auto tuple_indices(const std::tuple<Ts...>&) {
|
||||
return std::make_index_sequence<sizeof...(Ts)>();
|
||||
}
|
||||
|
||||
/// Applies (in the functional sense) a tuple to the constructor of a class.
|
||||
///
|
||||
/// \tparam T The type to construct.
|
||||
/// \tparam Indices The indices into the tuple (generated from an index
|
||||
/// sequence).
|
||||
/// \param args The tuple of arguments to construct the object with.
|
||||
template <typename T, typename... Args, std::size_t... Indices>
|
||||
constexpr T construct_from_tuple(const std::tuple<Args...>& arguments,
|
||||
std::index_sequence<Indices...>) {
|
||||
return T(std::forward<Args>(std::get<Indices>(arguments))...);
|
||||
}
|
||||
|
||||
/// Applies (in the functional sense) a tuple to the constructor of a class.
|
||||
///
|
||||
/// \tparam T The type to construct.
|
||||
/// \param args The tuple of arguments to construct the object with.
|
||||
template <typename T, typename... Args>
|
||||
constexpr T construct_from_tuple(const std::tuple<Args...>& args) {
|
||||
return construct_from_tuple<T>(args, tuple_indices(args));
|
||||
}
|
||||
|
||||
/// Applies (in the functional sense) a tuple to the constructor of a class.
|
||||
///
|
||||
/// \tparam T The type to construct.
|
||||
/// \param args The tuple of arguments to construct the object with.
|
||||
template <typename T, typename... Args>
|
||||
constexpr T construct_from_tuple(std::tuple<Args...>&& args) {
|
||||
return construct_from_tuple<T>(std::move(args), tuple_indices(args));
|
||||
}
|
||||
|
||||
/// A type trait that disables a template overload if a type is not an iterator.
|
||||
///
|
||||
/// \tparam T the type to check.
|
||||
template <typename T>
|
||||
using enable_if_iterator = typename std::iterator_traits<T>::value_type;
|
||||
|
||||
/// A type trait that disables a template overload if a type is not a range.
|
||||
///
|
||||
/// \tparam T the type to check.
|
||||
template <typename T>
|
||||
using enable_if_range = std::pair<decltype(std::declval<T>().begin()),
|
||||
decltype(std::declval<T>().end())>;
|
||||
|
||||
/// A type trait that disables a template overload if a type is not an iterator
|
||||
/// over a pair.
|
||||
///
|
||||
/// \tparam T the type to check.
|
||||
template <typename T>
|
||||
using enable_if_iterator_over_pair =
|
||||
std::pair<typename std::iterator_traits<T>::value_type::first_type,
|
||||
typename std::iterator_traits<T>::value_type::first_type>;
|
||||
|
||||
|
||||
/// A type trait that disables a template overload if a type is not convertible
|
||||
/// to a target type.
|
||||
///
|
||||
/// \tparam Target The type one wants to check against.
|
||||
/// \tparam T The type to check.
|
||||
template <typename Target, typename T>
|
||||
using enable_if_same = std::enable_if_t<std::is_convertible<T, Target>::value>;
|
||||
|
||||
/// Base case for `static_all_of` (the neutral element of AND is true).
|
||||
constexpr bool static_all_of() noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Checks if all the given parameters evaluate to true.
|
||||
///
|
||||
/// \param head The first expression to check.
|
||||
/// \param tail The remaining expression to check.
|
||||
template <typename Head, typename... Tail>
|
||||
constexpr bool static_all_of(Head&& head, Tail&&... tail) {
|
||||
// Replace with (ts && ...) when the time is right
|
||||
return std::forward<Head>(head) && static_all_of(std::forward<Tail>(tail)...);
|
||||
}
|
||||
|
||||
/// Base case for `static_any_of` (the neutral element of OR is false).
|
||||
constexpr bool static_any_of() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Checks if any the given parameters evaluate to true.
|
||||
///
|
||||
/// \param head The first expression to check.
|
||||
/// \param tail The remaining expression to check.
|
||||
/// \returns True if any of the given parameters evaluate to true.
|
||||
template <typename Head, typename... Tail>
|
||||
constexpr bool static_any_of(Head&& head, Tail&&... tail) {
|
||||
// Replace with (ts || ...) when the time is right
|
||||
return std::forward<Head>(head) || static_any_of(std::forward<Tail>(tail)...);
|
||||
}
|
||||
|
||||
/// Checks if none the given parameters evaluate to true.
|
||||
///
|
||||
/// \param ts The expressions to check.
|
||||
/// \returns True if any of the given parameters evaluate to true.
|
||||
template <typename... Ts>
|
||||
constexpr bool static_none_of(Ts&&... ts) {
|
||||
// Replace with (!ts && ...) when the time is right
|
||||
return !static_any_of(std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
/// Checks if all the given types are convertible to the first type.
|
||||
///
|
||||
/// \tparam T the first type.
|
||||
/// \tparam Ts The types to check against the first.
|
||||
template <typename T, typename... Ts>
|
||||
constexpr bool
|
||||
all_of_type = static_all_of(std::is_convertible<Ts, T>::value...);
|
||||
|
||||
/// Checks if none of the given types are convertible to the first type.
|
||||
///
|
||||
/// \tparam T the first type.
|
||||
/// \tparam Ts The types to check against the first.
|
||||
template <typename T, typename... Ts>
|
||||
constexpr bool
|
||||
none_of_type = static_none_of(std::is_convertible<Ts, T>::value...);
|
||||
|
||||
/// Base case for `for_each`.
|
||||
template <typename Function>
|
||||
void for_each(Function) noexcept {
|
||||
}
|
||||
|
||||
/// Calls a function for each of the given variadic arguments.
|
||||
///
|
||||
/// \param function The function to call for each argument.
|
||||
/// \param head The first value to call the function with.
|
||||
/// \param tail The remaining values to call the function with.
|
||||
template <typename Function, typename Head, typename... Tail>
|
||||
void for_each(Function function, Head&& head, Tail&&... tail) {
|
||||
function(std::forward<Head>(head));
|
||||
for_each(function, std::forward<Tail>(tail)...);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_UTILITY_HPP
|
||||
40
src/3rdParty/lru-cache/include/lru/iterator-tags.hpp
vendored
Normal file
40
src/3rdParty/lru-cache/include/lru/iterator-tags.hpp
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_ITERATOR_TAGS_HPP
|
||||
#define LRU_ITERATOR_TAGS_HPP
|
||||
|
||||
namespace LRU {
|
||||
namespace Tag {
|
||||
struct OrderedIterator {};
|
||||
struct UnorderedIterator {};
|
||||
} // namespace Tag
|
||||
|
||||
namespace Lowercase {
|
||||
namespace tag {
|
||||
using ordered_iterator = ::LRU::Tag::OrderedIterator;
|
||||
using unordered_iterator = ::LRU::Tag::UnorderedIterator;
|
||||
} // namespace tag
|
||||
} // namespace Lowercase
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_ITERATOR_TAGS_HPP
|
||||
67
src/3rdParty/lru-cache/include/lru/key-statistics.hpp
vendored
Normal file
67
src/3rdParty/lru-cache/include/lru/key-statistics.hpp
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
|
||||
#ifndef LRU_KEY_STATISTICS_HPP
|
||||
#define LRU_KEY_STATISTICS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace LRU {
|
||||
|
||||
/// Stores statistics for a single key.
|
||||
///
|
||||
/// The statistics stored are the total number of hits and the total number of
|
||||
/// misses. The total number of acccesses (the sum of hits and misses) may be
|
||||
/// accessed as well.
|
||||
struct KeyStatistics {
|
||||
using size_t = std::size_t;
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param hits_ The initial number of hits for the key.
|
||||
/// \param misses_ The initial number of misses for the key.
|
||||
explicit KeyStatistics(size_t hits_ = 0, size_t misses_ = 0)
|
||||
: hits(hits_), misses(misses_) {
|
||||
}
|
||||
|
||||
/// \returns The total number of accesses made for the key.
|
||||
/// \details This is the sum of the hits and misses.
|
||||
size_t accesses() const noexcept {
|
||||
return hits + misses;
|
||||
}
|
||||
|
||||
/// Resets the statistics for a key (sets them to zero).
|
||||
void reset() {
|
||||
hits = 0;
|
||||
misses = 0;
|
||||
}
|
||||
|
||||
/// The number of hits for the key.
|
||||
size_t hits;
|
||||
|
||||
/// The number of misses for the key.
|
||||
size_t misses;
|
||||
};
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_KEY_STATISTICS_HPP
|
||||
34
src/3rdParty/lru-cache/include/lru/lowercase.hpp
vendored
Normal file
34
src/3rdParty/lru-cache/include/lru/lowercase.hpp
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_LOWERCASE_HPP
|
||||
#define LRU_LOWERCASE_HPP
|
||||
|
||||
#include <lru/lru.hpp>
|
||||
|
||||
namespace LRU {
|
||||
using namespace Lowercase; // NOLINT(build/namespaces)
|
||||
} // namespace LRU
|
||||
|
||||
namespace lru = LRU;
|
||||
|
||||
|
||||
#endif // LRU_LOWERCASE_HPP
|
||||
33
src/3rdParty/lru-cache/include/lru/lru.hpp
vendored
Normal file
33
src/3rdParty/lru-cache/include/lru/lru.hpp
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_HPP
|
||||
#define LRU_HPP
|
||||
|
||||
#include <lru/cache-tags.hpp>
|
||||
#include <lru/cache.hpp>
|
||||
#include <lru/error.hpp>
|
||||
#include <lru/iterator-tags.hpp>
|
||||
#include <lru/statistics.hpp>
|
||||
#include <lru/timed-cache.hpp>
|
||||
#include <lru/wrap.hpp>
|
||||
|
||||
#endif // LRU_HPP
|
||||
256
src/3rdParty/lru-cache/include/lru/statistics.hpp
vendored
Normal file
256
src/3rdParty/lru-cache/include/lru/statistics.hpp
vendored
Normal file
@@ -0,0 +1,256 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
|
||||
#ifndef LRU_STATISTICS_HPP
|
||||
#define LRU_STATISTICS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <lru/error.hpp>
|
||||
#include <lru/internal/utility.hpp>
|
||||
#include <lru/key-statistics.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
template <typename>
|
||||
class StatisticsMutator;
|
||||
}
|
||||
|
||||
/// Stores statistics about LRU cache utilization and efficiency.
|
||||
///
|
||||
/// The statistics object stores the number of misses and hits were recorded for
|
||||
/// a cache in total. Furthemore, it is possibly to register a number of keys
|
||||
/// for *monitoring*. For each of these keys, an additional hit and miss count
|
||||
/// is maintained, that can keep insight into the utiliization of a particular
|
||||
/// cache. Note that accesses only mean lookups -- insertions or erasures will
|
||||
/// never signify an "access".
|
||||
///
|
||||
/// \tparam Key The type of the keys being monitored.
|
||||
template <typename Key>
|
||||
class Statistics {
|
||||
public:
|
||||
using size_t = std::size_t;
|
||||
using InitializerList = std::initializer_list<Key>;
|
||||
|
||||
/// Constructor.
|
||||
Statistics() noexcept : _total_accesses(0), _total_hits(0) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param keys Any number of keys to monitor.
|
||||
template <typename... Keys,
|
||||
typename = std::enable_if_t<Internal::all_of_type<Key, Keys...>>>
|
||||
explicit Statistics(Keys&&... keys) : Statistics() {
|
||||
// clang-format off
|
||||
Internal::for_each([this](auto&& key) {
|
||||
this->monitor(std::forward<decltype(key)>(key));
|
||||
}, std::forward<Keys>(keys)...);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param range A range of keys to monitor.
|
||||
template <typename Range, typename = Internal::enable_if_range<Range>>
|
||||
explicit Statistics(const Range& range)
|
||||
: Statistics(std::begin(range), std::end(range)) {
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param begin The start iterator of a range of keys to monitor.
|
||||
/// \param end The end iterator of a range of keys to monitor.
|
||||
template <typename Iterator,
|
||||
typename = Internal::enable_if_iterator<Iterator>>
|
||||
Statistics(Iterator begin, Iterator end) : Statistics() {
|
||||
for (; begin != end; ++begin) {
|
||||
monitor(*begin);
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructor.
|
||||
///
|
||||
/// \param list A list of keys to monitor.
|
||||
Statistics(InitializerList list) // NOLINT(runtime/explicit)
|
||||
: Statistics(list.begin(), list.end()) {
|
||||
}
|
||||
|
||||
/// \returns The total number of accesses (hits + misses) made to the cache.
|
||||
size_t total_accesses() const noexcept {
|
||||
return _total_accesses;
|
||||
}
|
||||
|
||||
/// \returns The total number of hits made to the cache.
|
||||
size_t total_hits() const noexcept {
|
||||
return _total_hits;
|
||||
}
|
||||
|
||||
/// \returns The total number of misses made to the cache.
|
||||
size_t total_misses() const noexcept {
|
||||
return total_accesses() - total_hits();
|
||||
}
|
||||
|
||||
/// \returns The ratio of hits ($\in [0, 1]$) relative to all accesses.
|
||||
double hit_rate() const noexcept {
|
||||
return static_cast<double>(total_hits()) / total_accesses();
|
||||
}
|
||||
|
||||
/// \returns The ratio of misses ($\in [0, 1]$) relative to all accesses.
|
||||
double miss_rate() const noexcept {
|
||||
return 1 - hit_rate();
|
||||
}
|
||||
|
||||
/// \returns The number of hits for the given key.
|
||||
/// \param key The key to retrieve the hits for.
|
||||
/// \throws LRU::UnmonitoredKey if the key was not registered for monitoring.
|
||||
size_t hits_for(const Key& key) const {
|
||||
return stats_for(key).hits;
|
||||
}
|
||||
|
||||
/// \returns The number of misses for the given key.
|
||||
/// \param key The key to retrieve the misses for.
|
||||
/// \throws LRU::UnmonitoredKey if the key was not registered for monitoring.
|
||||
size_t misses_for(const Key& key) const {
|
||||
return stats_for(key).misses;
|
||||
}
|
||||
|
||||
/// \returns The number of accesses (hits + misses) for the given key.
|
||||
/// \param key The key to retrieve the accesses for.
|
||||
/// \throws LRU::UnmonitoredKey if the key was not registered for monitoring.
|
||||
size_t accesses_for(const Key& key) const {
|
||||
return stats_for(key).accesses();
|
||||
}
|
||||
|
||||
/// \returns A `KeyStatistics` object for the given key.
|
||||
/// \param key The key to retrieve the stats for.
|
||||
/// \throws LRU::UnmonitoredKey if the key was not registered for monitoring.
|
||||
const KeyStatistics& stats_for(const Key& key) const {
|
||||
auto iterator = _key_map.find(key);
|
||||
if (iterator == _key_map.end()) {
|
||||
throw LRU::Error::UnmonitoredKey();
|
||||
}
|
||||
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
/// \copydoc stats_for()
|
||||
const KeyStatistics& operator[](const Key& key) const {
|
||||
return stats_for(key);
|
||||
}
|
||||
|
||||
/// Registers the key for monitoring.
|
||||
///
|
||||
/// If the key was already registered, this is a no-op (most importantly, the
|
||||
/// old statistics are __not__ wiped).
|
||||
///
|
||||
/// \param key The key to register.
|
||||
void monitor(const Key& key) {
|
||||
// emplace does nothing if the key is already present
|
||||
_key_map.emplace(key, KeyStatistics());
|
||||
}
|
||||
|
||||
/// Unregisters the given key from monitoring.
|
||||
///
|
||||
/// \param key The key to unregister.
|
||||
/// \throws LRU::Error::UnmonitoredKey if the key was never registered for
|
||||
/// monitoring.
|
||||
void unmonitor(const Key& key) {
|
||||
auto iterator = _key_map.find(key);
|
||||
if (iterator == _key_map.end()) {
|
||||
throw LRU::Error::UnmonitoredKey();
|
||||
} else {
|
||||
_key_map.erase(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
/// Unregisters all keys from monitoring.
|
||||
void unmonitor_all() {
|
||||
_key_map.clear();
|
||||
}
|
||||
|
||||
/// Clears all statistics for the given key, but keeps on monitoring it.
|
||||
///
|
||||
/// \param key The key to reset.
|
||||
void reset_key(const Key& key) {
|
||||
auto iterator = _key_map.find(key);
|
||||
if (iterator == _key_map.end()) {
|
||||
throw LRU::Error::UnmonitoredKey();
|
||||
} else {
|
||||
iterator->second.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the statistics of all keys, but keeps on monitoring it them.
|
||||
void reset_all() {
|
||||
for (auto& pair : _key_map) {
|
||||
_key_map.second.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns True if the given key is currently registered for monitoring,
|
||||
/// else false.
|
||||
/// \param key The key to check for.
|
||||
bool is_monitoring(const Key& key) const noexcept {
|
||||
return _key_map.count(key);
|
||||
}
|
||||
|
||||
/// \returns The number of keys currnetly being monitored.
|
||||
size_t number_of_monitored_keys() const noexcept {
|
||||
return _key_map.size();
|
||||
}
|
||||
|
||||
/// \returns True if currently any keys at all are being monitored, else
|
||||
/// false.
|
||||
bool is_monitoring_keys() const noexcept {
|
||||
return !_key_map.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename>
|
||||
friend class Internal::StatisticsMutator;
|
||||
|
||||
using HitMap = std::unordered_map<Key, KeyStatistics>;
|
||||
|
||||
/// The total number of accesses made for any key.
|
||||
size_t _total_accesses;
|
||||
|
||||
/// The total number of htis made for any key.
|
||||
size_t _total_hits;
|
||||
|
||||
/// The map to keep track of statistics for monitored keys.
|
||||
HitMap _key_map;
|
||||
};
|
||||
|
||||
namespace Lowercase {
|
||||
template <typename... Ts>
|
||||
using statistics = Statistics<Ts...>;
|
||||
} // namespace Lowercase
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_STATISTICS_HPP
|
||||
391
src/3rdParty/lru-cache/include/lru/timed-cache.hpp
vendored
Normal file
391
src/3rdParty/lru-cache/include/lru/timed-cache.hpp
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_TIMED_CACHE_HPP
|
||||
#define LRU_TIMED_CACHE_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <lru/error.hpp>
|
||||
#include <lru/internal/base-cache.hpp>
|
||||
#include <lru/internal/last-accessed.hpp>
|
||||
#include <lru/internal/timed-information.hpp>
|
||||
|
||||
namespace LRU {
|
||||
namespace Internal {
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename HashFunction,
|
||||
typename KeyEqual>
|
||||
using TimedCacheBase = BaseCache<Key,
|
||||
Value,
|
||||
Internal::TimedInformation,
|
||||
HashFunction,
|
||||
KeyEqual,
|
||||
Tag::TimedCache>;
|
||||
} // namespace Internal
|
||||
|
||||
|
||||
/// A timed LRU cache.
|
||||
///
|
||||
/// A timed LRU cache behaves like a regular LRU cache, but adds the concept of
|
||||
/// "expiration". The cache now not only remembers the order of insertion, but
|
||||
/// also the point in time at which each element was inserted into the cache.
|
||||
/// The cache then has an additional "time to live" property, which designates
|
||||
/// the time after which a key in the cache is said to be "expired". Once a key
|
||||
/// has expired, the cache will behave as if the key were not present in the
|
||||
/// cache at all and, for example, return false on calls to `contains()` or
|
||||
/// throw on calls to `lookup()`.
|
||||
///
|
||||
/// \see LRU::Cache
|
||||
template <typename Key,
|
||||
typename Value,
|
||||
typename Duration = std::chrono::duration<double, std::milli>,
|
||||
typename HashFunction = std::hash<Key>,
|
||||
typename KeyEqual = std::equal_to<Key>>
|
||||
class TimedCache
|
||||
: public Internal::TimedCacheBase<Key, Value, HashFunction, KeyEqual> {
|
||||
private:
|
||||
using super = Internal::TimedCacheBase<Key, Value, HashFunction, KeyEqual>;
|
||||
using PRIVATE_BASE_CACHE_MEMBERS;
|
||||
|
||||
public:
|
||||
using Tag = LRU::Tag::TimedCache;
|
||||
using PUBLIC_BASE_CACHE_MEMBERS;
|
||||
using super::ordered_end;
|
||||
using super::unordered_end;
|
||||
using typename super::size_t;
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(size_t,const HashFunction&,const KeyEqual&)
|
||||
template <typename AnyDurationType = Duration>
|
||||
explicit TimedCache(const AnyDurationType& time_to_live,
|
||||
size_t capacity = Internal::DEFAULT_CAPACITY,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(capacity, hash, equal)
|
||||
, _time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(size_t,Iterator,Iterator,const
|
||||
/// HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename Iterator, typename AnyDurationType = Duration>
|
||||
TimedCache(const AnyDurationType& time_to_live,
|
||||
size_t capacity,
|
||||
Iterator begin,
|
||||
Iterator end,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(capacity, begin, end, hash, equal)
|
||||
, _time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(Iterator,Iterator,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename Iterator, typename AnyDurationType = Duration>
|
||||
TimedCache(const AnyDurationType& time_to_live,
|
||||
Iterator begin,
|
||||
Iterator end,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(begin, end, hash, equal)
|
||||
, _time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(Range,size_t,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename Range,
|
||||
typename AnyDurationType = Duration,
|
||||
typename = Internal::enable_if_range<Range>>
|
||||
TimedCache(const AnyDurationType& time_to_live,
|
||||
size_t capacity,
|
||||
Range&& range,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(capacity, std::forward<Range>(range), hash, equal)
|
||||
, _time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(Range,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename Range,
|
||||
typename AnyDurationType = Duration,
|
||||
typename = Internal::enable_if_range<Range>>
|
||||
explicit TimedCache(const AnyDurationType& time_to_live,
|
||||
Range&& range,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual())
|
||||
: super(std::forward<Range>(range), hash, equal)
|
||||
, _time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(InitializerList,const HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename AnyDurationType = Duration>
|
||||
TimedCache(const AnyDurationType& time_to_live,
|
||||
InitializerList list,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual()) // NOLINT(runtime/explicit)
|
||||
: super(list, hash, equal),
|
||||
_time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \param time_to_live The time to live for keys in the cache.
|
||||
/// \copydoc BaseCache::BaseCache(InitializerList,size_t,const
|
||||
/// HashFunction&,const
|
||||
/// KeyEqual&)
|
||||
template <typename AnyDurationType = Duration>
|
||||
TimedCache(const AnyDurationType& time_to_live,
|
||||
size_t capacity,
|
||||
InitializerList list,
|
||||
const HashFunction& hash = HashFunction(),
|
||||
const KeyEqual& equal = KeyEqual()) // NOLINT(runtime/explicit)
|
||||
: super(capacity, list, hash, equal),
|
||||
_time_to_live(std::chrono::duration_cast<Duration>(time_to_live)) {
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::swap
|
||||
void swap(TimedCache& other) noexcept {
|
||||
using std::swap;
|
||||
|
||||
super::swap(other);
|
||||
swap(_time_to_live, other._time_to_live);
|
||||
}
|
||||
|
||||
/// Swaps the contents of one cache with another cache.
|
||||
///
|
||||
/// \param first The first cache to swap.
|
||||
/// \param second The second cache to swap.
|
||||
friend void swap(TimedCache& first, TimedCache& second) noexcept {
|
||||
first.swap(second);
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::find(const Key&)
|
||||
UnorderedIterator find(const Key& key) override {
|
||||
auto iterator = _map.find(key);
|
||||
if (iterator != _map.end()) {
|
||||
if (!_has_expired(iterator->second)) {
|
||||
_register_hit(key, iterator->second.value);
|
||||
_move_to_front(iterator->second.order);
|
||||
_last_accessed = iterator;
|
||||
return {*this, iterator};
|
||||
}
|
||||
}
|
||||
|
||||
_register_miss(key);
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::find(const Key&) const
|
||||
UnorderedConstIterator find(const Key& key) const override {
|
||||
auto iterator = _map.find(key);
|
||||
if (iterator != _map.end()) {
|
||||
if (!_has_expired(iterator->second)) {
|
||||
_register_hit(key, iterator->second.value);
|
||||
_move_to_front(iterator->second.order);
|
||||
_last_accessed = iterator;
|
||||
return {*this, iterator};
|
||||
}
|
||||
}
|
||||
|
||||
_register_miss(key);
|
||||
|
||||
return cend();
|
||||
}
|
||||
|
||||
// no front() because we may have to erase the
|
||||
// entire cache if everything happens to be expired
|
||||
|
||||
/// \returns True if all keys in the cache have expired, else false.
|
||||
bool all_expired() const {
|
||||
// By the laws of predicate logic, any statement about any empty set is true
|
||||
if (is_empty()) return true;
|
||||
|
||||
/// If the most-recently inserted key has expired, all others must have too.
|
||||
auto latest = _map.find(_order.back());
|
||||
return _has_expired(latest->second);
|
||||
}
|
||||
|
||||
/// Erases all expired elements from the cache.
|
||||
///
|
||||
/// \complexity O(N)
|
||||
/// \returns The number of elements erased.
|
||||
size_t clear_expired() {
|
||||
// We have to do a linear search here because linked lists do not
|
||||
// support O(log N) binary searches given their node-based nature.
|
||||
// Either way, in the worst case the entire cache has expired and
|
||||
// we would have to do O(N) erasures.
|
||||
|
||||
if (is_empty()) return 0;
|
||||
|
||||
auto iterator = _order.begin();
|
||||
size_t number_of_erasures = 0;
|
||||
|
||||
while (iterator != _order.end()) {
|
||||
auto map_iterator = _map.find(*iterator);
|
||||
|
||||
// If the current element hasn't expired, also all elements inserted
|
||||
// after will not have, so we can stop.
|
||||
if (!_has_expired(map_iterator->second)) break;
|
||||
|
||||
_erase(map_iterator);
|
||||
|
||||
iterator = _order.begin();
|
||||
number_of_erasures += 1;
|
||||
}
|
||||
|
||||
return number_of_erasures;
|
||||
}
|
||||
|
||||
/// \returns True if the given key is contained in the cache and has expired.
|
||||
/// \param key The key to test expiration for.
|
||||
bool has_expired(const Key& key) const noexcept {
|
||||
auto iterator = _map.find(key);
|
||||
return iterator != _map.end() && _has_expired(iterator->second);
|
||||
}
|
||||
|
||||
/// \returns True if the key pointed to by the iterator has expired.
|
||||
/// \param ordered_iterator The ordered iterator to check.
|
||||
/// \details If this is the end iterator, this method returns false.
|
||||
bool has_expired(OrderedConstIterator ordered_iterator) const noexcept {
|
||||
if (ordered_iterator == ordered_end()) return false;
|
||||
auto iterator = _map.find(ordered_iterator->key());
|
||||
assert(iterator != _map.end());
|
||||
|
||||
return _has_expired(iterator->second);
|
||||
}
|
||||
|
||||
/// \returns True if the key pointed to by the iterator has expired.
|
||||
/// \param unordered_iterator The unordered iterator to check.
|
||||
/// \details If this is the end iterator, this method returns false.
|
||||
bool has_expired(UnorderedConstIterator unordered_iterator) const noexcept {
|
||||
if (unordered_iterator == unordered_end()) return false;
|
||||
assert(unordered_iterator._iterator != _map.end());
|
||||
|
||||
return _has_expired(unordered_iterator._iterator->second);
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::is_valid(UnorderedConstIterator)
|
||||
bool is_valid(UnorderedConstIterator unordered_iterator) const
|
||||
noexcept override {
|
||||
if (!super::is_valid(unordered_iterator)) return false;
|
||||
if (has_expired(unordered_iterator)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::is_valid(OrderedConstIterator)
|
||||
bool is_valid(OrderedConstIterator ordered_iterator) const noexcept override {
|
||||
if (!super::is_valid(ordered_iterator)) return false;
|
||||
if (has_expired(ordered_iterator)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::is_valid(UnorderedConstIterator)
|
||||
/// \throws LRU::Error::KeyExpired if the key pointed to by the iterator has
|
||||
/// expired.
|
||||
void
|
||||
throw_if_invalid(UnorderedConstIterator unordered_iterator) const override {
|
||||
super::throw_if_invalid(unordered_iterator);
|
||||
if (has_expired(unordered_iterator)) {
|
||||
throw LRU::Error::KeyExpired();
|
||||
}
|
||||
}
|
||||
|
||||
/// \copydoc BaseCache::is_valid(OrderedConstIterator)
|
||||
/// \throws LRU::Error::KeyExpired if the key pointed to by the iterator has
|
||||
/// expired.
|
||||
void throw_if_invalid(OrderedConstIterator ordered_iterator) const override {
|
||||
super::throw_if_invalid(ordered_iterator);
|
||||
if (has_expired(ordered_iterator)) {
|
||||
throw LRU::Error::KeyExpired();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
using Clock = Internal::Clock;
|
||||
|
||||
/// \returns True if the last accessed object is valid.
|
||||
/// \details Next to performing the base cache's action, this method also
|
||||
/// checks for expiration of the last accessed key.
|
||||
bool _last_accessed_is_ok(const Key& key) const noexcept override {
|
||||
if (!super::_last_accessed_is_ok(key)) return false;
|
||||
return !_has_expired(_last_accessed.information());
|
||||
}
|
||||
|
||||
/// \copydoc _value_for_last_accessed() const
|
||||
Value& _value_for_last_accessed() override {
|
||||
auto& information = _last_accessed.information();
|
||||
if (_has_expired(information)) {
|
||||
throw LRU::Error::KeyExpired();
|
||||
} else {
|
||||
return information.value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to access the last accessed key's value.
|
||||
/// \throws LRU::Error::KeyExpired if the key has expired.
|
||||
/// \returns The value of the last accessed key.
|
||||
const Value& _value_for_last_accessed() const override {
|
||||
const auto& information = _last_accessed.information();
|
||||
if (_has_expired(information)) {
|
||||
throw LRU::Error::KeyExpired();
|
||||
} else {
|
||||
return information.value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a key has expired, given its information.
|
||||
///
|
||||
/// \param information The information to check expiration with.
|
||||
/// \returns True if the key has expired, else false.
|
||||
bool _has_expired(const Information& information) const noexcept {
|
||||
auto elapsed = Clock::now() - information.insertion_time;
|
||||
return std::chrono::duration_cast<Duration>(elapsed) > _time_to_live;
|
||||
}
|
||||
|
||||
/// The duration after which a key is said to be expired.
|
||||
Duration _time_to_live;
|
||||
};
|
||||
|
||||
namespace Lowercase {
|
||||
template <typename... Ts>
|
||||
using timed_cache = TimedCache<Ts...>;
|
||||
} // namespace Lowercase
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_TIMED_CACHE_HPP
|
||||
99
src/3rdParty/lru-cache/include/lru/wrap.hpp
vendored
Normal file
99
src/3rdParty/lru-cache/include/lru/wrap.hpp
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#ifndef LRU_WRAP_HPP
|
||||
#define LRU_WRAP_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <lru/cache.hpp>
|
||||
#include <lru/internal/hash.hpp>
|
||||
#include <lru/internal/utility.hpp>
|
||||
|
||||
namespace LRU {
|
||||
|
||||
/// Wraps a function with a "shallow" LRU cache.
|
||||
///
|
||||
/// Given a function, this function will return a new function, where
|
||||
/// "top-level" calls are cached. With "top-level" or "shallow", we mean
|
||||
/// that recursive calls to the same function are not cached, since those
|
||||
/// will call the original function symbol, not the wrapped one.
|
||||
///
|
||||
/// \tparam CacheType The cache template class to use.
|
||||
/// \param original_function The function to wrap.
|
||||
/// \param args Any arguments to forward to the cache.
|
||||
/// \returns A new function with a shallow LRU cache.
|
||||
template <typename Function,
|
||||
template <typename...> class CacheType = Cache,
|
||||
typename... Args>
|
||||
auto wrap(Function original_function, Args&&... args) {
|
||||
return [
|
||||
original_function,
|
||||
cache_args = std::forward_as_tuple(std::forward<Args>(args)...)
|
||||
](auto&&... arguments) mutable {
|
||||
using Arguments = std::tuple<std::decay_t<decltype(arguments)>...>;
|
||||
using ReturnType = decltype(
|
||||
original_function(std::forward<decltype(arguments)>(arguments)...));
|
||||
|
||||
static_assert(!std::is_void<ReturnType>::value,
|
||||
"Return type of wrapped function must not be void");
|
||||
|
||||
static auto cache =
|
||||
Internal::construct_from_tuple<CacheType<Arguments, ReturnType>>(
|
||||
cache_args);
|
||||
|
||||
auto key = std::make_tuple(arguments...);
|
||||
auto iterator = cache.find(key);
|
||||
|
||||
if (iterator != cache.end()) {
|
||||
return iterator->second;
|
||||
}
|
||||
|
||||
auto value =
|
||||
original_function(std::forward<decltype(arguments)>(arguments)...);
|
||||
cache.emplace(key, value);
|
||||
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
/// Wraps a function with a "shallow" LRU timed cache.
|
||||
///
|
||||
/// Given a function, this function will return a new function, where
|
||||
/// "top-level" calls are cached. With "top-level" or "shallow", we mean
|
||||
/// that recursive calls to the same function are not cached, since those
|
||||
/// will call the original function symbol, not the wrapped one.
|
||||
///
|
||||
/// \param original_function The function to wrap.
|
||||
/// \param args Any arguments to forward to the cache.
|
||||
/// \returns A new function with a shallow LRU cache.
|
||||
template <typename Function, typename Duration, typename... Args>
|
||||
auto timed_wrap(Function original_function, Duration duration, Args&&... args) {
|
||||
return wrap<Function, TimedCache>(
|
||||
original_function, duration, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace LRU
|
||||
|
||||
#endif // LRU_WRAP_HPP
|
||||
56
src/3rdParty/lru-cache/tests/CMakeLists.txt
vendored
Normal file
56
src/3rdParty/lru-cache/tests/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
########################################
|
||||
# CONFIG
|
||||
########################################
|
||||
|
||||
add_compile_options(-g -Werror -DDEBUG)
|
||||
|
||||
########################################
|
||||
# DEPENDENCIES
|
||||
########################################
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/googletest)
|
||||
|
||||
set(GTEST_INCLUDE_DIRS
|
||||
${gtest_SOURCE_DIR}/include
|
||||
${gtest_SOURCE_DIR})
|
||||
|
||||
########################################
|
||||
# INCLUDES
|
||||
########################################
|
||||
|
||||
include_directories(${GTEST_INCLUDE_DIRS})
|
||||
|
||||
########################################
|
||||
# SOURCES
|
||||
########################################
|
||||
|
||||
set(TEST_LRU_CACHE_SOURCES
|
||||
move-awareness-test.cpp
|
||||
last-accessed-test.cpp
|
||||
iterator-test.cpp
|
||||
cache-test.cpp
|
||||
timed-cache-test.cpp
|
||||
statistics-test.cpp
|
||||
wrap-test.cpp
|
||||
callback-test.cpp
|
||||
)
|
||||
|
||||
###########################################################
|
||||
## BINARIES
|
||||
###########################################################
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
########################################
|
||||
# TARGET
|
||||
########################################
|
||||
|
||||
add_executable(lru-cache-test ${TEST_LRU_CACHE_SOURCES})
|
||||
|
||||
target_link_libraries(lru-cache-test gtest gtest_main)
|
||||
|
||||
add_test(
|
||||
NAME lru-cache-test
|
||||
COMMAND lru-cache-test
|
||||
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
|
||||
)
|
||||
545
src/3rdParty/lru-cache/tests/cache-test.cpp
vendored
Normal file
545
src/3rdParty/lru-cache/tests/cache-test.cpp
vendored
Normal file
@@ -0,0 +1,545 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace LRU;
|
||||
|
||||
struct CacheTest : public ::testing::Test {
|
||||
using CacheType = Cache<std::string, int>;
|
||||
|
||||
template <typename Cache, typename Range>
|
||||
bool is_equal_to_range(const Cache& cache, const Range& range) {
|
||||
using std::begin;
|
||||
return std::equal(cache.ordered_begin(), cache.ordered_end(), begin(range));
|
||||
}
|
||||
|
||||
CacheType cache;
|
||||
};
|
||||
|
||||
TEST(CacheConstructionTest, IsConstructibleFromInitializerList) {
|
||||
Cache<std::string, int> cache = {
|
||||
{"one", 1}, {"two", 2}, {"three", 3},
|
||||
};
|
||||
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
EXPECT_EQ(cache.size(), 3);
|
||||
EXPECT_EQ(cache["one"], 1);
|
||||
EXPECT_EQ(cache["two"], 2);
|
||||
EXPECT_EQ(cache["three"], 3);
|
||||
}
|
||||
|
||||
TEST(CacheConstructionTest, IsConstructibleFromInitializerListWithCapacity) {
|
||||
// clang-format off
|
||||
Cache<std::string, int> cache(2, {
|
||||
{"one", 1}, {"two", 2}, {"three", 3},
|
||||
});
|
||||
// clang-format on
|
||||
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
EXPECT_EQ(cache.size(), 2);
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
EXPECT_EQ(cache["two"], 2);
|
||||
EXPECT_EQ(cache["three"], 3);
|
||||
}
|
||||
|
||||
TEST(CacheConstructionTest, IsConstructibleFromRange) {
|
||||
const std::vector<std::pair<std::string, int>> range = {
|
||||
{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
Cache<std::string, int> cache(range);
|
||||
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
EXPECT_EQ(cache.size(), 3);
|
||||
EXPECT_EQ(cache["one"], 1);
|
||||
EXPECT_EQ(cache["two"], 2);
|
||||
EXPECT_EQ(cache["three"], 3);
|
||||
}
|
||||
|
||||
TEST(CacheConstructionTest, IsConstructibleFromIterators) {
|
||||
std::vector<std::pair<std::string, int>> range = {
|
||||
{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
Cache<std::string, int> cache(range.begin(), range.end());
|
||||
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
EXPECT_EQ(cache.size(), 3);
|
||||
EXPECT_EQ(cache["one"], 1);
|
||||
EXPECT_EQ(cache["two"], 2);
|
||||
EXPECT_EQ(cache["three"], 3);
|
||||
}
|
||||
|
||||
TEST(CacheConstructionTest, CapacityIsMaxOfInternalDefaultAndIteratorDistance) {
|
||||
std::vector<std::pair<std::string, int>> range = {
|
||||
{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
Cache<std::string, int> cache(range.begin(), range.end());
|
||||
|
||||
EXPECT_EQ(cache.capacity(), Internal::DEFAULT_CAPACITY);
|
||||
|
||||
for (int i = 0; i < Internal::DEFAULT_CAPACITY; ++i) {
|
||||
range.emplace_back(std::to_string(i), i);
|
||||
}
|
||||
|
||||
cache = std::move(range);
|
||||
EXPECT_EQ(cache.capacity(), range.size());
|
||||
|
||||
Cache<std::string, int> cache2(range.begin(), range.end());
|
||||
EXPECT_EQ(cache2.capacity(), range.size());
|
||||
}
|
||||
|
||||
TEST(CacheConstructionTest, UsesCustomHashFunction) {
|
||||
using MockHash = std::function<int(int)>;
|
||||
|
||||
std::size_t mock_hash_call_count = 0;
|
||||
MockHash mock_hash = [&mock_hash_call_count](int value) {
|
||||
mock_hash_call_count += 1;
|
||||
return value;
|
||||
};
|
||||
|
||||
Cache<int, int, decltype(mock_hash)> cache(128, mock_hash);
|
||||
|
||||
EXPECT_EQ(mock_hash_call_count, 0);
|
||||
|
||||
cache.contains(5);
|
||||
EXPECT_EQ(mock_hash_call_count, 1);
|
||||
}
|
||||
|
||||
TEST(CacheConstructionTest, UsesCustomKeyEqual) {
|
||||
using MockCompare = std::function<bool(int, int)>;
|
||||
|
||||
std::size_t mock_equal_call_count = 0;
|
||||
MockCompare mock_equal = [&mock_equal_call_count](int a, int b) {
|
||||
mock_equal_call_count += 1;
|
||||
return a == b;
|
||||
};
|
||||
|
||||
Cache<int, int, std::hash<int>, decltype(mock_equal)> cache(
|
||||
128, std::hash<int>(), mock_equal);
|
||||
|
||||
EXPECT_EQ(mock_equal_call_count, 0);
|
||||
|
||||
cache.insert(5, 1);
|
||||
ASSERT_TRUE(cache.contains(5));
|
||||
EXPECT_EQ(mock_equal_call_count, 1);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ContainsAfterInsertion) {
|
||||
ASSERT_TRUE(cache.is_empty());
|
||||
|
||||
for (std::size_t i = 1; i <= 100; ++i) {
|
||||
const auto key = std::to_string(i);
|
||||
cache.insert(key, i);
|
||||
EXPECT_EQ(cache.size(), i);
|
||||
EXPECT_TRUE(cache.contains(key));
|
||||
}
|
||||
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ContainsAfteEmplacement) {
|
||||
ASSERT_TRUE(cache.is_empty());
|
||||
|
||||
for (std::size_t i = 1; i <= 100; ++i) {
|
||||
const auto key = std::to_string(i);
|
||||
cache.emplace(key, i);
|
||||
EXPECT_EQ(cache.size(), i);
|
||||
EXPECT_TRUE(cache.contains(key));
|
||||
}
|
||||
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, RemovesLRUElementWhenFull) {
|
||||
cache.capacity(2);
|
||||
ASSERT_EQ(cache.capacity(), 2);
|
||||
|
||||
cache.emplace("one", 1);
|
||||
cache.emplace("two", 2);
|
||||
ASSERT_EQ(cache.size(), 2);
|
||||
ASSERT_TRUE(cache.contains("one"));
|
||||
ASSERT_TRUE(cache.contains("two"));
|
||||
|
||||
|
||||
cache.emplace("three", 3);
|
||||
EXPECT_EQ(cache.size(), 2);
|
||||
EXPECT_TRUE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, LookupReturnsTheRightValue) {
|
||||
for (std::size_t i = 1; i <= 10; ++i) {
|
||||
const auto key = std::to_string(i);
|
||||
cache.emplace(key, i);
|
||||
ASSERT_EQ(cache.size(), i);
|
||||
EXPECT_EQ(cache.lookup(key), i);
|
||||
EXPECT_EQ(cache[key], i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, LookupOnlyThrowsWhenKeyNotFound) {
|
||||
cache.emplace("one", 1);
|
||||
|
||||
ASSERT_EQ(cache.size(), 1);
|
||||
EXPECT_EQ(cache.lookup("one"), 1);
|
||||
|
||||
EXPECT_THROW(cache.lookup("two"), LRU::Error::KeyNotFound);
|
||||
EXPECT_THROW(cache.lookup("three"), LRU::Error::KeyNotFound);
|
||||
|
||||
cache.emplace("two", 2);
|
||||
EXPECT_EQ(cache.lookup("two"), 2);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, SizeIsUpdatedProperly) {
|
||||
ASSERT_EQ(cache.size(), 0);
|
||||
|
||||
for (std::size_t i = 1; i <= 10; ++i) {
|
||||
cache.emplace(std::to_string(i), i);
|
||||
// Use ASSERT and not EXPECT to terminate the loop early
|
||||
ASSERT_EQ(cache.size(), i);
|
||||
}
|
||||
|
||||
for (std::size_t i = 10; i >= 1; --i) {
|
||||
ASSERT_EQ(cache.size(), i);
|
||||
cache.erase(std::to_string(i));
|
||||
// Use ASSERT and not EXPECT to terminate the loop early
|
||||
}
|
||||
|
||||
EXPECT_EQ(cache.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, SpaceLeftWorks) {
|
||||
cache.capacity(10);
|
||||
ASSERT_EQ(cache.size(), 0);
|
||||
|
||||
for (std::size_t i = 10; i >= 1; --i) {
|
||||
EXPECT_EQ(cache.space_left(), i);
|
||||
cache.emplace(std::to_string(i), i);
|
||||
}
|
||||
|
||||
EXPECT_EQ(cache.space_left(), 0);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, IsEmptyWorks) {
|
||||
ASSERT_TRUE(cache.is_empty());
|
||||
cache.emplace("one", 1);
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
cache.clear();
|
||||
EXPECT_TRUE(cache.is_empty());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, IsFullWorks) {
|
||||
ASSERT_FALSE(cache.is_full());
|
||||
cache.capacity(0);
|
||||
ASSERT_TRUE(cache.is_full());
|
||||
|
||||
cache.capacity(2);
|
||||
cache.emplace("one", 1);
|
||||
EXPECT_FALSE(cache.is_full());
|
||||
cache.emplace("two", 1);
|
||||
EXPECT_TRUE(cache.is_full());
|
||||
|
||||
cache.clear();
|
||||
EXPECT_FALSE(cache.is_full());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, CapacityCanBeAdjusted) {
|
||||
cache.capacity(10);
|
||||
|
||||
ASSERT_EQ(cache.capacity(), 10);
|
||||
|
||||
for (std::size_t i = 0; i < 10; ++i) {
|
||||
cache.emplace(std::to_string(i), i);
|
||||
}
|
||||
|
||||
ASSERT_EQ(cache.size(), 10);
|
||||
|
||||
cache.emplace("foo", 0xdeadbeef);
|
||||
EXPECT_EQ(cache.size(), 10);
|
||||
|
||||
cache.capacity(11);
|
||||
ASSERT_EQ(cache.capacity(), 11);
|
||||
|
||||
cache.emplace("bar", 0xdeadbeef);
|
||||
EXPECT_EQ(cache.size(), 11);
|
||||
|
||||
cache.capacity(5);
|
||||
EXPECT_EQ(cache.capacity(), 5);
|
||||
EXPECT_EQ(cache.size(), 5);
|
||||
|
||||
cache.capacity(0);
|
||||
EXPECT_EQ(cache.capacity(), 0);
|
||||
EXPECT_EQ(cache.size(), 0);
|
||||
|
||||
cache.capacity(128);
|
||||
EXPECT_EQ(cache.capacity(), 128);
|
||||
EXPECT_EQ(cache.size(), 0);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, EraseErasesAndReturnsTrueWhenElementContained) {
|
||||
cache.emplace("one", 1);
|
||||
ASSERT_TRUE(cache.contains("one"));
|
||||
|
||||
EXPECT_TRUE(cache.erase("one"));
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, EraseReturnsFalseWhenElementNotContained) {
|
||||
ASSERT_FALSE(cache.contains("one"));
|
||||
EXPECT_FALSE(cache.erase("one"));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ClearRemovesAllElements) {
|
||||
ASSERT_TRUE(cache.is_empty());
|
||||
|
||||
cache.emplace("one", 1);
|
||||
EXPECT_FALSE(cache.is_empty());
|
||||
|
||||
cache.clear();
|
||||
EXPECT_TRUE(cache.is_empty());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ShrinkAdjustsSizeWell) {
|
||||
cache.emplace("one", 1);
|
||||
cache.emplace("two", 2);
|
||||
|
||||
ASSERT_EQ(cache.size(), 2);
|
||||
|
||||
cache.shrink(1);
|
||||
|
||||
EXPECT_EQ(cache.size(), 1);
|
||||
|
||||
cache.emplace("three", 2);
|
||||
cache.emplace("four", 3);
|
||||
|
||||
ASSERT_EQ(cache.size(), 3);
|
||||
|
||||
cache.shrink(1);
|
||||
|
||||
EXPECT_EQ(cache.size(), 1);
|
||||
|
||||
cache.shrink(0);
|
||||
|
||||
EXPECT_TRUE(cache.is_empty());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ShrinkDoesNothingWhenRequestedSizeIsGreaterThanCurrent) {
|
||||
cache.emplace("one", 1);
|
||||
cache.emplace("two", 2);
|
||||
|
||||
ASSERT_EQ(cache.size(), 2);
|
||||
|
||||
cache.shrink(50);
|
||||
|
||||
EXPECT_EQ(cache.size(), 2);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ShrinkRemovesLRUElements) {
|
||||
cache.emplace("one", 1);
|
||||
cache.emplace("two", 2);
|
||||
cache.emplace("three", 3);
|
||||
|
||||
ASSERT_EQ(cache.size(), 3);
|
||||
|
||||
cache.shrink(2);
|
||||
|
||||
EXPECT_EQ(cache.size(), 2);
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
EXPECT_TRUE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
|
||||
cache.shrink(1);
|
||||
|
||||
EXPECT_EQ(cache.size(), 1);
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
EXPECT_FALSE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, CanInsertIterators) {
|
||||
using Range = std::vector<std::pair<std::string, int>>;
|
||||
Range range = {{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
EXPECT_EQ(cache.insert(range.begin(), range.end()), 3);
|
||||
EXPECT_TRUE(is_equal_to_range(cache, range));
|
||||
|
||||
Range range2 = {{"one", 1}, {"four", 4}};
|
||||
|
||||
EXPECT_EQ(cache.insert(range2.begin(), range2.end()), 1);
|
||||
// clang-format off
|
||||
EXPECT_TRUE(is_equal_to_range(cache, Range({
|
||||
{"two", 2}, {"three", 3}, {"one", 1}, {"four", 4}
|
||||
})));
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, CanInsertRange) {
|
||||
std::vector<std::pair<std::string, int>> range = {
|
||||
{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
cache.insert(range);
|
||||
EXPECT_TRUE(is_equal_to_range(cache, range));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, CanInsertList) {
|
||||
std::initializer_list<std::pair<std::string, int>> list = {
|
||||
{"one", 1}, {"two", 2}, {"three", 3}};
|
||||
|
||||
// Do it like this, just to verify that template deduction fails if only
|
||||
// the range function exists and no explicit overload for the initializer list
|
||||
cache.insert({{"one", 1}, {"two", 2}, {"three", 3}});
|
||||
EXPECT_TRUE(is_equal_to_range(cache, list));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ResultIsCorrectForInsert) {
|
||||
auto result = cache.insert("one", 1);
|
||||
|
||||
EXPECT_TRUE(result.was_inserted());
|
||||
EXPECT_TRUE(result);
|
||||
|
||||
EXPECT_EQ(result.iterator(), cache.begin());
|
||||
|
||||
result = cache.insert("one", 1);
|
||||
|
||||
EXPECT_FALSE(result.was_inserted());
|
||||
EXPECT_FALSE(result);
|
||||
|
||||
EXPECT_EQ(result.iterator(), cache.begin());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ResultIsCorrectForEmplace) {
|
||||
auto result = cache.emplace("one", 1);
|
||||
|
||||
EXPECT_TRUE(result.was_inserted());
|
||||
EXPECT_TRUE(result);
|
||||
|
||||
EXPECT_EQ(result.iterator(), cache.begin());
|
||||
|
||||
result = cache.emplace("one", 1);
|
||||
|
||||
EXPECT_FALSE(result.was_inserted());
|
||||
EXPECT_FALSE(result);
|
||||
|
||||
EXPECT_EQ(result.iterator(), cache.begin());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, CapacityIsSameAfterCopy) {
|
||||
cache.capacity(100);
|
||||
auto cache2 = cache;
|
||||
|
||||
EXPECT_EQ(cache.capacity(), cache2.capacity());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, CapacityIsSameAfterMove) {
|
||||
cache.capacity(100);
|
||||
auto cache2 = std::move(cache);
|
||||
|
||||
EXPECT_EQ(cache2.capacity(), 100);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, ComparisonOperatorWorks) {
|
||||
ASSERT_EQ(cache, cache);
|
||||
|
||||
auto cache2 = cache;
|
||||
EXPECT_EQ(cache, cache2);
|
||||
|
||||
cache.emplace("one", 1);
|
||||
cache2.emplace("one", 1);
|
||||
EXPECT_EQ(cache, cache2);
|
||||
|
||||
cache.emplace("two", 2);
|
||||
cache2.emplace("two", 2);
|
||||
EXPECT_EQ(cache, cache2);
|
||||
|
||||
cache.erase("two");
|
||||
EXPECT_NE(cache, cache2);
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, SwapWorks) {
|
||||
auto cache2 = cache;
|
||||
|
||||
cache.emplace("one", 1);
|
||||
cache2.emplace("two", 2);
|
||||
|
||||
ASSERT_TRUE(cache.contains("one"));
|
||||
ASSERT_TRUE(cache2.contains("two"));
|
||||
|
||||
cache.swap(cache2);
|
||||
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
EXPECT_TRUE(cache.contains("two"));
|
||||
EXPECT_FALSE(cache2.contains("two"));
|
||||
EXPECT_TRUE(cache2.contains("one"));
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, SizeStaysZeroWhenCapacityZero) {
|
||||
cache.capacity(0);
|
||||
|
||||
ASSERT_EQ(cache.capacity(), 0);
|
||||
ASSERT_EQ(cache.size(), 0);
|
||||
|
||||
auto result = cache.insert("one", 1);
|
||||
|
||||
EXPECT_EQ(cache.capacity(), 0);
|
||||
EXPECT_EQ(cache.size(), 0);
|
||||
EXPECT_FALSE(result.was_inserted());
|
||||
EXPECT_EQ(result.iterator(), cache.end());
|
||||
|
||||
result = cache.emplace("two", 2);
|
||||
|
||||
EXPECT_EQ(cache.capacity(), 0);
|
||||
EXPECT_EQ(cache.size(), 0);
|
||||
EXPECT_FALSE(result.was_inserted());
|
||||
EXPECT_EQ(result.iterator(), cache.end());
|
||||
}
|
||||
|
||||
TEST_F(CacheTest, LookupsMoveElementsToFront) {
|
||||
cache.capacity(2);
|
||||
cache.insert({{"one", 1}, {"two", 2}});
|
||||
|
||||
// The LRU principle mandates that lookups place
|
||||
// accessed elements to the front.
|
||||
|
||||
typename CacheType::OrderedIterator iterator(cache.find("one"));
|
||||
cache.emplace("three", 3);
|
||||
|
||||
EXPECT_TRUE(cache.contains("one"));
|
||||
EXPECT_FALSE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
EXPECT_EQ(std::prev(cache.ordered_end()).key(), "three");
|
||||
EXPECT_EQ(cache.front(), "three");
|
||||
EXPECT_EQ(cache.back(), "one");
|
||||
|
||||
ASSERT_EQ(cache.lookup("one"), 1);
|
||||
EXPECT_EQ(std::prev(cache.ordered_end()).key(), "one");
|
||||
EXPECT_EQ(cache.ordered_begin().key(), "three");
|
||||
EXPECT_EQ(cache.front(), "one");
|
||||
EXPECT_EQ(cache.back(), "three");
|
||||
}
|
||||
155
src/3rdParty/lru-cache/tests/callback-test.cpp
vendored
Normal file
155
src/3rdParty/lru-cache/tests/callback-test.cpp
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace LRU;
|
||||
|
||||
struct CallbackTest : public ::testing::Test {
|
||||
Cache<int, int> cache;
|
||||
};
|
||||
|
||||
TEST_F(CallbackTest, HitCallbacksGetCalled) {
|
||||
std::array<int, 3> counts = {0, 0, 0};
|
||||
|
||||
cache.hit_callback([&counts](auto& key, auto& value) { counts[key] += 1; });
|
||||
|
||||
cache.emplace(0, 0);
|
||||
cache.emplace(1, 1);
|
||||
cache.emplace(2, 2);
|
||||
|
||||
ASSERT_TRUE(cache.contains(0));
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], 0);
|
||||
EXPECT_EQ(counts[2], 0);
|
||||
|
||||
cache.find(2);
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], 0);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
|
||||
cache.lookup(1);
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], 1);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
|
||||
cache.lookup(0);
|
||||
EXPECT_EQ(counts[0], 2);
|
||||
EXPECT_EQ(counts[1], 1);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
|
||||
cache.contains(5);
|
||||
EXPECT_EQ(counts[0], 2);
|
||||
EXPECT_EQ(counts[1], 1);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
}
|
||||
|
||||
TEST_F(CallbackTest, MissCallbacksGetCalled) {
|
||||
std::array<int, 3> counts = {0, 0, 0};
|
||||
|
||||
cache.miss_callback([&counts](auto& key) { counts[key] += 1; });
|
||||
|
||||
cache.emplace(0, 0);
|
||||
|
||||
ASSERT_TRUE(cache.contains(0));
|
||||
EXPECT_EQ(counts[0], 0);
|
||||
EXPECT_EQ(counts[1], 0);
|
||||
EXPECT_EQ(counts[2], 0);
|
||||
|
||||
cache.find(2);
|
||||
EXPECT_EQ(counts[0], 0);
|
||||
EXPECT_EQ(counts[1], 0);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
|
||||
cache.find(1);
|
||||
EXPECT_EQ(counts[0], 0);
|
||||
EXPECT_EQ(counts[1], 1);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(counts[0], 0);
|
||||
EXPECT_EQ(counts[1], 2);
|
||||
EXPECT_EQ(counts[2], 1);
|
||||
}
|
||||
|
||||
TEST_F(CallbackTest, AccessCallbacksGetCalled) {
|
||||
std::array<int, 3> counts = {0, 0, 0};
|
||||
|
||||
cache.access_callback(
|
||||
[&counts](auto& key, bool found) { counts[key] += found ? 1 : -1; });
|
||||
|
||||
cache.emplace(0, 0);
|
||||
|
||||
ASSERT_TRUE(cache.contains(0));
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], 0);
|
||||
EXPECT_EQ(counts[2], 0);
|
||||
|
||||
cache.find(2);
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], 0);
|
||||
EXPECT_EQ(counts[2], -1);
|
||||
|
||||
cache.find(1);
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], -1);
|
||||
EXPECT_EQ(counts[2], -1);
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(counts[0], 1);
|
||||
EXPECT_EQ(counts[1], -2);
|
||||
EXPECT_EQ(counts[2], -1);
|
||||
|
||||
cache.find(0);
|
||||
EXPECT_EQ(counts[0], 2);
|
||||
EXPECT_EQ(counts[1], -2);
|
||||
EXPECT_EQ(counts[2], -1);
|
||||
}
|
||||
|
||||
TEST_F(CallbackTest, CallbacksAreNotCalledAfterBeingCleared) {
|
||||
int hit = 0, miss = 0, access = 0;
|
||||
cache.hit_callback([&hit](auto&, auto&) { hit += 1; });
|
||||
cache.miss_callback([&miss](auto&) { miss += 1; });
|
||||
cache.access_callback([&access](auto&, bool) { access += 1; });
|
||||
|
||||
cache.emplace(0, 0);
|
||||
|
||||
cache.contains(0);
|
||||
cache.find(1);
|
||||
|
||||
ASSERT_EQ(hit, 1);
|
||||
ASSERT_EQ(miss, 1);
|
||||
ASSERT_EQ(access, 2);
|
||||
|
||||
cache.clear_all_callbacks();
|
||||
|
||||
cache.contains(0);
|
||||
cache.find(1);
|
||||
cache.find(2);
|
||||
|
||||
ASSERT_EQ(hit, 1);
|
||||
ASSERT_EQ(miss, 1);
|
||||
ASSERT_EQ(access, 2);
|
||||
}
|
||||
312
src/3rdParty/lru-cache/tests/iterator-test.cpp
vendored
Normal file
312
src/3rdParty/lru-cache/tests/iterator-test.cpp
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace LRU;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
struct IteratorTest : public ::testing::Test {
|
||||
using CacheType = Cache<std::string, int>;
|
||||
using UnorderedIterator = typename CacheType::UnorderedIterator;
|
||||
using UnorderedConstIterator = typename CacheType::UnorderedConstIterator;
|
||||
using OrderedIterator = typename CacheType::OrderedIterator;
|
||||
using OrderedConstIterator = typename CacheType::OrderedConstIterator;
|
||||
|
||||
CacheType cache;
|
||||
};
|
||||
|
||||
TEST_F(IteratorTest, UnorderedIteratorsAreCompatibleAsExpected) {
|
||||
cache.emplace("one", 1);
|
||||
|
||||
// Move construction
|
||||
UnorderedIterator first(cache.unordered_begin());
|
||||
|
||||
// Copy construction
|
||||
UnorderedIterator second(first);
|
||||
|
||||
// Copy assignment
|
||||
UnorderedIterator third;
|
||||
third = second;
|
||||
|
||||
// Move construction from non-const to const
|
||||
UnorderedConstIterator first_const(std::move(first));
|
||||
|
||||
// Copy construction from non-const to const
|
||||
UnorderedConstIterator second_const(second);
|
||||
|
||||
// Copy assignment
|
||||
UnorderedConstIterator third_const;
|
||||
third_const = third;
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, OrderedIteratorsAreCompatibleAsExpected) {
|
||||
cache.emplace("one", 1);
|
||||
|
||||
// Move construction
|
||||
OrderedIterator first(cache.ordered_begin());
|
||||
|
||||
// Copy construction
|
||||
OrderedIterator second(first);
|
||||
|
||||
// Copy assignment
|
||||
OrderedIterator third;
|
||||
third = second;
|
||||
|
||||
// Move construction from non-const to const
|
||||
OrderedConstIterator first_const(std::move(first));
|
||||
|
||||
// Copy construction from non-const to const
|
||||
OrderedConstIterator second_const(second);
|
||||
|
||||
// Copy assignment
|
||||
OrderedConstIterator third_const;
|
||||
third_const = third;
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, OrderedAndUnorderedAreComparable) {
|
||||
cache.emplace("one", 1);
|
||||
|
||||
// Basic assumptions
|
||||
ASSERT_EQ(cache.unordered_begin(), cache.unordered_begin());
|
||||
ASSERT_EQ(cache.ordered_begin(), cache.ordered_begin());
|
||||
ASSERT_EQ(cache.unordered_end(), cache.unordered_end());
|
||||
ASSERT_EQ(cache.ordered_end(), cache.ordered_end());
|
||||
|
||||
EXPECT_EQ(cache.unordered_begin(), cache.ordered_begin());
|
||||
|
||||
// We need to ensure symmetry!
|
||||
EXPECT_EQ(cache.ordered_begin(), cache.unordered_begin());
|
||||
|
||||
// This is an exceptional property we expect
|
||||
EXPECT_EQ(cache.unordered_end(), cache.ordered_end());
|
||||
EXPECT_EQ(cache.ordered_end(), cache.unordered_end());
|
||||
|
||||
// These assumptions should hold because there is only one element
|
||||
// so the unordered iterator will convert to an ordered iterator, then
|
||||
// compare equal because both point to the same single element.
|
||||
EXPECT_EQ(cache.ordered_begin(), cache.unordered_begin());
|
||||
EXPECT_EQ(cache.unordered_begin(), cache.ordered_begin());
|
||||
|
||||
cache.emplace("two", 1);
|
||||
|
||||
// But then the usual assumptions should hold
|
||||
EXPECT_NE(cache.ordered_begin(), cache.find("two"));
|
||||
EXPECT_NE(cache.find("two"), cache.ordered_begin());
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, TestConversionFromUnorderedToOrdered) {
|
||||
cache.emplace("one", 1);
|
||||
cache.emplace("two", 2);
|
||||
cache.emplace("three", 3);
|
||||
|
||||
// Note: find() will always return end() - 1
|
||||
UnorderedIterator unordered = cache.find("one");
|
||||
|
||||
ASSERT_EQ(unordered.key(), "one");
|
||||
ASSERT_EQ(unordered.value(), 1);
|
||||
|
||||
OrderedIterator ordered(unordered);
|
||||
ordered = OrderedIterator(unordered);
|
||||
|
||||
EXPECT_EQ(ordered.key(), "one");
|
||||
EXPECT_EQ(ordered.value(), 1);
|
||||
|
||||
// Once it's ordered, the ordering shold be maintained
|
||||
--ordered;
|
||||
EXPECT_EQ(ordered.key(), "three");
|
||||
EXPECT_EQ(ordered.value(), 3);
|
||||
|
||||
UnorderedConstIterator const_unordered = unordered;
|
||||
const_unordered = unordered;
|
||||
|
||||
OrderedConstIterator const_ordered(std::move(const_unordered));
|
||||
const_ordered = OrderedConstIterator(std::move(const_unordered));
|
||||
|
||||
// Just making sure this compiles
|
||||
const_ordered = --ordered;
|
||||
const_ordered = OrderedConstIterator(unordered);
|
||||
|
||||
EXPECT_EQ(ordered.key(), "two");
|
||||
EXPECT_EQ(ordered.value(), 2);
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, OrdereredIteratorsAreOrdered) {
|
||||
for (std::size_t i = 0; i < 100; ++i) {
|
||||
cache.emplace(std::to_string(i), i);
|
||||
}
|
||||
|
||||
auto iterator = cache.ordered_begin();
|
||||
for (std::size_t i = 0; i < 100; ++i, ++iterator) {
|
||||
ASSERT_EQ(iterator.value(), i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, OrderedIteratorsDoNotChangeTheOrderOfElements) {
|
||||
cache.capacity(2);
|
||||
cache.insert({{"one", 1}});
|
||||
|
||||
auto begin = cache.ordered_begin();
|
||||
|
||||
cache.emplace("two", 2);
|
||||
|
||||
// This here will cause a lookup, but it should not
|
||||
// change the order of elements
|
||||
ASSERT_EQ(begin->key(), "one");
|
||||
ASSERT_EQ((++begin)->key(), "two");
|
||||
ASSERT_EQ((--begin)->key(), "one");
|
||||
cache.emplace("three", 3);
|
||||
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
EXPECT_TRUE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, UnorderedIteratorsDoNotChangeTheOrderOfElements) {
|
||||
cache.capacity(2);
|
||||
cache.insert({{"one", 1}});
|
||||
|
||||
auto begin = cache.unordered_begin();
|
||||
|
||||
cache.emplace("two", 2);
|
||||
|
||||
ASSERT_EQ(begin->key(), "one");
|
||||
cache.emplace("three", 3);
|
||||
|
||||
EXPECT_FALSE(cache.contains("one"));
|
||||
EXPECT_TRUE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
|
||||
ASSERT_EQ(cache.back(), "two");
|
||||
ASSERT_EQ(cache.front(), "three");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(IteratorTest, OrderedIteratorsThrowWhenAccessingExpiredElements) {
|
||||
TimedCache<int, int> timed_cache(0ms);
|
||||
|
||||
timed_cache.emplace(1, 1);
|
||||
|
||||
auto iterator = timed_cache.ordered_begin();
|
||||
|
||||
EXPECT_THROW(iterator.entry(), LRU::Error::KeyExpired);
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, UnorderedIteratorsThrowWhenAccessingExpiredElements) {
|
||||
TimedCache<int, int> timed_cache(0ms);
|
||||
|
||||
timed_cache.emplace(1, 1);
|
||||
|
||||
auto iterator = timed_cache.unordered_begin();
|
||||
|
||||
EXPECT_THROW(iterator.entry(), LRU::Error::KeyExpired);
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, IsValidReturnsTrueForValidIterators) {
|
||||
cache.emplace("one", 1);
|
||||
cache.emplace("two", 1);
|
||||
|
||||
auto ordered_iterator = cache.ordered_begin();
|
||||
EXPECT_TRUE(cache.is_valid(ordered_iterator));
|
||||
EXPECT_TRUE(cache.is_valid(++ordered_iterator));
|
||||
|
||||
auto unordered_iterator = cache.unordered_begin();
|
||||
EXPECT_TRUE(cache.is_valid(unordered_iterator));
|
||||
EXPECT_TRUE(cache.is_valid(++unordered_iterator));
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, IsValidReturnsFalseForInvalidIterators) {
|
||||
TimedCache<int, int> timed_cache(0ms);
|
||||
|
||||
EXPECT_FALSE(cache.is_valid(cache.ordered_begin()));
|
||||
EXPECT_FALSE(cache.is_valid(cache.ordered_end()));
|
||||
EXPECT_FALSE(cache.is_valid(cache.unordered_begin()));
|
||||
EXPECT_FALSE(cache.is_valid(cache.unordered_end()));
|
||||
|
||||
timed_cache.emplace(1, 1);
|
||||
|
||||
EXPECT_FALSE(cache.is_valid(cache.ordered_begin()));
|
||||
EXPECT_FALSE(cache.is_valid(cache.unordered_begin()));
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, ThrowIfInvalidThrowsAsExpected) {
|
||||
EXPECT_THROW(cache.throw_if_invalid(cache.ordered_begin()),
|
||||
LRU::Error::InvalidIterator);
|
||||
EXPECT_THROW(cache.throw_if_invalid(cache.ordered_end()),
|
||||
LRU::Error::InvalidIterator);
|
||||
EXPECT_THROW(cache.throw_if_invalid(cache.unordered_begin()),
|
||||
LRU::Error::InvalidIterator);
|
||||
EXPECT_THROW(cache.throw_if_invalid(cache.unordered_end()),
|
||||
LRU::Error::InvalidIterator);
|
||||
|
||||
TimedCache<int, int> timed_cache(0s, {{1, 1}});
|
||||
|
||||
ASSERT_EQ(timed_cache.size(), 1);
|
||||
|
||||
EXPECT_THROW(timed_cache.throw_if_invalid(timed_cache.ordered_begin()),
|
||||
LRU::Error::KeyExpired);
|
||||
EXPECT_THROW(timed_cache.throw_if_invalid(timed_cache.unordered_begin()),
|
||||
LRU::Error::KeyExpired);
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, DereferencingNeverThrows) {
|
||||
TimedCache<int, int> timed_cache(1ms, {{1, 1}});
|
||||
|
||||
// Test valid iterators.
|
||||
EXPECT_EQ(timed_cache.ordered_begin()->key(), 1);
|
||||
EXPECT_EQ(timed_cache.unordered_begin()->key(), 1);
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
// Test invalid iterators.
|
||||
*timed_cache.ordered_begin();
|
||||
*timed_cache.unordered_begin();
|
||||
timed_cache.ordered_begin()->key();
|
||||
timed_cache.unordered_begin()->key();
|
||||
timed_cache.ordered_begin()->value();
|
||||
timed_cache.unordered_begin()->value();
|
||||
}
|
||||
|
||||
TEST_F(IteratorTest, CallingAccessThrowsForInvalidIterators) {
|
||||
TimedCache<int, int> timed_cache(1ms, {{1, 1}});
|
||||
|
||||
// Test valid iterators.
|
||||
ASSERT_EQ(timed_cache.ordered_begin()->key(), 1);
|
||||
ASSERT_EQ(timed_cache.unordered_begin()->key(), 1);
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
// Test invalid iterators.
|
||||
EXPECT_THROW(timed_cache.ordered_begin().key(), LRU::Error::KeyExpired);
|
||||
EXPECT_THROW(timed_cache.unordered_begin().key(), LRU::Error::KeyExpired);
|
||||
EXPECT_THROW(timed_cache.ordered_begin().value(), LRU::Error::KeyExpired);
|
||||
EXPECT_THROW(timed_cache.unordered_begin().value(), LRU::Error::KeyExpired);
|
||||
EXPECT_THROW(timed_cache.ordered_end().key(), LRU::Error::InvalidIterator);
|
||||
EXPECT_THROW(timed_cache.unordered_end().key(), LRU::Error::InvalidIterator);
|
||||
EXPECT_THROW(timed_cache.ordered_end().value(), LRU::Error::InvalidIterator);
|
||||
EXPECT_THROW(timed_cache.unordered_end().value(),
|
||||
LRU::Error::InvalidIterator);
|
||||
}
|
||||
109
src/3rdParty/lru-cache/tests/last-accessed-test.cpp
vendored
Normal file
109
src/3rdParty/lru-cache/tests/last-accessed-test.cpp
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lru/internal/last-accessed.hpp"
|
||||
|
||||
using namespace LRU::Internal;
|
||||
|
||||
struct LastAccessedTest : public ::testing::Test {
|
||||
using Map = std::unordered_map<std::string, int>;
|
||||
static Map map;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
LastAccessedTest::Map LastAccessedTest::map = {
|
||||
{"one", 1},
|
||||
{"two", 2},
|
||||
{"three", 3}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
TEST_F(LastAccessedTest, IsAssignableFromConstAndNonConst) {
|
||||
auto front = map.find("one");
|
||||
|
||||
LastAccessed<std::string, int> last_accessed(front->first, front->second);
|
||||
|
||||
ASSERT_EQ(last_accessed.key(), "one");
|
||||
ASSERT_EQ(last_accessed.information(), 1);
|
||||
|
||||
last_accessed = map.find("two");
|
||||
|
||||
EXPECT_EQ(last_accessed.key(), "two");
|
||||
EXPECT_EQ(last_accessed.information(), 2);
|
||||
|
||||
last_accessed = map.find("three");
|
||||
|
||||
EXPECT_EQ(last_accessed.key(), "three");
|
||||
EXPECT_EQ(last_accessed.information(), 3);
|
||||
}
|
||||
|
||||
TEST_F(LastAccessedTest, IsComparableWithConstAndNonConstIterators) {
|
||||
auto front = map.find("one");
|
||||
LastAccessed<std::string, int> last_accessed(front->first, front->second);
|
||||
|
||||
// non-const
|
||||
EXPECT_EQ(last_accessed, front);
|
||||
EXPECT_EQ(front, last_accessed);
|
||||
|
||||
EXPECT_NE(map.find("two"), last_accessed);
|
||||
EXPECT_NE(last_accessed, map.find("three"));
|
||||
|
||||
// const
|
||||
Map::const_iterator const_front = map.find("one");
|
||||
EXPECT_EQ(last_accessed, const_front);
|
||||
EXPECT_EQ(const_front, last_accessed);
|
||||
|
||||
Map::const_iterator iterator = map.find("two");
|
||||
EXPECT_NE(iterator, last_accessed);
|
||||
|
||||
iterator = map.find("three");
|
||||
EXPECT_NE(last_accessed, iterator);
|
||||
}
|
||||
|
||||
TEST_F(LastAccessedTest, IsComparableToConstAndNonConstKeys) {
|
||||
using namespace std::string_literals;
|
||||
|
||||
std::string key = "forty-two";
|
||||
int information = 42;
|
||||
|
||||
LastAccessed<std::string, int> last_accessed(key, information);
|
||||
|
||||
EXPECT_EQ(last_accessed, key);
|
||||
EXPECT_EQ(key, last_accessed);
|
||||
|
||||
EXPECT_EQ(last_accessed, "forty-two"s);
|
||||
EXPECT_EQ("forty-two"s, last_accessed);
|
||||
|
||||
const std::string& key_const_reference = key;
|
||||
|
||||
EXPECT_EQ(key_const_reference, last_accessed);
|
||||
EXPECT_EQ(last_accessed, key_const_reference);
|
||||
|
||||
EXPECT_NE(last_accessed, "asdf"s);
|
||||
EXPECT_NE(last_accessed, "foo"s);
|
||||
EXPECT_NE(last_accessed, "forty-three"s);
|
||||
}
|
||||
166
src/3rdParty/lru-cache/tests/logbt.sh
vendored
Normal file
166
src/3rdParty/lru-cache/tests/logbt.sh
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Taken from:
|
||||
# https://github.com/mapbox/logbt
|
||||
|
||||
set -eu
|
||||
set -o pipefail
|
||||
shopt -s nullglob
|
||||
|
||||
export CORE_DIRECTORY=/tmp/logbt-coredumps
|
||||
|
||||
function error() {
|
||||
>&2 echo "$@"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ $(uname -s) == 'Linux' ]]; then
|
||||
if ! which gdb > /dev/null; then
|
||||
error "Could not find required command 'gdb'"
|
||||
fi
|
||||
|
||||
# if we have sudo then set core pattern
|
||||
if [[ $(id -u) == 0 ]]; then
|
||||
echo "Setting $(cat /proc/sys/kernel/core_pattern) -> ${CORE_DIRECTORY}/core.%p.%E"
|
||||
echo "${CORE_DIRECTORY}/core.%p.%E" > /proc/sys/kernel/core_pattern
|
||||
else
|
||||
# if we cannot modify the pattern we assert it has
|
||||
# already been set as we expect and need
|
||||
if [[ $(cat /proc/sys/kernel/core_pattern) != '/tmp/logbt-coredumps/core.%p.%E' ]]; then
|
||||
error "unexpected core_pattern: $(cat /proc/sys/kernel/core_pattern)"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using existing corefile location: $(cat /proc/sys/kernel/core_pattern)"
|
||||
fi
|
||||
else
|
||||
if ! which lldb > /dev/null; then
|
||||
error "Could not find required command 'lldb'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if we have sudo then set core pattern
|
||||
if [[ $(id -u) == 0 ]]; then
|
||||
sudo sysctl kern.corefile=${CORE_DIRECTORY}/core.%P
|
||||
else
|
||||
if [[ $(sysctl -n kern.corefile) == '/cores/core.%P' ]]; then
|
||||
# OS X default is /cores/core.%P which works for logbt out of the box
|
||||
export CORE_DIRECTORY=/cores
|
||||
elif [[ $(sysctl -n kern.corefile) == '${CORE_DIRECTORY}/core.%P' ]]; then
|
||||
# all good, previously set
|
||||
:
|
||||
else
|
||||
# restore default with:
|
||||
# sudo sysctl kern.corefile=/cores/core.%P
|
||||
error "unexpected core_pattern: $(sysctl -n kern.corefile)"
|
||||
exit 1
|
||||
fi
|
||||
echo "Using existing corefile location: $(sysctl -n kern.corefile)"
|
||||
fi
|
||||
|
||||
# Recommend running with the following setting to only show crashes
|
||||
# in the notification center
|
||||
# defaults write com.apple.CrashReporter UseUNC 1
|
||||
fi
|
||||
|
||||
if [[ ! -d ${CORE_DIRECTORY} ]]; then
|
||||
# TODO: enable this once tests are adapted to extra stdout
|
||||
# echo "Creating directory for core files at '${CORE_DIRECTORY}'"
|
||||
mkdir -p ${CORE_DIRECTORY}
|
||||
fi
|
||||
|
||||
# ensure we can write to the directory, otherwise
|
||||
# core files might not be able to be written
|
||||
WRITE_RETURN=0
|
||||
touch ${CORE_DIRECTORY}/test.txt || WRITE_RETURN=$?
|
||||
if [[ ${WRITE_RETURN} != 0 ]]; then
|
||||
error "Permissions problem: unable to write to ${CORE_DIRECTORY} (exited with ${WRITE_RETURN})"
|
||||
exit 1
|
||||
else
|
||||
# cleanup from test
|
||||
rm ${CORE_DIRECTORY}/test.txt
|
||||
fi
|
||||
|
||||
function process_core() {
|
||||
if [[ $(uname -s) == 'Darwin' ]]; then
|
||||
lldb --core ${2} --batch -o 'thread backtrace all' -o 'quit'
|
||||
else
|
||||
gdb ${1} --core ${2} -ex "set pagination 0" -ex "thread apply all bt" --batch
|
||||
fi
|
||||
# note: on OS X the -f avoids a hang on prompt 'remove write-protected regular file?'
|
||||
rm -f ${2}
|
||||
}
|
||||
|
||||
function backtrace {
|
||||
local code=$?
|
||||
echo "$1 exited with code:${code}"
|
||||
if [[ $(uname -s) == 'Darwin' ]]; then
|
||||
local COREFILE="${CORE_DIRECTORY}/core.${CHILD_PID}"
|
||||
if [ -e ${COREFILE} ]; then
|
||||
echo "Found core at ${COREFILE}"
|
||||
process_core $1 ${COREFILE}
|
||||
else
|
||||
if [[ ${code} != 0 ]]; then
|
||||
echo "No core found at ${COREFILE}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
local SEARCH_PATTERN_BY_PID="core.${CHILD_PID}.*"
|
||||
local hit=false
|
||||
for corefile in ${CORE_DIRECTORY}/${SEARCH_PATTERN_BY_PID}; do
|
||||
echo "Found core at ${corefile}"
|
||||
# extract program name from corefile
|
||||
filename=$(basename "${corefile}")
|
||||
binary_program=/$(echo ${filename##*.\!} | tr '!' '/')
|
||||
process_core ${binary_program} ${corefile}
|
||||
hit=true
|
||||
done
|
||||
if [[ ${hit} == false ]] && [[ ${code} != 0 ]]; then
|
||||
echo "No core found at ${CORE_DIRECTORY}/${SEARCH_PATTERN_BY_PID}"
|
||||
fi
|
||||
fi
|
||||
local SEARCH_PATTERN_NON_TRACKED="core.*"
|
||||
local hit=false
|
||||
for corefile in ${CORE_DIRECTORY}/${SEARCH_PATTERN_NON_TRACKED}; do
|
||||
echo "Found non-tracked core at ${corefile}"
|
||||
hit=true
|
||||
done
|
||||
if [[ ${code} != 0 ]]; then
|
||||
if [[ ${hit} == true ]]; then
|
||||
echo "Processing cores..."
|
||||
fi
|
||||
for corefile in ${CORE_DIRECTORY}/${SEARCH_PATTERN_NON_TRACKED}; do
|
||||
filename=$(basename "${corefile}")
|
||||
binary_program=/$(echo ${filename##*.\!} | tr '!' '/')
|
||||
process_core ${binary_program} ${corefile}
|
||||
done
|
||||
else
|
||||
if [[ ${hit} == true ]]; then
|
||||
echo "Skipping processing cores..."
|
||||
fi
|
||||
fi
|
||||
exit $code
|
||||
}
|
||||
|
||||
function warn_on_existing_cores() {
|
||||
local SEARCH_PATTERN_NON_TRACKED="core.*"
|
||||
# at startup warn about existing corefiles, since these are unexpected
|
||||
for corefile in ${CORE_DIRECTORY}/${SEARCH_PATTERN_NON_TRACKED}; do
|
||||
echo "WARNING: Found existing corefile at ${corefile}"
|
||||
done
|
||||
}
|
||||
|
||||
warn_on_existing_cores
|
||||
|
||||
# Hook up function to run when logbt exits
|
||||
trap "backtrace $1" EXIT
|
||||
|
||||
# Enable corefile generation
|
||||
ulimit -c unlimited
|
||||
|
||||
# Run the child process in a background process
|
||||
# in order to get the PID
|
||||
$* & export CHILD_PID=$!
|
||||
|
||||
# Keep logbt running as long as the child is running
|
||||
# to be able to hook into a potential crash
|
||||
wait ${CHILD_PID}
|
||||
171
src/3rdParty/lru-cache/tests/move-aware-dummies.hpp
vendored
Normal file
171
src/3rdParty/lru-cache/tests/move-aware-dummies.hpp
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
template <typename SubClassTemplateParameterJustForNewStaticMembersHehehe>
|
||||
struct MoveAwareBase {
|
||||
static std::size_t move_count;
|
||||
static std::size_t non_move_count;
|
||||
static std::size_t forwarding_count;
|
||||
static std::size_t copy_count;
|
||||
|
||||
static void reset() {
|
||||
move_count = 0;
|
||||
non_move_count = 0;
|
||||
forwarding_count = 0;
|
||||
copy_count = 0;
|
||||
}
|
||||
|
||||
MoveAwareBase(const MoveAwareBase& other) : s(other.s) {
|
||||
copy_count += 1;
|
||||
}
|
||||
|
||||
MoveAwareBase(MoveAwareBase&& other) : s(std::move(other.s)) {
|
||||
// Just need to implement so it's not deactivated
|
||||
// (because we do need the copy constructor)
|
||||
}
|
||||
|
||||
MoveAwareBase(std::string&& s_) : s(std::move(s_)) {
|
||||
move_count += 1;
|
||||
}
|
||||
|
||||
MoveAwareBase(std::string& s_) : s(s_) {
|
||||
non_move_count += 1;
|
||||
}
|
||||
|
||||
MoveAwareBase(const char* s_) : s(s_) {
|
||||
forwarding_count += 1;
|
||||
}
|
||||
|
||||
MoveAwareBase(const int& x, const double& y)
|
||||
: s(std::to_string(x) + std::to_string(y)) {
|
||||
non_move_count += 1;
|
||||
}
|
||||
|
||||
MoveAwareBase(int&& x, double&& y)
|
||||
: s(std::to_string(x) + std::to_string(y)) {
|
||||
move_count += 1;
|
||||
}
|
||||
|
||||
virtual ~MoveAwareBase() = default;
|
||||
|
||||
MoveAwareBase& operator=(const MoveAwareBase& other) {
|
||||
copy_count += 1;
|
||||
s = other.s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MoveAwareBase& operator=(MoveAwareBase&& other) {
|
||||
s = std::move(other.s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const MoveAwareBase& other) const noexcept {
|
||||
return this->s == other.s;
|
||||
}
|
||||
|
||||
bool operator!=(const MoveAwareBase& other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::string s;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::size_t MoveAwareBase<T>::move_count = 0;
|
||||
|
||||
template <typename T>
|
||||
std::size_t MoveAwareBase<T>::non_move_count = 0;
|
||||
|
||||
template <typename T>
|
||||
std::size_t MoveAwareBase<T>::forwarding_count = 0;
|
||||
|
||||
template <typename T>
|
||||
std::size_t MoveAwareBase<T>::copy_count = 0;
|
||||
|
||||
struct MoveAwareKey : public MoveAwareBase<MoveAwareKey> {
|
||||
using super = MoveAwareBase<MoveAwareKey>;
|
||||
|
||||
// clang-format off
|
||||
MoveAwareKey() = default;
|
||||
MoveAwareKey(const MoveAwareKey& other) : super(other) {}
|
||||
MoveAwareKey(MoveAwareKey&& other) : super(std::move(other)) {}
|
||||
MoveAwareKey(std::string&& s_) : super(std::move(s_)) {}
|
||||
MoveAwareKey(std::string& s_) : super(s_) {}
|
||||
MoveAwareKey(const char* s_) : super(s_) {}
|
||||
MoveAwareKey(const int& x, const double& y) : super(x, y) {}
|
||||
MoveAwareKey(int&& x, double&& y) : super(std::move(x), std::move(y)) {}
|
||||
// clang-format on
|
||||
|
||||
MoveAwareKey& operator=(const MoveAwareKey& other) {
|
||||
super::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MoveAwareKey& operator=(MoveAwareKey&& other) {
|
||||
super::operator=(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct MoveAwareValue : public MoveAwareBase<MoveAwareValue> {
|
||||
using super = MoveAwareBase<MoveAwareValue>;
|
||||
|
||||
// clang-format off
|
||||
MoveAwareValue() = default;
|
||||
MoveAwareValue(const MoveAwareValue& other) : super(other) {}
|
||||
MoveAwareValue(MoveAwareValue&& other) : super(std::move(other)) {}
|
||||
MoveAwareValue(std::string&& s_) : super(std::move(s_)) {}
|
||||
MoveAwareValue(std::string& s_) : super(s_) {}
|
||||
MoveAwareValue(const char* s_) : super(s_) {}
|
||||
MoveAwareValue(const int& x, const double& y) : super(x, y) {}
|
||||
MoveAwareValue(int&& x, double&& y) : super(std::move(x), std::move(y)) {}
|
||||
// clang-format on
|
||||
|
||||
MoveAwareValue& operator=(const MoveAwareValue& other) {
|
||||
super::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MoveAwareValue& operator=(MoveAwareValue&& other) {
|
||||
super::operator=(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<MoveAwareKey> {
|
||||
auto operator()(const MoveAwareKey& key) const {
|
||||
return hash<std::string>()(key.s);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<MoveAwareValue> {
|
||||
auto operator()(const MoveAwareValue& value) const {
|
||||
return hash<std::string>()(value.s);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
154
src/3rdParty/lru-cache/tests/move-awareness-test.cpp
vendored
Normal file
154
src/3rdParty/lru-cache/tests/move-awareness-test.cpp
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lru/lru.hpp"
|
||||
#include "tests/move-aware-dummies.hpp"
|
||||
|
||||
struct MoveAwarenessTest : public ::testing::Test {
|
||||
MoveAwarenessTest() {
|
||||
MoveAwareKey::reset();
|
||||
MoveAwareValue::reset();
|
||||
}
|
||||
|
||||
LRU::Cache<MoveAwareKey, MoveAwareValue> cache;
|
||||
};
|
||||
|
||||
TEST_F(MoveAwarenessTest, DoesNotMoveForInsert) {
|
||||
cache.insert("x", "y");
|
||||
|
||||
// One construction (right there)
|
||||
ASSERT_EQ(MoveAwareKey::forwarding_count, 1);
|
||||
ASSERT_EQ(MoveAwareValue::forwarding_count, 1);
|
||||
|
||||
ASSERT_EQ(MoveAwareKey::copy_count, 1);
|
||||
|
||||
// Values only go into the map
|
||||
ASSERT_EQ(MoveAwareValue::copy_count, 1);
|
||||
|
||||
// Do this at the end to avoid incrementing the counts
|
||||
ASSERT_EQ(cache["x"], "y");
|
||||
}
|
||||
|
||||
TEST_F(MoveAwarenessTest, ForwardsValuesWell) {
|
||||
cache.emplace("x", "y");
|
||||
|
||||
// One construction to make the key first
|
||||
EXPECT_GE(MoveAwareKey::forwarding_count, 1);
|
||||
EXPECT_GE(MoveAwareValue::forwarding_count, 1);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::copy_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::copy_count, 0);
|
||||
|
||||
ASSERT_EQ(cache["x"], "y");
|
||||
}
|
||||
|
||||
TEST_F(MoveAwarenessTest, MovesSingleRValues) {
|
||||
cache.emplace(std::string("x"), std::string("y"));
|
||||
|
||||
// Move constructions from the string
|
||||
EXPECT_EQ(MoveAwareKey::move_count, 1);
|
||||
EXPECT_EQ(MoveAwareValue::move_count, 1);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::non_move_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::non_move_count, 0);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::copy_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::copy_count, 0);
|
||||
|
||||
ASSERT_EQ(cache["x"], "y");
|
||||
}
|
||||
|
||||
TEST_F(MoveAwarenessTest, CopiesSingleLValues) {
|
||||
std::string x("x");
|
||||
std::string y("y");
|
||||
cache.emplace(x, y);
|
||||
|
||||
// Move constructions from the string
|
||||
EXPECT_EQ(MoveAwareKey::non_move_count, 1);
|
||||
EXPECT_EQ(MoveAwareValue::non_move_count, 1);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::move_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::move_count, 0);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::copy_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::copy_count, 0);
|
||||
|
||||
ASSERT_EQ(cache["x"], "y");
|
||||
}
|
||||
|
||||
TEST_F(MoveAwarenessTest, MovesRValueTuples) {
|
||||
cache.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(1, 3.14),
|
||||
std::forward_as_tuple(2, 2.718));
|
||||
|
||||
// construct_from_tuple performs one move construction
|
||||
// (i.e. construction from rvalues)
|
||||
EXPECT_EQ(MoveAwareKey::move_count, 1);
|
||||
EXPECT_EQ(MoveAwareValue::move_count, 1);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::non_move_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::non_move_count, 0);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::copy_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::copy_count, 0);
|
||||
}
|
||||
|
||||
TEST_F(MoveAwarenessTest, MovesLValueTuples) {
|
||||
int x = 1, z = 2;
|
||||
double y = 3.14, w = 2.718;
|
||||
|
||||
cache.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(x, y),
|
||||
std::forward_as_tuple(z, w));
|
||||
|
||||
// construct_from_tuple will perfom one copy construction
|
||||
// (i.e. construction from lvalues)
|
||||
EXPECT_EQ(MoveAwareKey::non_move_count, 1);
|
||||
EXPECT_EQ(MoveAwareValue::non_move_count, 1);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::move_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::move_count, 0);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::copy_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::copy_count, 0);
|
||||
}
|
||||
|
||||
TEST_F(MoveAwarenessTest, MovesElementsOutOfRValueRanges) {
|
||||
std::vector<std::pair<std::string, std::string>> range = {{"x", "y"}};
|
||||
cache.insert(std::move(range));
|
||||
|
||||
// Move constructions from the string
|
||||
EXPECT_EQ(MoveAwareKey::move_count, 1);
|
||||
EXPECT_EQ(MoveAwareValue::move_count, 1);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::non_move_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::non_move_count, 0);
|
||||
|
||||
EXPECT_EQ(MoveAwareKey::copy_count, 0);
|
||||
EXPECT_EQ(MoveAwareValue::copy_count, 0);
|
||||
|
||||
ASSERT_EQ(cache["x"], "y");
|
||||
}
|
||||
375
src/3rdParty/lru-cache/tests/statistics-test.cpp
vendored
Normal file
375
src/3rdParty/lru-cache/tests/statistics-test.cpp
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "lru/internal/statistics-mutator.hpp"
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace LRU;
|
||||
using namespace LRU::Internal;
|
||||
|
||||
TEST(StatisticsTest, ConstructsWellFromRange) {
|
||||
std::vector<int> range = {1, 2, 3};
|
||||
Statistics<int> stats(range);
|
||||
|
||||
for (const auto& i : range) {
|
||||
ASSERT_TRUE(stats.is_monitoring(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, ConstructsWellFromIterator) {
|
||||
std::vector<int> range = {1, 2, 3};
|
||||
Statistics<int> stats(range.begin(), range.end());
|
||||
|
||||
for (const auto& i : range) {
|
||||
ASSERT_TRUE(stats.is_monitoring(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, ConstructsWellFromInitializerList) {
|
||||
Statistics<int> stats({1, 2, 3});
|
||||
|
||||
std::vector<int> range = {1, 2, 3};
|
||||
for (const auto& i : range) {
|
||||
ASSERT_TRUE(stats.is_monitoring(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, ConstructsWellFromVariadicArguments) {
|
||||
Statistics<int> stats(1, 2, 3);
|
||||
|
||||
std::vector<int> range = {1, 2, 3};
|
||||
for (const auto& i : range) {
|
||||
ASSERT_TRUE(stats.is_monitoring(i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, EmptyPreconditions) {
|
||||
Statistics<int> stats;
|
||||
|
||||
EXPECT_FALSE(stats.is_monitoring_keys());
|
||||
EXPECT_EQ(stats.number_of_monitored_keys(), 0);
|
||||
EXPECT_FALSE(stats.is_monitoring(1));
|
||||
EXPECT_FALSE(stats.is_monitoring(2));
|
||||
EXPECT_EQ(stats.total_accesses(), 0);
|
||||
EXPECT_EQ(stats.total_hits(), 0);
|
||||
EXPECT_EQ(stats.total_misses(), 0);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, StatisticsMutatorCanRegisterHits) {
|
||||
auto stats = std::make_shared<Statistics<int>>(1, 2, 3);
|
||||
StatisticsMutator<int> mutator(stats);
|
||||
|
||||
mutator.register_hit(1);
|
||||
EXPECT_EQ(stats->hits_for(1), 1);
|
||||
EXPECT_EQ(stats->total_accesses(), 1);
|
||||
EXPECT_EQ(stats->total_hits(), 1);
|
||||
EXPECT_EQ(stats->total_misses(), 0);
|
||||
EXPECT_EQ(stats->hit_rate(), 1);
|
||||
EXPECT_EQ(stats->miss_rate(), 0);
|
||||
|
||||
mutator.register_hit(1);
|
||||
EXPECT_EQ(stats->hits_for(1), 2);
|
||||
EXPECT_EQ(stats->total_accesses(), 2);
|
||||
EXPECT_EQ(stats->total_hits(), 2);
|
||||
EXPECT_EQ(stats->total_misses(), 0);
|
||||
EXPECT_EQ(stats->hit_rate(), 1);
|
||||
EXPECT_EQ(stats->miss_rate(), 0);
|
||||
|
||||
mutator.register_hit(2);
|
||||
EXPECT_EQ(stats->hits_for(1), 2);
|
||||
EXPECT_EQ(stats->hits_for(2), 1);
|
||||
EXPECT_EQ(stats->total_accesses(), 3);
|
||||
EXPECT_EQ(stats->total_hits(), 3);
|
||||
EXPECT_EQ(stats->total_misses(), 0);
|
||||
EXPECT_EQ(stats->hit_rate(), 1);
|
||||
EXPECT_EQ(stats->miss_rate(), 0);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, StatisticsMutatorCanRegisterMisses) {
|
||||
auto stats = std::make_shared<Statistics<int>>(1, 2, 3);
|
||||
StatisticsMutator<int> mutator(stats);
|
||||
|
||||
mutator.register_miss(1);
|
||||
EXPECT_EQ(stats->misses_for(1), 1);
|
||||
EXPECT_EQ(stats->total_accesses(), 1);
|
||||
EXPECT_EQ(stats->total_hits(), 0);
|
||||
EXPECT_EQ(stats->total_misses(), 1);
|
||||
EXPECT_EQ(stats->hit_rate(), 0);
|
||||
EXPECT_EQ(stats->miss_rate(), 1);
|
||||
|
||||
mutator.register_miss(1);
|
||||
EXPECT_EQ(stats->misses_for(1), 2);
|
||||
EXPECT_EQ(stats->total_accesses(), 2);
|
||||
EXPECT_EQ(stats->total_hits(), 0);
|
||||
EXPECT_EQ(stats->total_misses(), 2);
|
||||
EXPECT_EQ(stats->hit_rate(), 0);
|
||||
EXPECT_EQ(stats->miss_rate(), 1);
|
||||
|
||||
mutator.register_miss(2);
|
||||
EXPECT_EQ(stats->misses_for(1), 2);
|
||||
EXPECT_EQ(stats->misses_for(2), 1);
|
||||
EXPECT_EQ(stats->total_accesses(), 3);
|
||||
EXPECT_EQ(stats->total_hits(), 0);
|
||||
EXPECT_EQ(stats->total_misses(), 3);
|
||||
EXPECT_EQ(stats->hit_rate(), 0);
|
||||
EXPECT_EQ(stats->miss_rate(), 1);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, CanDynamicallyMonitorAndUnmonitorKeys) {
|
||||
Statistics<int> stats;
|
||||
|
||||
ASSERT_EQ(stats.number_of_monitored_keys(), 0);
|
||||
|
||||
stats.monitor(1);
|
||||
|
||||
EXPECT_EQ(stats.number_of_monitored_keys(), 1);
|
||||
EXPECT_TRUE(stats.is_monitoring(1));
|
||||
EXPECT_FALSE(stats.is_monitoring(2));
|
||||
|
||||
stats.monitor(2);
|
||||
|
||||
EXPECT_EQ(stats.number_of_monitored_keys(), 2);
|
||||
EXPECT_TRUE(stats.is_monitoring(1));
|
||||
EXPECT_TRUE(stats.is_monitoring(2));
|
||||
|
||||
stats.unmonitor(1);
|
||||
|
||||
EXPECT_EQ(stats.number_of_monitored_keys(), 1);
|
||||
EXPECT_FALSE(stats.is_monitoring(1));
|
||||
EXPECT_TRUE(stats.is_monitoring(2));
|
||||
|
||||
stats.unmonitor_all();
|
||||
|
||||
EXPECT_FALSE(stats.is_monitoring_keys());
|
||||
EXPECT_FALSE(stats.is_monitoring(1));
|
||||
EXPECT_FALSE(stats.is_monitoring(2));
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, ThrowsForUnmonitoredKey) {
|
||||
Statistics<int> stats;
|
||||
|
||||
EXPECT_THROW(stats.stats_for(1), LRU::Error::UnmonitoredKey);
|
||||
EXPECT_THROW(stats.hits_for(2), LRU::Error::UnmonitoredKey);
|
||||
EXPECT_THROW(stats.misses_for(3), LRU::Error::UnmonitoredKey);
|
||||
EXPECT_THROW(stats[4], LRU::Error::UnmonitoredKey);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, RatesAreCalculatedCorrectly) {
|
||||
auto stats = std::make_shared<Statistics<int>>(1, 2, 3);
|
||||
StatisticsMutator<int> mutator(stats);
|
||||
|
||||
for (std::size_t i = 0; i < 20; ++i) {
|
||||
mutator.register_hit(1);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < 80; ++i) {
|
||||
mutator.register_miss(1);
|
||||
}
|
||||
|
||||
EXPECT_EQ(stats->hit_rate(), 0.2);
|
||||
EXPECT_EQ(stats->miss_rate(), 0.8);
|
||||
}
|
||||
|
||||
TEST(StatisticsTest, CanShareStatistics) {
|
||||
auto stats = std::make_shared<Statistics<int>>(1, 2, 3);
|
||||
StatisticsMutator<int> mutator1(stats);
|
||||
StatisticsMutator<int> mutator2(stats);
|
||||
StatisticsMutator<int> mutator3(stats);
|
||||
|
||||
ASSERT_EQ(mutator1.shared(), mutator2.shared());
|
||||
ASSERT_EQ(mutator2.shared(), mutator3.shared());
|
||||
ASSERT_EQ(&mutator2.get(), &mutator3.get());
|
||||
|
||||
mutator1.register_hit(1);
|
||||
EXPECT_EQ(stats->total_accesses(), 1);
|
||||
EXPECT_EQ(stats->total_hits(), 1);
|
||||
EXPECT_EQ(stats->total_misses(), 0);
|
||||
EXPECT_EQ(stats->hits_for(1), 1);
|
||||
|
||||
mutator2.register_hit(1);
|
||||
EXPECT_EQ(stats->total_accesses(), 2);
|
||||
EXPECT_EQ(stats->total_hits(), 2);
|
||||
EXPECT_EQ(stats->total_misses(), 0);
|
||||
EXPECT_EQ(stats->hits_for(1), 2);
|
||||
|
||||
mutator3.register_miss(2);
|
||||
EXPECT_EQ(stats->total_accesses(), 3);
|
||||
EXPECT_EQ(stats->total_hits(), 2);
|
||||
EXPECT_EQ(stats->total_misses(), 1);
|
||||
EXPECT_EQ(stats->hits_for(1), 2);
|
||||
EXPECT_EQ(stats->misses_for(1), 0);
|
||||
EXPECT_EQ(stats->hits_for(2), 0);
|
||||
EXPECT_EQ(stats->misses_for(2), 1);
|
||||
}
|
||||
|
||||
struct CacheWithStatisticsTest : public ::testing::Test {
|
||||
void assert_total_stats(int accesses, int hits, int misses) {
|
||||
ASSERT_EQ(cache.stats().total_accesses(), accesses);
|
||||
ASSERT_EQ(cache.stats().total_hits(), hits);
|
||||
ASSERT_EQ(cache.stats().total_misses(), misses);
|
||||
}
|
||||
|
||||
void expect_total_stats(int accesses, int hits, int misses) {
|
||||
EXPECT_EQ(cache.stats().total_accesses(), accesses);
|
||||
EXPECT_EQ(cache.stats().total_hits(), hits);
|
||||
EXPECT_EQ(cache.stats().total_misses(), misses);
|
||||
}
|
||||
|
||||
Cache<int, int> cache;
|
||||
};
|
||||
|
||||
TEST_F(CacheWithStatisticsTest,
|
||||
RequestForCacheStatisticsThrowsWhenNoneRegistered) {
|
||||
EXPECT_THROW(cache.stats(), LRU::Error::NotMonitoring);
|
||||
}
|
||||
|
||||
TEST_F(CacheWithStatisticsTest, CanRegisterLValueStatistics) {
|
||||
auto stats = std::make_shared<Statistics<int>>();
|
||||
cache.monitor(stats);
|
||||
|
||||
EXPECT_TRUE(cache.is_monitoring());
|
||||
|
||||
// This is a strong constraint, but must hold for lvalue stats object
|
||||
EXPECT_EQ(&cache.stats(), &*stats);
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(cache.shared_stats()->total_accesses(), 1);
|
||||
EXPECT_EQ(cache.stats().total_misses(), 1);
|
||||
|
||||
cache.emplace(1, 2);
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(cache.stats().total_accesses(), 2);
|
||||
EXPECT_EQ(cache.stats().total_misses(), 1);
|
||||
EXPECT_EQ(cache.stats().total_hits(), 1);
|
||||
}
|
||||
|
||||
TEST_F(CacheWithStatisticsTest, CanRegisterRValueStatistics) {
|
||||
auto s = std::make_unique<Statistics<int>>(1);
|
||||
cache.monitor(std::move(s));
|
||||
|
||||
EXPECT_TRUE(cache.is_monitoring());
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(cache.stats().total_accesses(), 1);
|
||||
EXPECT_EQ(cache.stats().total_misses(), 1);
|
||||
|
||||
cache.emplace(1, 2);
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(cache.stats().total_accesses(), 2);
|
||||
EXPECT_EQ(cache.stats().total_misses(), 1);
|
||||
EXPECT_EQ(cache.stats().total_hits(), 1);
|
||||
}
|
||||
|
||||
TEST_F(CacheWithStatisticsTest, CanConstructItsOwnStatistics) {
|
||||
cache.monitor(1, 2, 3);
|
||||
|
||||
EXPECT_TRUE(cache.is_monitoring());
|
||||
EXPECT_TRUE(cache.stats().is_monitoring(1));
|
||||
EXPECT_TRUE(cache.stats().is_monitoring(2));
|
||||
EXPECT_TRUE(cache.stats().is_monitoring(3));
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(cache.stats().total_accesses(), 1);
|
||||
EXPECT_EQ(cache.stats().total_misses(), 1);
|
||||
|
||||
cache.emplace(1, 2);
|
||||
|
||||
cache.contains(1);
|
||||
EXPECT_EQ(cache.stats().total_accesses(), 2);
|
||||
EXPECT_EQ(cache.stats().total_misses(), 1);
|
||||
EXPECT_EQ(cache.stats().total_hits(), 1);
|
||||
}
|
||||
|
||||
TEST_F(CacheWithStatisticsTest, KnowsWhenItIsMonitoring) {
|
||||
EXPECT_FALSE(cache.is_monitoring());
|
||||
|
||||
cache.monitor();
|
||||
|
||||
EXPECT_TRUE(cache.is_monitoring());
|
||||
|
||||
cache.stop_monitoring();
|
||||
|
||||
EXPECT_FALSE(cache.is_monitoring());
|
||||
}
|
||||
|
||||
TEST_F(CacheWithStatisticsTest, StatisticsWorkWithCache) {
|
||||
cache.monitor(1);
|
||||
ASSERT_TRUE(cache.is_monitoring());
|
||||
assert_total_stats(0, 0, 0);
|
||||
|
||||
// contains
|
||||
cache.contains(1);
|
||||
expect_total_stats(1, 0, 1);
|
||||
|
||||
// An access should only occur for lookup(),
|
||||
// find(), contains() and operator[]
|
||||
cache.emplace(1, 1);
|
||||
expect_total_stats(1, 0, 1);
|
||||
|
||||
cache.contains(1);
|
||||
expect_total_stats(2, 1, 1);
|
||||
|
||||
// find
|
||||
cache.find(2);
|
||||
expect_total_stats(3, 1, 2);
|
||||
|
||||
cache.emplace(2, 2);
|
||||
|
||||
cache.find(2);
|
||||
expect_total_stats(4, 2, 2);
|
||||
|
||||
EXPECT_THROW(cache.lookup(3), LRU::Error::KeyNotFound);
|
||||
expect_total_stats(5, 2, 3);
|
||||
|
||||
cache.emplace(3, 3);
|
||||
|
||||
ASSERT_EQ(cache.lookup(3), 3);
|
||||
expect_total_stats(6, 3, 3);
|
||||
|
||||
EXPECT_THROW(cache[4], LRU::Error::KeyNotFound);
|
||||
expect_total_stats(7, 3, 4);
|
||||
|
||||
cache.emplace(4, 4);
|
||||
|
||||
ASSERT_EQ(cache[4], 4);
|
||||
expect_total_stats(8, 4, 4);
|
||||
}
|
||||
|
||||
TEST_F(CacheWithStatisticsTest, StopsMonitoringWhenAsked) {
|
||||
auto stats = std::make_shared<Statistics<int>>(1);
|
||||
cache.monitor(stats);
|
||||
cache.emplace(1, 1);
|
||||
|
||||
ASSERT_TRUE(cache.contains(1));
|
||||
ASSERT_EQ(cache.stats().hits_for(1), 1);
|
||||
|
||||
cache.stop_monitoring();
|
||||
|
||||
ASSERT_TRUE(cache.contains(1));
|
||||
EXPECT_EQ(stats->hits_for(1), 1);
|
||||
}
|
||||
177
src/3rdParty/lru-cache/tests/timed-cache-test.cpp
vendored
Normal file
177
src/3rdParty/lru-cache/tests/timed-cache-test.cpp
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <chrono>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
using namespace LRU;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST(TimedCacheTest, ContainsRespectsExpiration) {
|
||||
TimedCache<int, int> cache(2ms);
|
||||
|
||||
cache.insert(1, 2);
|
||||
ASSERT_EQ(cache.size(), 1);
|
||||
ASSERT_TRUE(cache.contains(1));
|
||||
ASSERT_EQ(cache[1], 2);
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_TRUE(cache.contains(1));
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_FALSE(cache.contains(1));
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, KnowsWhenAllKeysHaveExpired) {
|
||||
TimedCache<int, int> cache(2ms);
|
||||
|
||||
ASSERT_TRUE(cache.all_expired());
|
||||
|
||||
cache = {{1, 2}, {2, 3}};
|
||||
|
||||
ASSERT_EQ(cache.size(), 2);
|
||||
ASSERT_FALSE(cache.all_expired());
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
cache.insert(3, 4);
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_FALSE(cache.all_expired());
|
||||
EXPECT_FALSE(cache.contains(1));
|
||||
EXPECT_FALSE(cache.contains(2));
|
||||
EXPECT_TRUE(cache.contains(3));
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_TRUE(cache.all_expired());
|
||||
EXPECT_FALSE(cache.contains(1));
|
||||
EXPECT_FALSE(cache.contains(2));
|
||||
EXPECT_FALSE(cache.contains(3));
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, CleanExpiredRemovesExpiredElements) {
|
||||
TimedCache<int, int> cache(2ms, 128, {{1, 2}, {2, 3}});
|
||||
|
||||
ASSERT_EQ(cache.size(), 2);
|
||||
ASSERT_FALSE(cache.all_expired());
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
cache.insert(3, 4);
|
||||
ASSERT_EQ(cache.size(), 3);
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
ASSERT_EQ(cache.size(), 3);
|
||||
|
||||
cache.clear_expired();
|
||||
|
||||
EXPECT_EQ(cache.size(), 1);
|
||||
EXPECT_FALSE(cache.contains(1));
|
||||
EXPECT_FALSE(cache.contains(2));
|
||||
EXPECT_TRUE(cache.contains(3));
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
cache.clear_expired();
|
||||
|
||||
EXPECT_FALSE(cache.contains(3));
|
||||
EXPECT_EQ(cache.size(), 0);
|
||||
EXPECT_TRUE(cache.is_empty());
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, LookupThrowsWhenKeyExpired) {
|
||||
TimedCache<int, int> cache(2ms, 128, {{1, 2}});
|
||||
|
||||
ASSERT_EQ(cache.lookup(1), 2);
|
||||
|
||||
std::this_thread::sleep_for(2ms);
|
||||
|
||||
ASSERT_THROW(cache.lookup(1), LRU::Error::KeyExpired);
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, HasExpiredReturnsFalseForNonContainedKeys) {
|
||||
TimedCache<int, int> cache(2ms);
|
||||
|
||||
EXPECT_FALSE(cache.has_expired(1));
|
||||
EXPECT_FALSE(cache.has_expired(2));
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, HasExpiredReturnsFalseForContainedButNotExpiredKeys) {
|
||||
TimedCache<int, int> cache(100ms);
|
||||
|
||||
cache.emplace(1, 1);
|
||||
cache.emplace(2, 2);
|
||||
|
||||
EXPECT_FALSE(cache.has_expired(1));
|
||||
EXPECT_FALSE(cache.has_expired(2));
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, HasExpiredReturnsTrueForContainedAndExpiredKeys) {
|
||||
TimedCache<int, int> cache(2ms);
|
||||
|
||||
cache.emplace(1, 1);
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
cache.emplace(2, 2);
|
||||
|
||||
EXPECT_FALSE(cache.has_expired(1));
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_TRUE(cache.has_expired(1));
|
||||
EXPECT_FALSE(cache.has_expired(2));
|
||||
|
||||
std::this_thread::sleep_for(3ms);
|
||||
|
||||
EXPECT_TRUE(cache.has_expired(1));
|
||||
EXPECT_TRUE(cache.has_expired(2));
|
||||
}
|
||||
|
||||
TEST(TimedCacheTest, LookupsMoveElementsToFront) {
|
||||
TimedCache<std::string, int> cache(1s);
|
||||
|
||||
cache.capacity(2);
|
||||
cache.insert({{"one", 1}, {"two", 2}});
|
||||
|
||||
// The LRU principle mandates that lookups place
|
||||
// accessed elements to the front. So when we look at
|
||||
// one it should move to the front.
|
||||
|
||||
auto iterator = cache.find("one");
|
||||
cache.emplace("three", 3);
|
||||
|
||||
EXPECT_TRUE(cache.contains("one"));
|
||||
EXPECT_FALSE(cache.contains("two"));
|
||||
EXPECT_TRUE(cache.contains("three"));
|
||||
EXPECT_EQ(++iterator, cache.end());
|
||||
}
|
||||
90
src/3rdParty/lru-cache/tests/wrap-test.cpp
vendored
Normal file
90
src/3rdParty/lru-cache/tests/wrap-test.cpp
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
/// The MIT License (MIT)
|
||||
/// Copyright (c) 2016 Peter Goldsborough
|
||||
///
|
||||
/// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
/// of this software and associated documentation files (the "Software"), to
|
||||
/// deal in the Software without restriction, including without limitation the
|
||||
/// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
/// sell copies of the Software, and to permit persons to whom the Software is
|
||||
/// furnished to do so, subject to the following conditions:
|
||||
///
|
||||
/// The above copyright notice and this permission notice shall be included in
|
||||
/// all copies or substantial portions of the Software.
|
||||
///
|
||||
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
/// IN THE SOFTWARE.
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "lru/lru.hpp"
|
||||
|
||||
TEST(WrapTest, CanWrapMutableAndNonMutableLambdas) {
|
||||
// This is purely to make sure both variants compile
|
||||
LRU::wrap([](int x) { return x; })(5);
|
||||
LRU::wrap([](int x) mutable { return x; })(5);
|
||||
}
|
||||
|
||||
TEST(WrapTest, WrappingWorks) {
|
||||
auto f = [x = 0](int _) mutable {
|
||||
return ++x;
|
||||
};
|
||||
auto wrapped = LRU::wrap(f);
|
||||
|
||||
EXPECT_EQ(wrapped(69), 1);
|
||||
EXPECT_EQ(wrapped(69), 1);
|
||||
EXPECT_EQ(wrapped(42), 2);
|
||||
EXPECT_EQ(wrapped(42), 2);
|
||||
EXPECT_EQ(wrapped(50), 3);
|
||||
}
|
||||
|
||||
TEST(WrapTest, CanPassCapacityArgumentToWrap) {
|
||||
std::size_t call_count = 0;
|
||||
auto f = [&call_count](int _) { return call_count += 1; };
|
||||
|
||||
auto wrapped1 = LRU::wrap(f, 1);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
|
||||
auto wrapped2 = LRU::wrap(f, 0);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
}
|
||||
|
||||
|
||||
TEST(WrapTest, CanPassTimeArgumentToTimedCacheWrap) {
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
std::size_t call_count = 0;
|
||||
auto f = [&call_count](int _) { return call_count += 1; };
|
||||
|
||||
auto wrapped1 = LRU::wrap<decltype(f), LRU::TimedCache>(f, 100ms);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
|
||||
auto wrapped2 = LRU::timed_wrap(f, 0ms);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
|
||||
wrapped1(1);
|
||||
EXPECT_EQ(call_count, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user