mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-24 17:41:39 +08:00
MODIFIED JKQTPDataCache to implement a limited-size cache with least-recently-used delete stategy
This commit is contained in:
parent
868d6dcdf4
commit
1bf6c43134
@ -97,10 +97,10 @@ This test results in the following numbers (on my AMD Ryzen5 8/16-core laptop):
|
||||
<b>VERSION:</b> 5.0.0
|
||||
<b>BUILD MODE:</b> Release
|
||||
|
||||
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 2336.7ms<br/>single runtimes = (97.3 +/- 158.4) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/><br/>
|
||||
<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 4241.3ms<br/>single runtimes = (176.7 +/- 319.6) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/><br/>
|
||||
|
||||
<u><b>PARALLEL RESULTS:</b></u><br/>
|
||||
runtime, overall = 527.2ms<br/>single runtimes = (166.4 +/- 8.1) ms<br/>speedup = 7.58x<br/>threads / available = 8 / 16<br/>batch runs = 3<br/><br/><b>speedup vs. serial = 4.4x</b>
|
||||
runtime, overall = 1025.3ms<br/>single runtimes = (325.0 +/- 15.0) ms<br/>speedup = 7.61x<br/>threads / available = 8 / 16<br/>batch runs = 3<br/><br/><b>speedup vs. serial = 4.1x</b>
|
||||
|
||||
[comment]:RESULTS_END
|
||||
|
||||
|
@ -25,10 +25,24 @@
|
||||
#define JKQTPCACHINGTOOLS_H
|
||||
|
||||
#include "jkqtcommon/jkqtcommon_imexport.h"
|
||||
#include "jkqtcommon/jkqtpmathtools.h"
|
||||
#include <QReadWriteLock>
|
||||
#include <QReadLocker>
|
||||
#include <QWriteLocker>
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
/** \brief tag type to configure JKQTPDataCache for thread-safety
|
||||
* \ingroup jkqtptools_concurrency
|
||||
*/
|
||||
struct JKQTPDataCacheThreadSafe {};
|
||||
/** \brief tag type to configure JKQTPDataCache for non thread-safety
|
||||
* \ingroup jkqtptools_concurrency
|
||||
*/
|
||||
struct JKQTPDataCacheNotThreadSafe {};
|
||||
|
||||
/** \brief this class can be used to implement a general cache for values
|
||||
* \ingroup jkqtptools_concurrency
|
||||
@ -45,51 +59,132 @@
|
||||
*
|
||||
* Internally the cache maps TKey to TData, but the signature of the get()-function and the generator functor actually uses TKeyInSignature,
|
||||
* which may differ from TKey. The only limitation is that TKeyInSignature can be converted/assigned to a TKey
|
||||
*
|
||||
* The cache has a maximmum size m_maxEntries.
|
||||
* When you try to add a new object, after which the size would grow beyond this, a fraction 1-m_retainFraction of elements are
|
||||
* deleted from the cache. The delete strategy is least-recently used (LRU). In order to immplement this, the cache keeps track of
|
||||
* the last use timestamp of each entry.
|
||||
*
|
||||
* You can deactivate the cleaning by setting m_maxEntries<0, but the the cache may grow indefinitely and there is possibly undefined behaviour
|
||||
* when add one too many items!
|
||||
*/
|
||||
template <class TData, class TKey, bool ThreadSafe=true, class TKeyInSignature=TKey>
|
||||
template <class TData, class TKey, typename ThreadSafe=JKQTPDataCacheThreadSafe, class TKeyInSignature=TKey>
|
||||
struct JKQTPDataCache {
|
||||
template <typename FF>
|
||||
inline JKQTPDataCache(FF generateData):
|
||||
m_generateData(std::forward<FF>(generateData))
|
||||
inline JKQTPDataCache(FF generateData, int maxEntries=10000, double retainFraction=0.8):
|
||||
m_maxEntries(maxEntries), m_retainFraction(retainFraction), m_generateData(std::forward<FF>(generateData))
|
||||
{
|
||||
|
||||
}
|
||||
JKQTPDataCache()=delete;
|
||||
JKQTPDataCache(const JKQTPDataCache&)=delete;
|
||||
JKQTPDataCache& operator=(const JKQTPDataCache&)=delete;
|
||||
JKQTPDataCache(JKQTPDataCache&&)=default;
|
||||
JKQTPDataCache& operator=(JKQTPDataCache&&)=default;
|
||||
|
||||
template<class... Args>
|
||||
inline TData get_inline(Args... args) {
|
||||
return get(TKeyInSignature(args...));
|
||||
}
|
||||
|
||||
template <bool TSS=ThreadSafe>
|
||||
inline TData get(const typename std::enable_if<TSS, TKeyInSignature>::type& key) {
|
||||
template <typename TSS=ThreadSafe>
|
||||
inline TData get(const typename std::enable_if<std::is_same<JKQTPDataCacheThreadSafe, TSS>::value, TKeyInSignature>::type& key) {
|
||||
const TKey cacheKey=key;
|
||||
|
||||
QReadLocker lockR(&m_mutex);
|
||||
if (m_cache.contains(cacheKey)) return m_cache[cacheKey];
|
||||
auto it=m_cache.find(cacheKey);
|
||||
if (m_cache.end()!=it) {
|
||||
m_cacheLastUseTimestamps[cacheKey]->exchange(currenTimestamp());
|
||||
return it->second;
|
||||
}
|
||||
lockR.unlock();
|
||||
|
||||
QWriteLocker lockW(&m_mutex);
|
||||
if (m_cache.contains(cacheKey)) return m_cache[cacheKey];
|
||||
|
||||
it=m_cache.find(cacheKey);
|
||||
if (m_cache.end()!=it) {
|
||||
m_cacheLastUseTimestamps.at(cacheKey)->exchange(currenTimestamp());
|
||||
return it->second;
|
||||
}
|
||||
if (m_maxEntries>0 && m_cache.size()>=static_cast<size_t>(m_maxEntries)) cleanCache_notThreadSafe();
|
||||
m_cacheLastUseTimestamps.emplace(cacheKey, std::make_shared<std::atomic<int64_t>>(currenTimestamp()));
|
||||
const auto newData=m_generateData(key);
|
||||
m_cache[cacheKey]=newData;
|
||||
m_cache.emplace(cacheKey,newData);
|
||||
return newData;
|
||||
}
|
||||
|
||||
template <bool TSS=ThreadSafe>
|
||||
inline TData get(const typename std::enable_if<!TSS, TKeyInSignature>::type& key) {
|
||||
template <typename TSS=ThreadSafe>
|
||||
inline TData get(const typename std::enable_if<std::is_same<JKQTPDataCacheNotThreadSafe, TSS>::value, TKeyInSignature>::type& key) {
|
||||
const TKey cacheKey=key;
|
||||
|
||||
if (m_cache.contains(cacheKey)) return m_cache[cacheKey];
|
||||
auto it=m_cache.find(cacheKey);
|
||||
if (m_cache.end()!=it) {
|
||||
m_cacheLastUseTimestamps[cacheKey]->exchange(currenTimestamp());
|
||||
return it->second;
|
||||
}
|
||||
if (m_maxEntries>0 && m_cache.size()>=static_cast<size_t>(m_maxEntries)) cleanCache_notThreadSafe();
|
||||
const auto newData=m_generateData(key);
|
||||
m_cache[cacheKey]=newData;
|
||||
m_cache.emplace(cacheKey,newData);
|
||||
m_cacheLastUseTimestamps.emplace(cacheKey, std::make_shared<std::atomic<int64_t>>(currenTimestamp()));
|
||||
return newData;
|
||||
}
|
||||
|
||||
template <typename TSS=ThreadSafe>
|
||||
inline bool contains(const typename std::enable_if<std::is_same<JKQTPDataCacheThreadSafe, TSS>::value, TKeyInSignature>::type& key) const {
|
||||
const TKey cacheKey=key;
|
||||
|
||||
QReadLocker lockR(&m_mutex);
|
||||
return m_cache.find(cacheKey)!=m_cache.end();
|
||||
}
|
||||
|
||||
template <typename TSS=ThreadSafe>
|
||||
inline bool contains(const typename std::enable_if<std::is_same<JKQTPDataCacheNotThreadSafe, TSS>::value, TKeyInSignature>::type& key) const {
|
||||
const TKey cacheKey=key;
|
||||
return m_cache.find(cacheKey)!=m_cache.end();
|
||||
}
|
||||
|
||||
|
||||
inline int size() const {
|
||||
return size_impl<ThreadSafe>();
|
||||
}
|
||||
|
||||
private:
|
||||
QHash<TKey, TData> m_cache;
|
||||
mutable typename std::enable_if<ThreadSafe, QReadWriteLock>::type m_mutex;
|
||||
template <typename TSS>
|
||||
inline typename std::enable_if<std::is_same<JKQTPDataCacheThreadSafe, TSS>::value, int>::type size_impl() const {
|
||||
QReadLocker lockR(&m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
template <typename TSS>
|
||||
inline typename std::enable_if<std::is_same<JKQTPDataCacheNotThreadSafe, TSS>::value, int>::type size_impl() const {
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
/** \brief generate a timestamp */
|
||||
static inline int64_t currenTimestamp() {
|
||||
static auto firstTime=std::chrono::steady_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now()-firstTime).count();
|
||||
}
|
||||
/** \brief clean the cache, so at m_retainFraction*m_maxEntries entries remain. */
|
||||
inline void cleanCache_notThreadSafe() {
|
||||
if (m_maxEntries<0 || m_cache.size()<static_cast<size_t>(m_maxEntries)) return;
|
||||
const int deleteItems=jkqtp_boundedRoundTo<int>(1, (1.0-m_retainFraction)*static_cast<double>(m_cache.size()), m_cache.size());
|
||||
QList<QPair<TKey,int64_t> > allItems;
|
||||
allItems.reserve(m_cacheLastUseTimestamps.size());
|
||||
for (auto it=m_cacheLastUseTimestamps.begin(); it!=m_cacheLastUseTimestamps.end(); ++it) {
|
||||
allItems.emplaceBack(it->first, it->second->load());
|
||||
}
|
||||
std::sort(allItems.begin(), allItems.end(), [](const QPair<TKey,int64_t>&a, const QPair<TKey,int64_t>&b) {return a.second>b.second;});
|
||||
for (int i=0; i<deleteItems; i++) {
|
||||
m_cache.erase(allItems[i].first);
|
||||
m_cacheLastUseTimestamps.erase(allItems[i].first);
|
||||
}
|
||||
}
|
||||
const int m_maxEntries;
|
||||
const double m_retainFraction;
|
||||
std::unordered_map<TKey, TData> m_cache;
|
||||
std::unordered_map<TKey, std::shared_ptr<std::atomic<int64_t>>> m_cacheLastUseTimestamps;
|
||||
mutable QReadWriteLock m_mutex;
|
||||
const std::function<TData(TKeyInSignature)> m_generateData;
|
||||
Q_DISABLE_COPY(JKQTPDataCache)
|
||||
};
|
||||
|
||||
#endif // JKQTPCACHINGTOOLS_H
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <QFont>
|
||||
#include <QReadWriteLock>
|
||||
#include <mutex>
|
||||
#include <functional>
|
||||
|
||||
|
||||
void initJKQTMathTextResources()
|
||||
@ -884,6 +885,9 @@ QPainterPath JKQTMathTextMakeHBracePath(double x, double ybrace, double width, d
|
||||
namespace {
|
||||
|
||||
struct JKQTMathTextCacheKeyBase {
|
||||
JKQTMathTextCacheKeyBase():
|
||||
f(), ldpiX(0), ldpiY(0), pdpiX(0), pdpiY(0)
|
||||
{}
|
||||
inline explicit JKQTMathTextCacheKeyBase(const QFont& f_, QPaintDevice *pd):
|
||||
f(f_)
|
||||
{
|
||||
@ -904,7 +908,12 @@ namespace {
|
||||
|
||||
inline bool operator==(const JKQTMathTextCacheKeyBase& other) const{
|
||||
return ldpiX==other.ldpiX && ldpiY==other.ldpiY && pdpiX==other.pdpiX && pdpiY==other.pdpiY && f==other.f;
|
||||
|
||||
};
|
||||
inline bool operator<(const JKQTMathTextCacheKeyBase& other) const{
|
||||
return ldpiX<other.ldpiX && ldpiY<other.ldpiY && pdpiX<other.pdpiX && pdpiY<other.pdpiY && f<other.f;
|
||||
};
|
||||
inline bool operator!=(const JKQTMathTextCacheKeyBase& other) const{
|
||||
return !operator==(other);
|
||||
};
|
||||
};
|
||||
|
||||
@ -931,6 +940,9 @@ namespace {
|
||||
|
||||
template <class TText=QString>
|
||||
struct JKQTMathTextTBRDataH: public JKQTMathTextCacheKeyBase {
|
||||
JKQTMathTextTBRDataH():
|
||||
JKQTMathTextCacheKeyBase(), text("")
|
||||
{}
|
||||
inline explicit JKQTMathTextTBRDataH(const QFont& f_, const TText& text_, QPaintDevice *pd):
|
||||
JKQTMathTextCacheKeyBase(f_, pd), text(text_)
|
||||
{
|
||||
@ -940,7 +952,12 @@ namespace {
|
||||
|
||||
inline bool operator==(const JKQTMathTextTBRDataH& other) const{
|
||||
return JKQTMathTextCacheKeyBase::operator==(other) && text==other.text;
|
||||
|
||||
};
|
||||
inline bool operator!=(const JKQTMathTextTBRDataH& other) const{
|
||||
return JKQTMathTextCacheKeyBase::operator!=(other) && text!=other.text;
|
||||
};
|
||||
inline bool operator<(const JKQTMathTextTBRDataH& other) const{
|
||||
return JKQTMathTextCacheKeyBase::operator<(other) && text<other.text;
|
||||
};
|
||||
};
|
||||
|
||||
@ -967,13 +984,41 @@ namespace {
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct std::hash<JKQTMathTextCacheKeyBase>
|
||||
{
|
||||
std::size_t operator()(const JKQTMathTextCacheKeyBase& data) const noexcept
|
||||
{
|
||||
return qHash(data.f)+std::hash<int>()(data.ldpiX)+std::hash<int>()(data.ldpiY)+std::hash<int>()(data.pdpiX)+std::hash<int>()(data.pdpiY);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct std::hash<JKQTMathTextTBRDataH<QString>>
|
||||
{
|
||||
std::size_t operator()(const JKQTMathTextTBRDataH<QString>& data) const noexcept
|
||||
{
|
||||
return qHash(data.f)+qHash(data.text)+std::hash<int>()(data.ldpiX)+std::hash<int>()(data.ldpiY)+std::hash<int>()(data.pdpiX)+std::hash<int>()(data.pdpiY);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::hash<JKQTMathTextTBRDataH<QChar>>
|
||||
{
|
||||
std::size_t operator()(const JKQTMathTextTBRDataH<QChar>& data) const noexcept
|
||||
{
|
||||
return qHash(data.f)+qHash(data.text)+std::hash<int>()(data.ldpiX)+std::hash<int>()(data.ldpiY)+std::hash<int>()(data.pdpiX)+std::hash<int>()(data.pdpiY);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
QRectF JKQTMathTextGetTightBoundingRect(const QFont &f, const QString &text, QPaintDevice *pd)
|
||||
{
|
||||
//thread_local JKQTPDataCache<QRectF,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
|
||||
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
|
||||
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,JKQTPDataCacheThreadSafe,JKQTMathTextTBRDataHExt<QString>> cache(
|
||||
[](const JKQTMathTextTBRDataHExt<QString>& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.tightBoundingRect(key.text);
|
||||
@ -986,7 +1031,7 @@ QRectF JKQTMathTextGetTightBoundingRect(const QFont &f, const QString &text, QPa
|
||||
QRectF JKQTMathTextGetBoundingRect(const QFont &f, const QString &text, QPaintDevice *pd)
|
||||
{
|
||||
//thread_local JKQTPDataCache<QRectF,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
|
||||
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
|
||||
static JKQTPDataCache<QRectF,JKQTMathTextTBRDataH<QString>,JKQTPDataCacheThreadSafe,JKQTMathTextTBRDataHExt<QString>> cache(
|
||||
[](const JKQTMathTextTBRDataHExt<QString>& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.boundingRect(key.text);
|
||||
@ -999,7 +1044,7 @@ QRectF JKQTMathTextGetBoundingRect(const QFont &f, const QString &text, QPaintDe
|
||||
qreal JKQTMathTextGetHorAdvance(const QFont &f, const QString &text, QPaintDevice *pd)
|
||||
{
|
||||
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QString>,true,JKQTMathTextTBRDataHExt<QString>> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QString>,JKQTPDataCacheThreadSafe,JKQTMathTextTBRDataHExt<QString>> cache(
|
||||
[](const JKQTMathTextTBRDataHExt<QString>& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
#if (QT_VERSION>=QT_VERSION_CHECK(5, 15, 0))
|
||||
@ -1016,7 +1061,7 @@ qreal JKQTMathTextGetHorAdvance(const QFont &f, const QString &text, QPaintDevic
|
||||
qreal JKQTMathTextGetRightBearing(const QFont &f, const QChar &text, QPaintDevice *pd)
|
||||
{
|
||||
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,true,JKQTMathTextTBRDataHExt<QChar>> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,JKQTPDataCacheThreadSafe,JKQTMathTextTBRDataHExt<QChar>> cache(
|
||||
[](const JKQTMathTextTBRDataHExt<QChar>& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.rightBearing(key.text);
|
||||
@ -1028,7 +1073,7 @@ qreal JKQTMathTextGetRightBearing(const QFont &f, const QChar &text, QPaintDevic
|
||||
qreal JKQTMathTextGetLeftBearing(const QFont &f, const QChar &text, QPaintDevice *pd)
|
||||
{
|
||||
//thread_local JKQTPDataCache<double,JKQTMathTextTBRDataH,false,JKQTMathTextTBRDataHExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,true,JKQTMathTextTBRDataHExt<QChar>> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextTBRDataH<QChar>,JKQTPDataCacheThreadSafe,JKQTMathTextTBRDataHExt<QChar>> cache(
|
||||
[](const JKQTMathTextTBRDataHExt<QChar>& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.leftBearing(key.text);
|
||||
@ -1040,7 +1085,7 @@ qreal JKQTMathTextGetLeftBearing(const QFont &f, const QChar &text, QPaintDevice
|
||||
|
||||
qreal JKQTMathTextGetFontAscent(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.ascent();
|
||||
@ -1051,7 +1096,7 @@ qreal JKQTMathTextGetFontAscent(const QFont &f, QPaintDevice *pd)
|
||||
|
||||
qreal JKQTMathTextGetFontDescent(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.descent();
|
||||
@ -1062,7 +1107,7 @@ qreal JKQTMathTextGetFontDescent(const QFont &f, QPaintDevice *pd)
|
||||
|
||||
qreal JKQTMathTextGetFontHeight(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.height();
|
||||
@ -1073,7 +1118,7 @@ qreal JKQTMathTextGetFontHeight(const QFont &f, QPaintDevice *pd)
|
||||
|
||||
qreal JKQTMathTextGetFontLineWidth(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.lineWidth();
|
||||
@ -1084,7 +1129,7 @@ qreal JKQTMathTextGetFontLineWidth(const QFont &f, QPaintDevice *pd)
|
||||
|
||||
qreal JKQTMathTextGetFontLeading(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.leading();
|
||||
@ -1095,7 +1140,7 @@ qreal JKQTMathTextGetFontLeading(const QFont &f, QPaintDevice *pd)
|
||||
|
||||
qreal JKQTMathTextGetFontLineSpacing(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.lineSpacing();
|
||||
@ -1106,7 +1151,7 @@ qreal JKQTMathTextGetFontLineSpacing(const QFont &f, QPaintDevice *pd)
|
||||
|
||||
qreal JKQTMathTextGetFontStrikoutPos(const QFont &f, QPaintDevice *pd)
|
||||
{
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,true,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
static JKQTPDataCache<qreal,JKQTMathTextCacheKeyBase,JKQTPDataCacheThreadSafe,JKQTMathTextCacheKeyBaseExt> cache(
|
||||
[](const JKQTMathTextCacheKeyBaseExt& key) {
|
||||
const QFontMetricsF fm(key.f, key.pd);
|
||||
return fm.strikeOutPos();
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 249 KiB |
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
@ -1,6 +1,7 @@
|
||||
#include <QObject>
|
||||
#include <QtTest>
|
||||
#include "jkqtcommon/jkqtpcsstools.h"
|
||||
#include "jkqtcommon/jkqtpcachingtools.h"
|
||||
|
||||
#ifndef QCOMPARE_EQ
|
||||
#define QCOMPARE_EQ(A,B) if (!static_cast<bool>((A)==(B))) {qDebug()<<QTest::toString(A)<< "!=" << QTest::toString(B); } QVERIFY((A)==(B))
|
||||
@ -238,6 +239,74 @@ private slots:
|
||||
QCOMPARE_EQ(n, QColor::fromRgbF(0.52,0.52,0.52,240.0/255.0));
|
||||
}
|
||||
|
||||
|
||||
inline void test_JKQTPCSSParser_JKQTPDataCache_ThreadSafe() {
|
||||
JKQTPDataCache<QString, int, JKQTPDataCacheThreadSafe> cache([](int key) { return QString::number(key);}, 100,0.8);
|
||||
|
||||
QString sum;
|
||||
for (int i=0; i<100; i++) {
|
||||
sum+=cache.get(i);
|
||||
}
|
||||
qDebug()<<"sum.size()="<<sum.size();
|
||||
QCOMPARE_EQ(cache.size(), 100);
|
||||
for (int i=0; i<100; i++) {
|
||||
QVERIFY(cache.contains(i));
|
||||
}
|
||||
sum+=cache.get(5000);
|
||||
QCOMPARE_EQ(cache.size(), 81);
|
||||
for (int i=1000; i<1005; i++) {
|
||||
sum+=cache.get(i);
|
||||
}
|
||||
QCOMPARE_EQ(cache.size(), 86);
|
||||
|
||||
qDebug()<<"sum.size()="<<sum.size();
|
||||
|
||||
}
|
||||
|
||||
inline void test_JKQTPCSSParser_JKQTPDataCache_NotThreadSafe() {
|
||||
JKQTPDataCache<QString, int, JKQTPDataCacheNotThreadSafe> cache([](int key) { return QString::number(key);}, 100,0.8);
|
||||
|
||||
QString sum;
|
||||
for (int i=0; i<100; i++) {
|
||||
sum+=cache.get(i);
|
||||
}
|
||||
qDebug()<<"sum.size()="<<sum.size();
|
||||
QCOMPARE_EQ(cache.size(), 100);
|
||||
for (int i=0; i<100; i++) {
|
||||
QVERIFY(cache.contains(i));
|
||||
}
|
||||
sum+=cache.get(5000);
|
||||
QCOMPARE_EQ(cache.size(), 81);
|
||||
for (int i=1000; i<1005; i++) {
|
||||
sum+=cache.get(i);
|
||||
}
|
||||
QCOMPARE_EQ(cache.size(), 86);
|
||||
|
||||
qDebug()<<"sum.size()="<<sum.size();
|
||||
|
||||
}
|
||||
|
||||
inline void benchmark_JKQTPCSSParser_JKQTPDataCache_ThreadSafe() {
|
||||
JKQTPDataCache<QString, int, JKQTPDataCacheThreadSafe> cache([](int key) { return QString::number(key);}, 100,0.8);
|
||||
|
||||
int sum=cache.get(1).size();
|
||||
QBENCHMARK(sum+=cache.get(1).size());
|
||||
int i=1;
|
||||
QBENCHMARK(sum+=cache.get(++i).size());
|
||||
qDebug()<<"sum.size()="<<sum<<", i="<<i;
|
||||
|
||||
}
|
||||
|
||||
inline void benchmark_JKQTPCSSParser_JKQTPDataCache_NotThreadSafe() {
|
||||
JKQTPDataCache<QString, int, JKQTPDataCacheNotThreadSafe> cache([](int key) { return QString::number(key);}, 100,0.8);
|
||||
|
||||
int sum=cache.get(1).size();
|
||||
QBENCHMARK(sum+=cache.get(1).size());
|
||||
int i=1;
|
||||
QBENCHMARK(sum+=cache.get(++i).size());
|
||||
qDebug()<<"sum.size()="<<sum<<", i="<<i;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user