class BaseStyle {
public:
enum ProperyID{
PROP_FONT_SIZE,
PROP_PARAGRAPH_INDENT
};
// virtual bool createLocalStyle();
virtual void setProperty(int type, void* val) = 0;
};
using BaseStyleSp = std::shared_ptr<BaseStyle>;
class ShareData {
public:
ShareData(float fontSize): m_fontSize(fontSize){}
size_t hash() const { return std::hash<float>()(m_fontSize);}
public:
float m_fontSize;
};
using ShareDataSp = std::shared_ptr<ShareData>;
using ShareDataWp = std::weak_ptr<ShareData>;
class ShareDocData {
public:
float paragraphIndent;
};
using ShareDocDataSp = std::shared_ptr<ShareDocData>;
using ShareDocDataWp = std::weak_ptr<ShareDocData>;
class ShareDataLRU {
public:
ShareDataLRU(): m_hitCount(0) {}
int m_hitCount;
};
#include <cassert>
#include <unordered_map>
class ShareDataMergeManger{
class CharHash {
public:
std::size_t operator()(const ShareDataSp &sharedPtr) const {
if(!sharedPtr)
return 0;
return sharedPtr->hash();
}
};
class CharCmp {
public:
bool operator()(const ShareDataSp &selfPtr, const ShareDataSp &otherPtr) const {
if(selfPtr == otherPtr)
return true;
if(!selfPtr)
return false;
if(!otherPtr)
return false;
return selfPtr->hash() == otherPtr->hash();
}
};
public:
ShareDataSp allocCharData(const ShareDataSp charData) {
//if(manger.size() > 20000)
// clearUnUsed();
return std::make_shared<ShareData>(*charData);
}
ShareDataSp addCacheCharData(const ShareDataSp& data) {
auto ret = manger.emplace(data, ShareDataLRU());
if(ret.second) { //新添加成功
return ret.first->first;
} else { //已存在,返回旧的
++ret.first->second.m_hitCount;
return ret.first->first;
}
}
ShareDataSp findCharData(const ShareDataSp& data) {
auto shareData = manger.find(data);
if(shareData == manger.end()) {
return nullptr;
}
else {
++shareData->second.m_hitCount; //查找次数+1,热度上升
return shareData->first;
}
}
void removeCharData(const ShareDataSp& data) {
manger.erase(data);
}
// 内存超过指定长度,自动清除未使用的区域
void clearUnUsed() {
for (auto iter = manger.begin(); iter != manger.end(); ) {
if(1 == iter->first.use_count())
iter = manger.erase(iter);
else
++iter;
}
}
public:
std::unordered_map<ShareDataSp, ShareDataLRU, CharHash, CharCmp> manger;
};
using ShareDataMergeMangerSp = std::shared_ptr<ShareDataMergeManger>;
using ShareDataMergeMangerWp = std::weak_ptr<ShareDataMergeManger>;
class LocalStyle : public BaseStyle {
public:
LocalStyle(ShareDataSp charData, ShareDocDataSp docData, const ShareDataMergeMangerSp& shareDataMergeManger):m_charData(shareDataMergeManger->addCacheCharData(charData)), m_docData(docData), m_shareDataMergeManger(shareDataMergeManger){
}
// ~LocalStyle() {
// if(m_shareDataMergeManger.expired()) {
// return;
// }
// auto allocManger = m_shareDataMergeManger.lock();
// if(!allocManger)
// return;
// if(2 == m_charData.use_count())
// allocManger->removeCharData(m_charData);
// }
void setFontSize(float size) {
m_charData->m_fontSize = size;
}
float fontSize() const {
return m_charData->m_fontSize;
}
private:
void setProperty(int type, void* val) override {
if(PROP_FONT_SIZE == type) {
auto newVal = *(float*)val;
auto useCout = m_charData.use_count();
if(fontSize() == newVal)
return;
if(useCout == 2 || useCout == 1) { //自己独占或与内存管理类共享数据
removeCache(); //更新hash,需先移除
} else {
detach(); //创建副本
}
setFontSize(newVal);// 改值
merge(); //缓存更新
}
}
void removeCache() {
auto allocManger = shareMemoryManger();
if(!allocManger)
return;
allocManger->removeCharData(m_charData); //先删除,key值hash不跟随联动,暂无法解决性能损耗
}
void detach() {
auto allocManger = shareMemoryManger();
if(!allocManger)
return;
m_charData = allocManger->allocCharData(m_charData);
}
bool merge() {
auto allocManger = shareMemoryManger();
if(!allocManger)
return false;
auto cacheCharData = allocManger->addCacheCharData(m_charData); //新数据加入
if(cacheCharData != m_charData) {
m_charData = cacheCharData;
return true;
} else {
return false;
}
}
private:
inline ShareDataMergeMangerSp shareMemoryManger() const {
if(m_shareDataMergeManger.expired())
return nullptr;
return m_shareDataMergeManger.lock();
}
public:
ShareDataSp m_charData;
ShareDocDataSp m_docData;
ShareDataMergeMangerWp m_shareDataMergeManger;
};
using LocalStyleSp = std::shared_ptr<LocalStyle>;
class Style {
public:
std::string hyperLink;
int styleId;
ShareDataSp charData;
};
class DocStyle {
public:
ShareDocDataSp docData;
int align;
};
int main(int argc, char** argv)
{
auto shareDataManger = std::make_shared<ShareDataMergeManger>();
auto shareCharData = std::make_shared<ShareData>(0);
auto shareDocData = std::make_shared<ShareDocData>();
BaseStyleSp localStyle = std::make_shared<LocalStyle>(shareCharData, shareDocData, shareDataManger);
float size = 1; //数据存在浮点精度,无法准确去重,暂时不优化
localStyle->setProperty(BaseStyle::ProperyID::PROP_FONT_SIZE, &size);
size = 2;
localStyle->setProperty(BaseStyle::ProperyID::PROP_FONT_SIZE, &size);
size = 0;
localStyle->setProperty(BaseStyle::ProperyID::PROP_FONT_SIZE, &size);
return 0;
}
perf-10万样式-同时修改1万个-5-6ms(堆内存频繁分配,合并,释放,尝试转栈)
#include <iostream>
#include <chrono>
int main(int argc, char** argv)
{
auto shareDataManger = std::make_shared<ShareDataMergeManger>();
size_t count = 100000;
std::vector<BaseStyleSp> vctStyles;
vctStyles.reserve(count);
for (int i = 0; i < count; ++i) {
auto shareCharData = std::make_shared<ShareCharData>(i);
auto shareDocData = std::make_shared<ShareDocData>();
BaseStyleSp localStyle = std::make_shared<LocalStyle>(shareCharData, shareDocData, shareDataManger);
vctStyles.push_back(localStyle);
}
// 获取当前时间点
auto start = std::chrono::high_resolution_clock::now();
float size = 50000;
auto shareCharData = std::make_shared<ShareCharData>(size);
auto shareDocData = std::make_shared<ShareDocData>();
BaseStyleSp localStyle = std::make_shared<LocalStyle>(shareCharData, shareDocData, shareDataManger);
for (int i = 40000; i < 50000; ++i) {
size = i + 1;
vctStyles.at(i)->setProperty(BaseStyle::ProperyID::PROP_FONT_SIZE, &size);
}
// 获取代码执行后的时间点
auto end = std::chrono::high_resolution_clock::now();
// 计算代码执行的时间差
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
// 输出运行时间
std::cout << "代码执行时间: " << duration << " 微秒" << std::endl;
return 0;
}