From a3589f7452bc0fab5aea3da998bbe1d3d0e0ecde Mon Sep 17 00:00:00 2001 From: xy Date: Sun, 5 Aug 2012 18:42:39 +0800 Subject: [PATCH] Xy Flyweight. [Part 1] --- src/subtitles/RTS.cpp | 32 ++++++----- src/subtitles/RTS.h | 2 +- src/subtitles/cache_manager.cpp | 8 +-- src/subtitles/cache_manager.h | 32 ++++++----- src/subtitles/flyweight_base_types.h | 92 ++++++++++++++++++++++++++++++ src/subtitles/mru_cache.h | 48 ++++++++++++++++ src/subtitles/xy_overlay_paint_machine.cpp | 2 +- 7 files changed, 183 insertions(+), 33 deletions(-) diff --git a/src/subtitles/RTS.cpp b/src/subtitles/RTS.cpp index 718788e..68d2b6e 100644 --- a/src/subtitles/RTS.cpp +++ b/src/subtitles/RTS.cpp @@ -121,22 +121,21 @@ CMyFont::CMyFont(const STSStyleBase& style) // CWord CWord::CWord(const FwSTSStyle& style, const CStringW& str, int ktype, int kstart, int kend) - : m_style(style), m_str(str) + : m_style(style), m_str(new CStringW(str)) , m_width(0), m_ascent(0), m_descent(0) , m_ktype(ktype), m_kstart(kstart), m_kend(kend) , m_fLineBreak(false), m_fWhiteSpaceChar(false) //, m_pOpaqueBox(NULL) { - if(m_str.IsEmpty()) + if(m_str.Get().IsEmpty()) { m_fWhiteSpaceChar = m_fLineBreak = true; } m_width = 0; } -CWord::CWord( const CWord& src) +CWord::CWord( const CWord& src):m_str(src.m_str) { - m_str = src.m_str; m_fWhiteSpaceChar = src.m_fWhiteSpaceChar; m_fLineBreak = src.m_fLineBreak; m_style = src.m_style; @@ -159,8 +158,12 @@ bool CWord::Append(const SharedPtrCWord& w) if(!(m_style == w->m_style) || m_fLineBreak || w->m_fLineBreak || w->m_kstart != w->m_kend || m_ktype != w->m_ktype) return(false); - m_fWhiteSpaceChar = m_fWhiteSpaceChar && w->m_fWhiteSpaceChar; - m_str += w->m_str; + m_fWhiteSpaceChar = m_fWhiteSpaceChar && w->m_fWhiteSpaceChar; + CStringW *str = new CStringW();//Fix me: anyway to avoid this flyweight update? + ASSERT(str); + *str = m_str.Get(); + *str += w->m_str.Get(); + m_str = XyFwStringW(str); m_width += w->m_width; return(true); } @@ -773,7 +776,7 @@ bool CWord::CreateOpaqueBox() bool CWord::operator==( const CWord& rhs ) const { return (this==&rhs) || ( - m_str == rhs.m_str && + m_str.GetId() == rhs.m_str.GetId() && m_fWhiteSpaceChar == rhs.m_fWhiteSpaceChar && m_fLineBreak == rhs.m_fLineBreak && m_style == rhs.m_style && //fix me:? @@ -792,13 +795,13 @@ bool CWord::operator==( const CWord& rhs ) const CText::CText(const FwSTSStyle& style, const CStringW& str, int ktype, int kstart, int kend) : CWord(style, str, ktype, kstart, kend) { - if(m_str == L" ") + if(m_str.Get() == L" ") { m_fWhiteSpaceChar = true; } SharedPtrTextInfo text_info; TextInfoCacheKey text_info_key; - text_info_key.m_str = m_str; + text_info_key.m_str = m_str.Get(); text_info_key.m_style = m_style; text_info_key.UpdateHashValue(); TextInfoMruCache* text_info_cache = CacheManager::GetTextInfoCache(); @@ -806,7 +809,7 @@ CText::CText(const FwSTSStyle& style, const CStringW& str, int ktype, int kstart if(pos==NULL) { TextInfo* tmp=new TextInfo(); - GetTextInfo(tmp, m_style, m_str); + GetTextInfo(tmp, m_style, m_str.Get()); text_info.reset(tmp); text_info_cache->UpdateCache(text_info_key, text_info); } @@ -842,10 +845,11 @@ bool CText::CreatePath(PathData* path_data) FwCMyFont font(m_style); HFONT hOldFont = SelectFont(g_hDC, font.get()); int width = 0; + const CStringW& str = m_str.Get(); if(m_style.get().fontSpacing || (long)GetVersion() < 0) { bool bFirstPath = true; - for(LPCWSTR s = m_str; *s; s++) + for(LPCWSTR s = str; *s; s++) { CSize extent; if(!GetTextExtentPoint32W(g_hDC, s, 1, &extent)) {SelectFont(g_hDC, hOldFont); ASSERT(0); return(false);} @@ -859,9 +863,9 @@ bool CText::CreatePath(PathData* path_data) else { CSize extent; - if(!GetTextExtentPoint32W(g_hDC, m_str, m_str.GetLength(), &extent)) {SelectFont(g_hDC, hOldFont); ASSERT(0); return(false);} + if(!GetTextExtentPoint32W(g_hDC, str, str.GetLength(), &extent)) {SelectFont(g_hDC, hOldFont); ASSERT(0); return(false);} path_data->BeginPath(g_hDC); - TextOutW(g_hDC, 0, 0, m_str, m_str.GetLength()); + TextOutW(g_hDC, 0, 0, str, str.GetLength()); path_data->EndPath(g_hDC); } SelectFont(g_hDC, hOldFont); @@ -951,7 +955,7 @@ bool CPolygon::ParseStr() if(m_pathTypesOrg.GetCount() > 0) return(true); CPoint p; int j, lastsplinestart = -1, firstmoveto = -1, lastmoveto = -1; - CStringW str = m_str; + CStringW str = m_str.Get(); str.SpanIncluding(L"mnlbspc 0123456789"); str.Replace(L"m", L"*m"); str.Replace(L"n", L"*n"); diff --git a/src/subtitles/RTS.h b/src/subtitles/RTS.h index 1ba57f7..7d5db82 100644 --- a/src/subtitles/RTS.h +++ b/src/subtitles/RTS.h @@ -93,7 +93,7 @@ public: bool PaintFromRawData( const CPoint& psub, const CPoint& trans_org, const OverlayKey& key, SharedPtrOverlay* overlay ); protected: - CStringW m_str; + XyFwStringW m_str; public: bool m_fWhiteSpaceChar, m_fLineBreak; diff --git a/src/subtitles/cache_manager.cpp b/src/subtitles/cache_manager.cpp index 7928cdf..0fc6851 100644 --- a/src/subtitles/cache_manager.cpp +++ b/src/subtitles/cache_manager.cpp @@ -52,7 +52,7 @@ ULONG PathDataTraits::Hash( const PathData& key ) ULONG ClipperTraits::Hash( const CClipper& key ) { - ULONG hash = CStringElementTraits::Hash(key.m_polygon->m_str);; + ULONG hash = key.m_polygon->m_str.GetId(); hash += (hash<<5); hash += key.m_inverse; hash += (hash<<5); @@ -126,7 +126,7 @@ bool PathDataCacheKey::CompareSTSStyle( const STSStyle& lhs, const STSStyle& rhs ULONG PathDataCacheKey::UpdateHashValue() { const STSStyle& style = m_style.get(); - m_hash_value = CStringElementTraits::Hash(m_str); + m_hash_value = m_str_id; m_hash_value += (m_hash_value<<5); m_hash_value += style.charSet; m_hash_value += (m_hash_value<<5); @@ -295,7 +295,7 @@ bool ClipperAlphaMaskCacheKey::operator==( const ClipperAlphaMaskCacheKey& key ) { const CClipper& lhs = *m_clipper; const CClipper& rhs = *key.m_clipper; - result = (lhs.m_polygon->m_str == rhs.m_polygon->m_str + result = (lhs.m_polygon->m_str.GetId() == rhs.m_polygon->m_str.GetId() && fabs(lhs.m_polygon->m_scalex - rhs.m_polygon->m_scalex) < 0.000001 && fabs(lhs.m_polygon->m_scaley - rhs.m_polygon->m_scaley) < 0.000001 && lhs.m_size == rhs.m_size @@ -316,7 +316,7 @@ ULONG ClipperAlphaMaskCacheKey::UpdateHashValue() } ////////////////////////////////////////////////////////////////////////////////////////////// - + // DrawItemHashKey ULONG DrawItemHashKey::UpdateHashValue() diff --git a/src/subtitles/cache_manager.h b/src/subtitles/cache_manager.h index f0c5d60..71cd12e 100644 --- a/src/subtitles/cache_manager.h +++ b/src/subtitles/cache_manager.h @@ -27,20 +27,26 @@ public: class PathDataCacheKey { -public: - PathDataCacheKey(const CWord& word):m_str(word.m_str),m_style(word.m_style){} +public: + PathDataCacheKey(const CWord& word):m_style(word.m_style) + { + m_str_id = word.m_str.GetId(); + } PathDataCacheKey(const PathDataCacheKey& key) - :m_str(key.m_str) + :m_str_id(key.m_str_id) ,m_style(key.m_style) - ,m_hash_value(key.m_hash_value){} - PathDataCacheKey(const FwSTSStyle& style, const CStringW& str):m_str(str),m_style(style){} + ,m_hash_value(key.m_hash_value){} + PathDataCacheKey(const FwSTSStyle& style, XyFwStringW::IdType str_id):m_style(style) + { + m_str_id = str_id; + } bool operator==(const PathDataCacheKey& key)const { - return m_str==key.m_str && ( m_style==key.m_style || CompareSTSStyle(m_style, key.m_style) ); + return m_str_id==key.m_str_id && ( m_style==key.m_style || CompareSTSStyle(m_style, key.m_style) ); } bool operator==(const CWord& key)const - { - return m_str==key.m_str && ( m_style==key.m_style || CompareSTSStyle(m_style.get(), key.m_style.get()) ); + { + return m_str_id==key.m_str.GetId() && ( m_style==key.m_style || CompareSTSStyle(m_style.get(), key.m_style.get()) ); } static bool CompareSTSStyle(const STSStyle& lhs, const STSStyle& rhs); @@ -53,7 +59,7 @@ public: public: ULONG m_hash_value; protected: - CStringW m_str; + XyFwStringW::IdType m_str_id; FwSTSStyle m_style; }; @@ -65,8 +71,8 @@ public: :PathDataCacheKey(key) ,m_org(key.m_org) ,m_hash_value(key.m_hash_value) { } - ScanLineData2CacheKey(const FwSTSStyle& style, const CStringW& str, const POINT& org) - :PathDataCacheKey(style, str),m_org(org) { } + ScanLineData2CacheKey(const FwSTSStyle& style, XyFwStringW::IdType str_id, const POINT& org) + :PathDataCacheKey(style, str_id),m_org(org) { } bool operator==(const ScanLineData2CacheKey& key)const; ULONG UpdateHashValue(); @@ -84,8 +90,8 @@ class OverlayNoBlurKey: public ScanLineData2CacheKey public: OverlayNoBlurKey(const CWord& word, const POINT& p, const POINT& org):ScanLineData2CacheKey(word,org),m_p(p) {} OverlayNoBlurKey(const OverlayNoBlurKey& key):ScanLineData2CacheKey(key),m_p(key.m_p),m_hash_value(key.m_hash_value) {} - OverlayNoBlurKey(const FwSTSStyle& style, const CStringW& str, const POINT& p, const POINT& org) - :ScanLineData2CacheKey(style, str, org),m_p(p) {} + OverlayNoBlurKey(const FwSTSStyle& style, XyFwStringW::IdType str_id, const POINT& p, const POINT& org) + :ScanLineData2CacheKey(style, str_id, org),m_p(p) {} bool operator==(const OverlayNoBlurKey& key)const; ULONG UpdateHashValue(); diff --git a/src/subtitles/flyweight_base_types.h b/src/subtitles/flyweight_base_types.h index 5d578ea..ebab936 100644 --- a/src/subtitles/flyweight_base_types.h +++ b/src/subtitles/flyweight_base_types.h @@ -4,8 +4,11 @@ #include #include #include +#include #include +#include "mru_cache.h" + template<> struct std::equal_to { // functor for operator== @@ -17,6 +20,95 @@ struct std::equal_to typedef ::boost::flyweights::flyweight FwRect; +template< + typename V, + int DEFAULT_CACHE_SIZE = 1024, + class VTraits=CElementTraits +> +class XyFlyWeight +{ +public: + typedef std::size_t IdType; + typedef ::boost::shared_ptr SharedConstV; + + class SharedVElementTraits:public CElementTraits + { + public: + static ULONG Hash(const SharedConstV& v) + { + return VTraits::Hash(*v); + } + static bool CompareElements( + const SharedConstV& element1, + const SharedConstV& element2) + { + return VTraits::CompareElements(*element1, *element2); + } + static int CompareElementsOrdered( + const SharedConstV& element1, + const SharedConstV& element2) + { + return VTraits::CompareElementsOrdered(*element1, *element2); + } + }; + + typedef EnhancedXyMru Cacher; +public: + static const int INVALID_ID = 0; +public: + // v will be assigned to a shared pointer + XyFlyWeight(const V *v):_v(v) + { + Cacher * cacher = GetCacher(); + ASSERT( cacher ); + bool new_item_added = false; + POSITION pos = cacher->AddHeadIfNotExists(_v, INVALID_ID, &new_item_added); + if ( !new_item_added ) + { + cacher->UpdateCache(pos); + _v = cacher->GetKeyAt(pos); + _id = cacher->GetAt(pos); + } + else + { + _id = AllocId(); + cacher->GetAt(pos) = _id; + } + } + inline const V& Get() const { return *_v; } + inline IdType GetId() const { return _id; } + + static inline Cacher* GetCacher(); +private: + SharedConstV _v; + IdType _id; + + static inline IdType AllocId(); +}; + +template +inline +typename XyFlyWeight::Cacher* XyFlyWeight::GetCacher() +{ + static Cacher cacher(DEFAULT_CACHE_SIZE); + return &cacher; +} + +template +inline +typename XyFlyWeight::IdType XyFlyWeight::AllocId() +{ + static IdType cur_id=INVALID_ID; + ++cur_id; + if (cur_id==INVALID_ID) + { + ++cur_id; + } + return cur_id; +} + +typedef XyFlyWeight> XyFwStringW; + static inline std::size_t hash_value(const double& d) { std::size_t hash = 515; diff --git a/src/subtitles/mru_cache.h b/src/subtitles/mru_cache.h index 316ec7a..e445157 100644 --- a/src/subtitles/mru_cache.h +++ b/src/subtitles/mru_cache.h @@ -1099,6 +1099,36 @@ public: } return pos_hash_value; } + inline POSITION AddHeadIfNotExists(const K& key, const V& value, bool *new_item_added) + { + POSITION pos; + POSITION pos_hash_value = NULL; + bool new_hash_item_added = false; + pos = _hash.SetAtIfNotExists(key, (POSITION)NULL, &new_hash_item_added); + if (new_hash_item_added) + { + pos_hash_value = _list.AddHead( ListItem(pos, value) ); + _hash.SetValueAt(pos, pos_hash_value); + if (new_item_added) + { + *new_item_added = true; + } + } + else + { + pos_hash_value = _hash.GetValueAt(pos); + if (new_item_added) + { + *new_item_added = false; + } + } + if(_list.GetCount()>_max_item_num) + { + _hash.RemoveAtPos(_list.GetTail().first); + _list.RemoveTail(); + } + return pos_hash_value; + } inline void RemoveAll() { _hash.RemoveAll(); @@ -1117,9 +1147,17 @@ public: return NULL; } } + inline V& GetAt(POSITION pos) + { + return _list.GetAt(pos).second; + } inline const V& GetAt(POSITION pos) const { return _list.GetAt(pos).second; + } + inline const K& GetKeyAt(POSITION pos) const + { + return _hash.GetKeyAt(_list.GetAt(pos).first); } inline std::size_t SetMaxItemNum( std::size_t max_item_num ) { @@ -1177,6 +1215,16 @@ public: _cache_hit += (pos!=NULL); return pos; } + inline POSITION AddHeadIfNotExists(const K& key, const V& value, bool *new_item_added) + { + _query_count++; + bool tmp = false; + POSITION pos = __super::AddHeadIfNotExists(key, value, &tmp); + _cache_hit += (tmp==false); + if(new_item_added) + *new_item_added = tmp; + return pos; + } inline std::size_t GetCacheHitCount() const { return _cache_hit; } inline std::size_t GetQueryCount() const { return _query_count; } diff --git a/src/subtitles/xy_overlay_paint_machine.cpp b/src/subtitles/xy_overlay_paint_machine.cpp index a0061fd..ccf77fa 100644 --- a/src/subtitles/xy_overlay_paint_machine.cpp +++ b/src/subtitles/xy_overlay_paint_machine.cpp @@ -58,7 +58,7 @@ void CWordPaintMachine::Paint( LAYER layer, SharedPtrOverlay* overlay ) void CWordPaintMachine::PaintBody( const SharedPtrCWord& word, const CPoint& p, SharedPtrOverlay* overlay ) { - if(!word->m_str || overlay==NULL) return; + if(!word->m_str.Get() || overlay==NULL) return; bool error = false; do { -- 2.11.4.GIT