diff --git a/common/font/font.cpp b/common/font/font.cpp index 45ed4b6a6c..d5ccaf9da6 100644 --- a/common/font/font.cpp +++ b/common/font/font.cpp @@ -24,6 +24,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <list> +#include <mutex> +#include <unordered_map> + #include <wx/font.h> #include <string_utils.h> #include <gal/graphics_abstraction_layer.h> @@ -47,6 +51,75 @@ FONT* FONT::s_defaultFont = nullptr; std::map< std::tuple<wxString, bool, bool>, FONT*> FONT::s_fontMap; +class MARKUP_CACHE +{ +public: + struct ENTRY + { + std::string source; + std::unique_ptr<MARKUP::NODE> root; + }; + + typedef std::pair<wxString, ENTRY> CACHE_ENTRY; + + MARKUP_CACHE( size_t aMaxSize ) : + m_maxSize( aMaxSize ) + { + } + + ENTRY& Put( const CACHE_ENTRY::first_type& aQuery, ENTRY&& aResult ) + { + auto it = m_cache.find( aQuery ); + + m_cacheMru.emplace_front( CACHE_ENTRY( aQuery, std::move( aResult ) ) ); + + if( it != m_cache.end() ) + { + m_cacheMru.erase( it->second ); + m_cache.erase( it ); + } + + m_cache[aQuery] = m_cacheMru.begin(); + + if( m_cache.size() > m_maxSize ) + { + auto last = m_cacheMru.end(); + last--; + m_cache.erase( last->first ); + m_cacheMru.pop_back(); + } + + return m_cacheMru.begin()->second; + } + + ENTRY* Get( const CACHE_ENTRY::first_type& aQuery ) + { + auto it = m_cache.find( aQuery ); + + if( it == m_cache.end() ) + return nullptr; + + m_cacheMru.splice( m_cacheMru.begin(), m_cacheMru, it->second ); + + return &m_cacheMru.begin()->second; + } + + void Clear() + { + m_cacheMru.clear(); + m_cache.clear(); + } + +private: + size_t m_maxSize; + std::list<CACHE_ENTRY> m_cacheMru; + std::unordered_map<wxString, std::list<CACHE_ENTRY>::iterator> m_cache; +}; + + +static MARKUP_CACHE s_markupCache( 1024 ); +static std::mutex s_markupCacheMutex; + FONT::FONT() { @@ -106,7 +179,7 @@ void FONT::getLinePositions( const wxString& aText, const VECTOR2I& aPosition, { VECTOR2I pos( aPosition.x, aPosition.y + i * interline ); VECTOR2I end = boundingBoxSingleLine( nullptr, aTextLines[i], pos, aAttrs.m_Size, - aAttrs.m_Italic ); + aAttrs.m_Italic ); VECTOR2I bBox( end - pos ); aExtents.push_back( bBox ); @@ -186,7 +259,7 @@ void FONT::Draw( KIGFX::GAL* aGal, const wxString& aText, const VECTOR2I& aPosit * @return position of cursor for drawing next substring */ VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* aGlyphs, - const std::unique_ptr<MARKUP::NODE>& aNode, const VECTOR2I& aPosition, + const MARKUP::NODE* aNode, const VECTOR2I& aPosition, const KIFONT::FONT* aFont, const VECTOR2I& aSize, const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) { @@ -221,8 +294,8 @@ VECTOR2I drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYPH>>* a for( const std::unique_ptr<MARKUP::NODE>& child : aNode->children ) { - nextPosition = drawMarkup( aBoundingBox, aGlyphs, child, nextPosition, aFont, aSize, - aAngle, aMirror, aOrigin, textStyle ); + nextPosition = drawMarkup( aBoundingBox, aGlyphs, child.get(), nextPosition, aFont, + aSize, aAngle, aMirror, aOrigin, textStyle ); } } @@ -235,11 +308,24 @@ VECTOR2I FONT::drawMarkup( BOX2I* aBoundingBox, std::vector<std::unique_ptr<GLYP const EDA_ANGLE& aAngle, bool aMirror, const VECTOR2I& aOrigin, TEXT_STYLE_FLAGS aTextStyle ) const { - MARKUP::MARKUP_PARSER markupParser( TO_UTF8( aText ) ); - std::unique_ptr<MARKUP::NODE> root = markupParser.Parse(); + std::lock_guard<std::mutex> lock( s_markupCacheMutex ); - return ::drawMarkup( aBoundingBox, aGlyphs, root, aPosition, this, aSize, aAngle, aMirror, - aOrigin, aTextStyle ); + MARKUP_CACHE::ENTRY* markup = s_markupCache.Get( aText ); + + if( !markup || !markup->root ) + { + MARKUP_CACHE::ENTRY& cached = s_markupCache.Put( aText, {} ); + + cached.source = TO_UTF8( aText ); + MARKUP::MARKUP_PARSER markupParser( &cached.source ); + cached.root = markupParser.Parse(); + markup = &cached; + } + + wxASSERT( markup && markup->root ); + + return ::drawMarkup( aBoundingBox, aGlyphs, markup->root.get(), aPosition, this, aSize, aAngle, + aMirror, aOrigin, aTextStyle ); } diff --git a/common/markup_parser.cpp b/common/markup_parser.cpp index 770f8d489a..e94f522177 100644 --- a/common/markup_parser.cpp +++ b/common/markup_parser.cpp @@ -30,7 +30,13 @@ std::unique_ptr<NODE> MARKUP_PARSER::Parse() { try { - auto root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( in ); + std::unique_ptr<NODE> root; + + if( mem_in ) + root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( *mem_in ); + else + root = parse_tree::parse<MARKUP::grammar, MARKUP::NODE, MARKUP::selector>( *in ); + return root; } catch ( tao::pegtl::parse_error& ) diff --git a/common/template_fieldnames.cpp b/common/template_fieldnames.cpp index 022a7bb53a..044218dc80 100644 --- a/common/template_fieldnames.cpp +++ b/common/template_fieldnames.cpp @@ -36,16 +36,21 @@ using namespace TFIELD_T; #define FOOTPRINT_CANONICAL "Footprint" #define DATASHEET_CANONICAL "Datasheet" +static wxString s_CanonicalReference( REFERENCE_CANONICAL ); +static wxString s_CanonicalValue( VALUE_CANONICAL ); +static wxString s_CanonicalFootprint( FOOTPRINT_CANONICAL ); +static wxString s_CanonicalDatasheet( DATASHEET_CANONICAL ); + const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx, bool aTranslateForHI ) { if( !aTranslateForHI ) { switch( aFieldNdx ) { - case REFERENCE_FIELD: return REFERENCE_CANONICAL; // The symbol reference, R1, C1, etc. - case VALUE_FIELD: return VALUE_CANONICAL; // The symbol value - case FOOTPRINT_FIELD: return FOOTPRINT_CANONICAL; // The footprint for use with Pcbnew - case DATASHEET_FIELD: return DATASHEET_CANONICAL; // Link to a datasheet for symbol + case REFERENCE_FIELD: return s_CanonicalReference; // The symbol reference, R1, C1, etc. + case VALUE_FIELD: return s_CanonicalValue; // The symbol value + case FOOTPRINT_FIELD: return s_CanonicalFootprint; // The footprint for use with Pcbnew + case DATASHEET_FIELD: return s_CanonicalDatasheet; // Link to a datasheet for symbol default: return wxString::Format( wxT( "Field%d" ), aFieldNdx ); } } diff --git a/common/transform.cpp b/common/transform.cpp index d805c68db4..0499b4ee04 100644 --- a/common/transform.cpp +++ b/common/transform.cpp @@ -22,6 +22,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <hash.h> #include <macros.h> #include <trigo.h> #include <transform.h> @@ -124,3 +125,9 @@ bool TRANSFORM::MapAngles( EDA_ANGLE* aAngle1, EDA_ANGLE* aAngle2 ) const } +size_t std::hash<TRANSFORM>::operator()( const TRANSFORM& s ) const +{ + size_t seed = std::hash<int>{}( s.x1 ); + hash_combine( seed, s.y1, s.x2, s.y2 ); + return seed; +} diff --git a/eeschema/sch_symbol.cpp b/eeschema/sch_symbol.cpp index 571338c81c..713eb1ce76 100644 --- a/eeschema/sch_symbol.cpp +++ b/eeschema/sch_symbol.cpp @@ -44,6 +44,9 @@ #include "plotters/plotter.h" +std::unordered_map<TRANSFORM, int> SCH_SYMBOL::s_transformToOrientationCache; + + /** * Convert a wxString to UTF8 and replace any control characters with a ~, * where a control character is one of the first ASCII values up to ' ' 32d. @@ -1535,6 +1538,13 @@ void SCH_SYMBOL::SetOrientation( int aOrientation ) int SCH_SYMBOL::GetOrientation() const { + /* + * This is slow, but also a bizarre algorithm. I don't feel like unteasing the algorithm right + * now, so let's just cache it for the moment. + */ + if( s_transformToOrientationCache.count( m_transform ) ) + return s_transformToOrientationCache.at( m_transform ); + int rotate_values[] = { SYM_ORIENT_0, @@ -1560,7 +1570,10 @@ int SCH_SYMBOL::GetOrientation() const temp.SetOrientation( type_rotate ); if( transform == temp.GetTransform() ) + { + s_transformToOrientationCache[m_transform] = type_rotate; return type_rotate; + } } // Error: orientation not found in list (should not happen) diff --git a/eeschema/sch_symbol.h b/eeschema/sch_symbol.h index 9c5ee0b314..f36a06bdc2 100644 --- a/eeschema/sch_symbol.h +++ b/eeschema/sch_symbol.h @@ -798,6 +798,9 @@ private: // Defines the hierarchical path and reference of the symbol. This allows support // for multiple references to a single sub-sheet. std::vector<SCH_SYMBOL_INSTANCE> m_instanceReferences; + + /// @see SCH_SYMBOL::GetOrientation + static std::unordered_map<TRANSFORM, int> s_transformToOrientationCache; }; #endif /* __SYMBOL_H__ */ diff --git a/include/markup_parser.h b/include/markup_parser.h index 99b97858b4..7427e4aff8 100644 --- a/include/markup_parser.h +++ b/include/markup_parser.h @@ -97,13 +97,20 @@ class MARKUP_PARSER { public: MARKUP_PARSER( const std::string& source ) : - in( source, "from_input" ) + in( std::make_unique<string_input<>>( source, "from_input" ) ), + mem_in() + {} + + MARKUP_PARSER( const std::string* source ) : + in(), + mem_in( std::make_unique<memory_input<>>( *source, "from_input" ) ) {} std::unique_ptr<NODE> Parse(); private: - string_input<> in; + std::unique_ptr<string_input<>> in; + std::unique_ptr<memory_input<>> mem_in; }; } // namespace MARKUP diff --git a/include/transform.h b/include/transform.h index 726302bfe8..61a6cea025 100644 --- a/include/transform.h +++ b/include/transform.h @@ -98,5 +98,12 @@ public: bool MapAngles( EDA_ANGLE* aAngle1, EDA_ANGLE* aAngle2 ) const; }; +namespace std +{ + template <> struct hash<TRANSFORM> + { + size_t operator() ( const TRANSFORM& k ) const; + }; +} #endif // _TRANSFORM_H_