From 0be357ec3e88d4467d59ac93a8e84628c14067dc Mon Sep 17 00:00:00 2001 From: Bernhard Stegmaier Date: Sun, 17 Sep 2017 10:26:06 +0200 Subject: [PATCH] LIB_ITEMS_CONTAINER reimplemented using C-style array of boost::ptr_vector Fixes: lp:1714974 * https://bugs.launchpad.net/kicad/+bug/1714974 --- eeschema/class_libentry.cpp | 173 +++++++++++------------ eeschema/class_libentry.h | 17 +-- eeschema/lib_collectors.cpp | 8 +- eeschema/lib_collectors.h | 4 +- eeschema/lib_items.cpp | 264 ++++++++++++++++-------------------- eeschema/lib_items.h | 118 ++++++++++------ eeschema/libeditframe.cpp | 2 +- eeschema/symbedit.cpp | 6 +- 8 files changed, 294 insertions(+), 298 deletions(-) diff --git a/eeschema/class_libentry.cpp b/eeschema/class_libentry.cpp index 1e9aed8c34..81f8c47acc 100644 --- a/eeschema/class_libentry.cpp +++ b/eeschema/class_libentry.cpp @@ -178,7 +178,7 @@ struct null_deleter LIB_PART::LIB_PART( const wxString& aName, PART_LIB* aLibrary ) : EDA_ITEM( LIB_PART_T ), - m_me( this, null_deleter() ), drawings( drawingsMap ) + m_me( this, null_deleter() ) { m_name = aName; m_library = aLibrary; @@ -198,17 +198,17 @@ LIB_PART::LIB_PART( const wxString& aName, PART_LIB* aLibrary ) : // when the field editors are invoked. LIB_FIELD* value = new LIB_FIELD( this, VALUE ); value->SetText( aName ); - drawingsMap[LIB_FIELD_T].push_back( value ); + m_drawings[LIB_FIELD_T].push_back( value ); - drawingsMap[LIB_FIELD_T].push_back( new LIB_FIELD( this, REFERENCE ) ); - drawingsMap[LIB_FIELD_T].push_back( new LIB_FIELD( this, FOOTPRINT ) ); - drawingsMap[LIB_FIELD_T].push_back( new LIB_FIELD( this, DATASHEET ) ); + m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, REFERENCE ) ); + m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, FOOTPRINT ) ); + m_drawings[LIB_FIELD_T].push_back( new LIB_FIELD( this, DATASHEET ) ); } LIB_PART::LIB_PART( LIB_PART& aPart, PART_LIB* aLibrary ) : EDA_ITEM( aPart ), - m_me( this, null_deleter() ), drawings( drawingsMap ) + m_me( this, null_deleter() ) { LIB_ITEM* newItem; @@ -223,14 +223,14 @@ LIB_PART::LIB_PART( LIB_PART& aPart, PART_LIB* aLibrary ) : m_dateModified = aPart.m_dateModified; m_options = aPart.m_options; - for( LIB_ITEM& oldItem : aPart.drawings ) + for( LIB_ITEM& oldItem : aPart.m_drawings ) { if( oldItem.IsNew() ) continue; newItem = (LIB_ITEM*) oldItem.Clone(); newItem->SetParent( this ); - drawings.push_back( newItem ); + m_drawings.push_back( newItem ); } for( size_t i = 0; i < aPart.m_aliases.size(); i++ ) @@ -329,7 +329,7 @@ void LIB_PART::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDc, const wxPoint& aOffset, if( ! ( screen && screen->m_IsPrinting && GetGRForceBlackPenState() ) && ( aOpts.color == COLOR4D::UNSPECIFIED ) ) { - for( LIB_ITEM& drawItem : drawings ) + for( LIB_ITEM& drawItem : m_drawings ) { if( drawItem.m_Fill != FILLED_WITH_BG_BODYCOLOR ) continue; @@ -367,7 +367,7 @@ void LIB_PART::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDc, const wxPoint& aOffset, // Track the index into the dangling pins list size_t pin_index = 0; - for( LIB_ITEM& drawItem : drawings ) + for( LIB_ITEM& drawItem : m_drawings ) { if( aOpts.only_selected && !drawItem.IsSelected() ) continue; @@ -463,7 +463,7 @@ void LIB_PART::Plot( PLOTTER* aPlotter, int aUnit, int aConvert, // draw background for filled items using background option // Solid lines will be drawn after the background - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { // Lib Fields are not plotted here, because this plot function // is used to plot schematic items, which have they own fields @@ -482,7 +482,7 @@ void LIB_PART::Plot( PLOTTER* aPlotter, int aUnit, int aConvert, // Not filled items and filled shapes are now plotted // (plot only items which are not already plotted) - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( item.Type() == LIB_FIELD_T ) continue; @@ -506,7 +506,7 @@ void LIB_PART::PlotLibFields( PLOTTER* aPlotter, int aUnit, int aConvert, aPlotter->SetColor( GetLayerColor( LAYER_FIELDS ) ); bool fill = aPlotter->GetColorMode(); - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( item.Type() != LIB_FIELD_T ) continue; @@ -552,7 +552,7 @@ void LIB_PART::RemoveDrawItem( LIB_ITEM* aItem, EDA_DRAW_PANEL* aPanel, wxDC* aD } } - LIB_ITEMS& items = drawingsMap[aItem->Type()]; + LIB_ITEMS& items = m_drawings[ aItem->Type() ]; for( LIB_ITEMS::iterator i = items.begin(); i != items.end(); i++ ) { @@ -574,7 +574,7 @@ void LIB_PART::AddDrawItem( LIB_ITEM* aItem ) { wxASSERT( aItem != NULL ); - drawings.push_back( aItem ); + m_drawings.push_back( aItem ); } @@ -583,32 +583,24 @@ LIB_ITEM* LIB_PART::GetNextDrawItem( LIB_ITEM* aItem, KICAD_T aType ) /* Return the next draw object pointer. * If item is NULL return the first item of type in the list. */ - if( drawings.empty() ) + if( m_drawings.empty( aType ) ) return NULL; - if( aItem == NULL && aType == TYPE_NOT_INIT ) // type is unspecified - return &drawings[0]; + if( aItem == NULL ) + return &( *( m_drawings.begin( aType ) ) ); - // Search for last item - size_t idx = 0; - - if( aItem ) - { - for( ; idx < drawings.size(); idx++ ) - { - if( aItem == &drawings[idx] ) - { - idx++; // Prepare the next item search - break; - } - } - } + // Search for last item, assume aItem is of type aType + wxASSERT( ( aType == TYPE_NOT_INIT ) || ( aType == aItem->Type() ) ); + LIB_ITEMS_CONTAINER::ITERATOR it = m_drawings.begin( aType ); + while( ( it != m_drawings.end( aType ) ) && ( aItem != &( *it ) ) ) + ++it; // Search the next item - for( ; idx < drawings.size(); idx++ ) + if( it != m_drawings.end( aType ) ) { - if( aType == TYPE_NOT_INIT || drawings[ idx ].Type() == aType ) - return &drawings[ idx ]; + ++it; + if( it != m_drawings.end( aType ) ) + return &( *it ); } return NULL; @@ -617,7 +609,7 @@ LIB_ITEM* LIB_PART::GetNextDrawItem( LIB_ITEM* aItem, KICAD_T aType ) void LIB_PART::GetPins( LIB_PINS& aList, int aUnit, int aConvert ) { - if( drawingsMap.count( LIB_PIN_T ) == 0 ) + if( m_drawings.empty( LIB_PIN_T ) ) return; /* Notes: @@ -626,7 +618,7 @@ void LIB_PART::GetPins( LIB_PINS& aList, int aUnit, int aConvert ) * when .m_Unit == 0, the body item is common to units * when .m_Convert == 0, the body item is common to shapes */ - for( LIB_ITEM& item : drawingsMap[LIB_PIN_T] ) + for( LIB_ITEM& item : m_drawings[ LIB_PIN_T ] ) { // Unit filtering: if( aUnit && item.m_Unit && ( item.m_Unit != aUnit ) ) @@ -816,15 +808,15 @@ bool LIB_PART::Save( OUTPUTFORMATTER& aFormatter ) } // Save graphics items (including pins) - if( !drawings.empty() ) + if( !m_drawings.empty() ) { /* we sort the draw items, in order to have an edition more easy, * when a file editing "by hand" is made */ - drawings.sort(); + m_drawings.sort(); aFormatter.Print( 0, "DRAW\n" ); - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( item.Type() == LIB_FIELD_T ) continue; @@ -1073,7 +1065,7 @@ bool LIB_PART::LoadDrawEntries( LINE_READER& aLineReader, wxString& aErrorMsg ) } else { - drawings.push_back( newEntry ); + m_drawings.push_back( newEntry ); } } @@ -1123,7 +1115,7 @@ bool LIB_PART::LoadField( LINE_READER& aLineReader, wxString& aErrorMsg ) } else { - drawingsMap[LIB_FIELD_T].push_back( field ); + m_drawings.push_back( field ); } return true; @@ -1160,7 +1152,7 @@ const EDA_RECT LIB_PART::GetUnitBoundingBox( int aUnit, int aConvert ) const EDA_RECT bBox; bool initialized = false; - for( const LIB_ITEM& item : drawings ) + for( const LIB_ITEM& item : m_drawings ) { if( ( item.m_Unit > 0 ) && ( ( m_unitCount > 1 ) && ( aUnit > 0 ) && ( aUnit != item.m_Unit ) ) ) @@ -1190,7 +1182,7 @@ const EDA_RECT LIB_PART::GetBodyBoundingBox( int aUnit, int aConvert ) const EDA_RECT bBox; bool initialized = false; - for( const LIB_ITEM& item : drawings ) + for( const LIB_ITEM& item : m_drawings ) { if( ( item.m_Unit > 0 ) && ( ( m_unitCount > 1 ) && ( aUnit > 0 ) && ( aUnit != item.m_Unit ) ) ) @@ -1217,7 +1209,7 @@ const EDA_RECT LIB_PART::GetBodyBoundingBox( int aUnit, int aConvert ) const void LIB_PART::deleteAllFields() { - drawingsMap[LIB_FIELD_T].clear(); + m_drawings[ LIB_FIELD_T ].clear(); } @@ -1231,7 +1223,7 @@ void LIB_PART::SetFields( const std::vector & aFields ) LIB_FIELD* field = new LIB_FIELD( aFields[i] ); field->SetParent( this ); - drawingsMap[LIB_FIELD_T].push_back( field ); + m_drawings.push_back( field ); } } @@ -1256,7 +1248,7 @@ void LIB_PART::GetFields( LIB_FIELDS& aList ) } // Now grab all the rest of fields. - for( LIB_ITEM& item : drawingsMap[LIB_FIELD_T] ) + for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] ) { field = ( LIB_FIELD* ) &item; @@ -1270,7 +1262,7 @@ void LIB_PART::GetFields( LIB_FIELDS& aList ) LIB_FIELD* LIB_PART::GetField( int aId ) { - for( LIB_ITEM& item : drawingsMap[LIB_FIELD_T] ) + for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] ) { LIB_FIELD* field = ( LIB_FIELD* ) &item; @@ -1284,7 +1276,7 @@ LIB_FIELD* LIB_PART::GetField( int aId ) LIB_FIELD* LIB_PART::FindField( const wxString& aFieldName ) { - for( LIB_ITEM& item : drawingsMap[LIB_FIELD_T] ) + for( LIB_ITEM& item : m_drawings[ LIB_FIELD_T ] ) { LIB_FIELD* field = ( LIB_FIELD* ) &item; @@ -1361,21 +1353,20 @@ bool LIB_PART::LoadDateAndTime( char* aLine ) void LIB_PART::SetOffset( const wxPoint& aOffset ) { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) item.SetOffset( aOffset ); } void LIB_PART::RemoveDuplicateDrawItems() { - for( auto& itemTypes : drawingsMap ) - itemTypes.second.unique(); + m_drawings.unique(); } bool LIB_PART::HasConversion() const { - for( const LIB_ITEM& item : drawings ) + for( const LIB_ITEM& item : m_drawings ) { if( item.m_Convert > 1 ) return true; @@ -1387,7 +1378,7 @@ bool LIB_PART::HasConversion() const void LIB_PART::ClearStatus() { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { item.m_Flags = 0; } @@ -1398,7 +1389,7 @@ int LIB_PART::SelectItems( EDA_RECT& aRect, int aUnit, int aConvert, bool aEditP { int itemCount = 0; - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { item.ClearFlags( SELECTED ); @@ -1427,7 +1418,7 @@ int LIB_PART::SelectItems( EDA_RECT& aRect, int aUnit, int aConvert, bool aEditP void LIB_PART::MoveSelectedItems( const wxPoint& aOffset ) { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( !item.IsSelected() ) continue; @@ -1440,7 +1431,7 @@ void LIB_PART::MoveSelectedItems( const wxPoint& aOffset ) void LIB_PART::ClearSelectedItems() { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { item.m_Flags = 0; } @@ -1449,14 +1440,14 @@ void LIB_PART::ClearSelectedItems() void LIB_PART::DeleteSelectedItems() { - LIB_ITEMS_LIST::ITERATOR item = drawings.begin(); + LIB_ITEMS_CONTAINER::ITERATOR item = m_drawings.begin(); // We *do not* remove the 2 mandatory fields: reference and value // so skip them (do not remove) if they are flagged selected. // Skip also not visible items. // But I think fields must not be deleted by a block delete command or other global command // because they are not really graphic items - while( item != drawings.end() ) + while( item != m_drawings.end() ) { if( item->Type() == LIB_FIELD_T ) { @@ -1472,25 +1463,17 @@ void LIB_PART::DeleteSelectedItems() if( !item->IsSelected() ) ++item; else - item = drawings.erase( item ); + item = m_drawings.erase( item ); } } void LIB_PART::CopySelectedItems( const wxPoint& aOffset ) { - /* *do not* use iterators here, because new items - * are added to drawings that is a boost::ptr_vector. - * When push_back elements in buffer, - * a memory reallocation can happen and will break pointers - */ - unsigned icnt = drawings.size(); std::vector< LIB_ITEM* > tmp; - for( unsigned ii = 0; ii < icnt; ii++ ) + for( LIB_ITEM& item : m_drawings ) { - LIB_ITEM& item = drawings[ii]; - // We *do not* copy fields because they are unique for the whole component // so skip them (do not duplicate) if they are flagged selected. if( item.Type() == LIB_FIELD_T ) @@ -1502,11 +1485,15 @@ void LIB_PART::CopySelectedItems( const wxPoint& aOffset ) item.ClearFlags( SELECTED ); LIB_ITEM* newItem = (LIB_ITEM*) item.Clone(); newItem->SetFlags( SELECTED ); + + // When push_back elements in buffer, a memory reallocation can happen + // and will break pointers. + // So, push_back later. tmp.push_back( newItem ); } - for( unsigned ii = 0; ii < tmp.size(); ii++ ) - drawings.push_back( tmp[ii] ); + for( auto item : tmp) + m_drawings.push_back( item ); MoveSelectedItems( aOffset ); } @@ -1514,7 +1501,7 @@ void LIB_PART::CopySelectedItems( const wxPoint& aOffset ) void LIB_PART::MirrorSelectedItemsH( const wxPoint& aCenter ) { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( !item.IsSelected() ) continue; @@ -1527,7 +1514,7 @@ void LIB_PART::MirrorSelectedItemsH( const wxPoint& aCenter ) void LIB_PART::MirrorSelectedItemsV( const wxPoint& aCenter ) { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( !item.IsSelected() ) continue; @@ -1540,7 +1527,7 @@ void LIB_PART::MirrorSelectedItemsV( const wxPoint& aCenter ) void LIB_PART::RotateSelectedItems( const wxPoint& aCenter ) { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( !item.IsSelected() ) continue; @@ -1554,7 +1541,7 @@ void LIB_PART::RotateSelectedItems( const wxPoint& aCenter ) LIB_ITEM* LIB_PART::LocateDrawItem( int aUnit, int aConvert, KICAD_T aType, const wxPoint& aPoint ) { - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { if( ( aUnit && item.m_Unit && ( aUnit != item.m_Unit) ) || ( aConvert && item.m_Convert && ( aConvert != item.m_Convert ) ) @@ -1597,12 +1584,12 @@ void LIB_PART::SetUnitCount( int aCount ) if( aCount < m_unitCount ) { - LIB_ITEMS_LIST::ITERATOR i = drawings.begin(); + LIB_ITEMS_CONTAINER::ITERATOR i = m_drawings.begin(); - while( i != drawings.end() ) + while( i != m_drawings.end() ) { if( i->m_Unit > aCount ) - i = drawings.erase( i ); + i = m_drawings.erase( i ); else ++i; } @@ -1611,23 +1598,25 @@ void LIB_PART::SetUnitCount( int aCount ) { int prevCount = m_unitCount; - // We cannot use an iterator here, because when adding items in vector - // the buffer can be reallocated, that change the previous value of - // .begin() and .end() iterators and invalidate others iterators - unsigned imax = drawings.size(); - - for( unsigned ii = 0; ii < imax; ii++ ) + std::vector< LIB_ITEM* > tmp; + for( LIB_ITEM& item : m_drawings ) { - if( drawings[ii].m_Unit != 1 ) + if( item.m_Unit != 1 ) continue; for( int j = prevCount + 1; j <= aCount; j++ ) { - LIB_ITEM* newItem = (LIB_ITEM*) drawings[ii].Clone(); + LIB_ITEM* newItem = (LIB_ITEM*) item.Clone(); newItem->m_Unit = j; - drawings.push_back( newItem ); + + // We cannot use push_back here, because when adding items in vector + // the buffer can be reallocated, that change the previous value of + // .begin() and .end() iterators and invalidate others iterators + tmp.push_back( newItem ); } } + for( auto item : tmp ) + m_drawings.push_back( item ); } m_unitCount = aCount; @@ -1644,7 +1633,7 @@ void LIB_PART::SetConversion( bool aSetConvert ) { std::vector< LIB_ITEM* > tmp; // Temporarily store the duplicated pins here. - for( LIB_ITEM& item : drawings ) + for( LIB_ITEM& item : m_drawings ) { // Only pins are duplicated. if( item.Type() != LIB_PIN_T ) @@ -1660,18 +1649,18 @@ void LIB_PART::SetConversion( bool aSetConvert ) // Transfer the new pins to the LIB_PART. for( unsigned i = 0; i < tmp.size(); i++ ) - drawings.push_back( tmp[i] ); + m_drawings.push_back( tmp[i] ); } else { // Delete converted shape items because the converted shape does // not exist - LIB_ITEMS_LIST::ITERATOR i = drawings.begin(); + LIB_ITEMS_CONTAINER::ITERATOR i = m_drawings.begin(); - while( i != drawings.end() ) + while( i != m_drawings.end() ) { if( i->m_Convert > 1 ) - i = drawings.erase( i ); + i = m_drawings.erase( i ); else ++i; } diff --git a/eeschema/class_libentry.h b/eeschema/class_libentry.h index 7659ccd998..5d33e99ebb 100644 --- a/eeschema/class_libentry.h +++ b/eeschema/class_libentry.h @@ -236,8 +236,7 @@ class LIB_PART : public EDA_ITEM long m_dateModified; ///< Date the part was last modified. LIBRENTRYOPTIONS m_options; ///< Special part features such as POWER or NORMAL.) int m_unitCount; ///< Number of units (parts) per package. - LIB_ITEMS_MAP drawingsMap; ///< How to draw this part. - LIB_ITEMS_LIST drawings; ///< Wrapper to drawingsMap to present as a flat structure + LIB_ITEMS_CONTAINER m_drawings; ///< Drawing items of this part. wxArrayString m_FootprintList; /**< List of suitable footprint names for the part (wild card names accepted). */ LIB_ALIASES m_aliases; ///< List of alias object pointers associated with the @@ -683,19 +682,11 @@ public: /** * Return a reference to the draw item list. * - * @return LIB_ITEMS_LIST& - Reference to the draw item object list. + * @return LIB_ITEMS_CONTAINER& - Reference to the draw item object container. */ - LIB_ITEMS_LIST& GetDrawItemList() + LIB_ITEMS_CONTAINER& GetDrawItems() { - return drawings; - } - - /** - * Returns a reference to the draw item map that stores items per their type. - */ - LIB_ITEMS_MAP& GetDrawItemMap() - { - return drawingsMap; + return m_drawings; } /** diff --git a/eeschema/lib_collectors.cpp b/eeschema/lib_collectors.cpp index 2190388baf..1f922ab01b 100644 --- a/eeschema/lib_collectors.cpp +++ b/eeschema/lib_collectors.cpp @@ -111,7 +111,7 @@ SEARCH_RESULT LIB_COLLECTOR::Inspect( EDA_ITEM* aItem, void* testData ) } -void LIB_COLLECTOR::Collect( LIB_ITEMS_LIST& aItems, const KICAD_T aFilterList[], +void LIB_COLLECTOR::Collect( LIB_ITEMS_CONTAINER& aItems, const KICAD_T aFilterList[], const wxPoint& aPosition, int aUnit, int aConvert ) { Empty(); // empty the collection just in case @@ -124,9 +124,7 @@ void LIB_COLLECTOR::Collect( LIB_ITEMS_LIST& aItems, const KICAD_T aFilterList[] m_data.m_unit = aUnit; m_data.m_convert = aConvert; - for( size_t i = 0; i < aItems.size(); i++ ) - { - if( SEARCH_QUIT == aItems[i].Visit( m_inspector, NULL, m_ScanTypes ) ) + for( LIB_ITEM& item : aItems ) + if( SEARCH_QUIT == item.Visit( m_inspector, NULL, m_ScanTypes ) ) break; - } } diff --git a/eeschema/lib_collectors.h b/eeschema/lib_collectors.h index c875c452d5..143c18466b 100644 --- a/eeschema/lib_collectors.h +++ b/eeschema/lib_collectors.h @@ -30,7 +30,7 @@ #include -class LIB_ITEMS_LIST; +class LIB_ITEMS_CONTAINER; class LIB_COLLECTOR; @@ -128,7 +128,7 @@ public: * @param aUnit The unit of the items to collect or zero if all units. * @param aConvert The convert of the items to collect or zero if all conversions. */ - void Collect( LIB_ITEMS_LIST& aItem, const KICAD_T aFilterList[], const wxPoint& aPosition, + void Collect( LIB_ITEMS_CONTAINER& aItem, const KICAD_T aFilterList[], const wxPoint& aPosition, int aUnit = 0, int aConvert = 0 ); }; diff --git a/eeschema/lib_items.cpp b/eeschema/lib_items.cpp index fec8f46e6f..e245bfb81b 100644 --- a/eeschema/lib_items.cpp +++ b/eeschema/lib_items.cpp @@ -3,6 +3,7 @@ * * Copyright 2017 CERN * @author Maciej Suminski + * @author Bernhard Stegmaier * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,194 +29,169 @@ #include -LIB_ITEMS_LIST::ITERATOR::ITERATOR( LIB_ITEMS_MAP& aItems, int aType ) - : m_parent( &aItems ) +void LIB_ITEMS_CONTAINER::push_back( LIB_ITEM *aItem ) { - m_filter = ( aType != TYPE_NOT_INIT ); - m_type = m_filter ? aType : FIRST_TYPE; - m_it = (*m_parent)[m_type].begin(); - - // be sure the enum order is correct for the type - static_assert( (int) ( ITERATOR::FIRST_TYPE ) < (int) ( ITERATOR::LAST_TYPE ), - "fix FIRST_TYPE and LAST_TYPE definitions" ); - wxASSERT( m_type >= ITERATOR::FIRST_TYPE && m_type <= ITERATOR::LAST_TYPE ); + operator[]( aItem->Type() ).push_back( aItem ); } - -LIB_ITEMS_LIST::ITERATOR LIB_ITEMS_LIST::begin( int aType ) const +LIB_ITEMS_CONTAINER::ITERATOR LIB_ITEMS_CONTAINER::erase(const LIB_ITEMS_CONTAINER::ITERATOR &aIterator) { - LIB_ITEMS_LIST::ITERATOR it( m_data, aType ); - - if( it.m_filter ) // iterates over a specific type - { - it.m_it = (*it.m_parent)[it.m_type].begin(); - } - else // iterates over all items - { - // find a not empty container - auto i = m_data.begin(); - - while( i->second.empty() && i != m_data.end() ) - ++i; - - if( i == m_data.end() ) - --i; - - it.m_it = i->second.begin(); - it.m_type = i->first; - } - - return it; -} - - -LIB_ITEMS_LIST::ITERATOR LIB_ITEMS_LIST::end( int aType ) const -{ - LIB_ITEMS_LIST::ITERATOR it( m_data, aType ); - - if( it.m_filter ) // iterates over a specific type - { - it.m_it = (*it.m_parent)[it.m_type].end(); - } - else // iterates over all items - { - // find a not empty container, starting from the last type - auto i = m_data.rbegin(); - - while( i->second.empty() && i != m_data.rend() ) - ++i; - - if( i == m_data.rend() ) - --i; - - it.m_it = i->second.end(); - it.m_type = i->first; - } - - return it; -} - - -void LIB_ITEMS_LIST::push_back( LIB_ITEM* aItem ) -{ - wxASSERT( aItem->Type() >= ITERATOR::FIRST_TYPE && aItem->Type() <= ITERATOR::LAST_TYPE ); - m_data[aItem->Type()].push_back( aItem ); -} - - -LIB_ITEMS_LIST::ITERATOR LIB_ITEMS_LIST::erase( const ITERATOR& aIterator ) -{ - LIB_ITEMS_LIST::ITERATOR it( aIterator ); - it.m_it = (*aIterator.m_parent)[aIterator.m_type].erase( aIterator.m_it ); + LIB_ITEMS_CONTAINER::ITERATOR it( aIterator ); + it.m_it = (*aIterator.m_parent)[ aIterator.m_curType ].erase( aIterator.m_it ); it.validate(); return it; } - -size_t LIB_ITEMS_LIST::size() const +LIB_ITEMS_CONTAINER::ITERATOR LIB_ITEMS_CONTAINER::begin( int aType ) { - size_t counter = 0; - - for( auto& type : m_data ) - counter += type.second.size(); - - return counter; + size_t bucket = ( aType != TYPE_NOT_INIT ) ? aType : first(); + return ITERATOR( this, operator[]( bucket ).begin(), bucket, aType ); } - -bool LIB_ITEMS_LIST::empty() const +LIB_ITEMS_CONTAINER::ITERATOR LIB_ITEMS_CONTAINER::end(int aType) { - for( auto& type : m_data ) + size_t bucket = ( aType != TYPE_NOT_INIT ) ? aType : last(); + return ITERATOR( this, operator[]( bucket ).end(), bucket, aType ); +} + +LIB_ITEMS_CONTAINER::CONST_ITERATOR LIB_ITEMS_CONTAINER::begin( int aType ) const +{ + size_t bucket = ( aType != TYPE_NOT_INIT ) ? aType : first(); + return CONST_ITERATOR( this, operator[]( bucket ).begin(), bucket, aType ); +} + +LIB_ITEMS_CONTAINER::CONST_ITERATOR LIB_ITEMS_CONTAINER::end( int aType ) const +{ + size_t bucket = ( aType != TYPE_NOT_INIT ) ? aType : last(); + return CONST_ITERATOR( this, operator[]( bucket ).end(), bucket, aType ); +} + +size_t LIB_ITEMS_CONTAINER::size( int aType ) const +{ + if( aType != TYPE_NOT_INIT ) { - if( !type.second.empty() ) - return false; + return operator[]( aType ).size(); } - - return true; -} - - -void LIB_ITEMS_LIST::sort() -{ - for( auto& itemType : m_data ) - itemType.second.sort(); -} - - -LIB_ITEM& LIB_ITEMS_LIST::operator[]( unsigned int aIdx ) -{ - int counter = 0; - - for( auto& type : m_data ) + else { - if( aIdx < counter + type.second.size() ) - return type.second[aIdx - counter]; - else - counter += type.second.size(); - } + size_t cnt = 0; + for( int i = 0; i < TYPES_COUNT; ++i) + cnt += m_data[ i ].size(); - throw std::out_of_range( "LIB_ITEMS_LIST out of range" ); + return cnt; + } } - -const LIB_ITEM& LIB_ITEMS_LIST::operator[]( unsigned int aIdx ) const +bool LIB_ITEMS_CONTAINER::empty( int aType ) const { - int counter = 0; - - for( const auto& type : m_data ) - { - if( aIdx < counter + type.second.size() ) - return type.second[aIdx - counter]; - else - counter += type.second.size(); - } - - throw std::out_of_range( "LIB_ITEMS_LIST out of range" ); + return ( size( aType ) == 0 ); } - -LIB_ITEMS_LIST::ITERATOR& LIB_ITEMS_LIST::ITERATOR::operator++() +void LIB_ITEMS_CONTAINER::sort() { - if( m_it != (*m_parent)[m_type].end() ) + for( int i = 0; i < TYPES_COUNT; ++i ) + m_data[ i ].sort(); +} + +void LIB_ITEMS_CONTAINER::unique() +{ + for( int i = 0; i < TYPES_COUNT; ++i ) + m_data[ i ].unique(); +} + +LIB_ITEMS &LIB_ITEMS_CONTAINER::operator[]( int aType ) +{ + if( ( aType < FIRST_TYPE ) || ( aType > LAST_TYPE ) ) + throw std::out_of_range( "LIB_ITEMS_CONTAINER out of range" ); + + return m_data[ aType - FIRST_TYPE ]; +} + +const LIB_ITEMS &LIB_ITEMS_CONTAINER::operator[]( int aType ) const +{ + if( ( aType < FIRST_TYPE ) || ( aType > LAST_TYPE ) ) + throw std::out_of_range( "LIB_ITEMS_CONTAINER out of range" ); + + return m_data[ aType - FIRST_TYPE ]; +} + +size_t LIB_ITEMS_CONTAINER::first() const +{ + int i = 0; + while( ( i < TYPES_COUNT ) && ( m_data[ i ].empty() ) ) + ++i; + + return ( i == TYPES_COUNT ) ? FIRST_TYPE : FIRST_TYPE + i; +} + +size_t LIB_ITEMS_CONTAINER::last() const +{ + int i = TYPES_COUNT - 1; + while( ( i >= 0 ) && ( m_data[ i ].empty() ) ) + --i; + + return ( i < 0 ) ? FIRST_TYPE : FIRST_TYPE + i; +} + +template< typename ITEM_TYPE > +LIB_ITEMS_CONTAINER::ITERATOR_BASE& LIB_ITEMS_CONTAINER::ITERATOR_BASE::operator++() +{ + if( m_it != (*m_parent)[ m_curType ].end() ) ++m_it; - validate(); return *this; } - -bool LIB_ITEMS_LIST::ITERATOR::operator!=( const LIB_ITEMS_LIST::ITERATOR& aOther ) const +template< typename ITEM_TYPE > +bool LIB_ITEMS_CONTAINER::ITERATOR_BASE::operator!=(const LIB_ITEMS_CONTAINER::ITERATOR_BASE &aOther) const { - wxASSERT( aOther.m_parent == m_parent ); - wxASSERT( aOther.m_filter == m_filter ); - wxASSERT( !m_filter || aOther.m_type == m_type ); - + if( aOther.m_parent != m_parent ) + return true; + if( aOther.m_filter != m_filter ) + return true; + if( aOther.m_curType != m_curType ) + return true; return aOther.m_it != m_it; } +template< typename ITEM_TYPE > +LIB_ITEMS_CONTAINER::ITERATOR_BASE::ITERATOR_BASE( typename LIB_ITEMS_CONTAINER::ITERATOR_ADAPTER< ITEM_TYPE >::CONTAINER* aItems, + typename LIB_ITEMS_CONTAINER::ITERATOR_ADAPTER< ITEM_TYPE >::ITERATOR aIt, + int aBucket, int aType ) + : m_parent( aItems ) + , m_it( aIt ) + , m_curType( aBucket ) +{ + m_filter = ( aType != TYPE_NOT_INIT ); +} -void LIB_ITEMS_LIST::ITERATOR::validate() +template< typename ITEM_TYPE > +void LIB_ITEMS_CONTAINER::ITERATOR_BASE::validate() { // for all-items iterators (unfiltered): check if this is the end of the // current type container, if so switch to the next non-empty container - if( m_it == (*m_parent)[m_type].end() && !m_filter ) + if( !m_filter && m_it == (*m_parent)[ m_curType ].end() ) { - auto typeIt = m_parent->find( m_type ); - wxASSERT( typeIt != m_parent->end() ); - // switch to the next type (look for a not empty container) + int nextType = m_curType; do - ++typeIt; - while( typeIt != m_parent->end() && typeIt->second.empty() ); + ++nextType; + while( ( nextType <= LAST_TYPE ) && (*m_parent)[ nextType ].empty() ); // there is another not empty container, so make the iterator point to it, // otherwise it means the iterator points to the last item - if( typeIt != m_parent->end() ) + if( nextType <= LAST_TYPE ) { - m_it = typeIt->second.begin(); - m_type = typeIt->first; + m_curType = nextType; + m_it = (*m_parent)[ m_curType ].begin(); } } } + +/* + * Template instantiation for const/non-const iterator + */ +template class LIB_ITEMS_CONTAINER::ITERATOR_BASE< LIB_ITEM >; +template class LIB_ITEMS_CONTAINER::ITERATOR_BASE< const LIB_ITEM >; diff --git a/eeschema/lib_items.h b/eeschema/lib_items.h index 1a584ba0c0..7cf3e2a1a0 100644 --- a/eeschema/lib_items.h +++ b/eeschema/lib_items.h @@ -3,6 +3,7 @@ * * Copyright 2017 CERN * @author Maciej Suminski + * @author Bernhard Stegmaier * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -31,7 +32,6 @@ #include #include -#include class LIB_ITEM; @@ -43,89 +43,131 @@ class LIB_ITEM; */ typedef boost::ptr_vector LIB_ITEMS; -/** - * LIB_ITEM container to keep them sorted by their type. - */ -typedef std::map LIB_ITEMS_MAP; /** - * Wrapper for LIB_ITEMS_MAP to provide flat (list-like) access to the items - * stored in the map (@see LIB_ITEMS_MAP). + * LIB_ITEM container class. Provides both access as a flat list as well as + * access by type of item. */ -class LIB_ITEMS_LIST +class LIB_ITEMS_CONTAINER { public: - class ITERATOR + /** + * Compile-time helper class to define some types depending on const/non-const iterator. + */ + template< typename ITEM_TYPE > struct ITERATOR_ADAPTER; + + /** + * Generic implementation of a flat const/non-const iterator over contained items. + */ + template< typename ITEM_TYPE > class ITERATOR_BASE { public: - ITERATOR& operator++(); + ITERATOR_BASE& operator++(); - LIB_ITEM& operator*() + ITEM_TYPE& operator*() { return *m_it; } - LIB_ITEM* operator->() + ITEM_TYPE* operator->() { - return &(*m_it); + return &( *m_it ); } - bool operator!=( const ITERATOR& aOther ) const; + bool operator!=( const ITERATOR_BASE& aOther ) const; - private: + protected: /** * Constructor. * @param aItems is the container to wrap. + * @param aIt is the iterator to initialize this iterator (usually some begin() or end() + * iterator). + * @param aBucket is the type ID of the given iterator. * @param aType enables item type filtering. When aType is TYPE_NOT_INIT, there is no * filtering and all item types are accessible by the iterator. */ - ITERATOR( LIB_ITEMS_MAP& aItems, int aType = TYPE_NOT_INIT ); + ITERATOR_BASE( typename ITERATOR_ADAPTER::CONTAINER* aItems, + typename ITERATOR_ADAPTER::ITERATOR aIt, + int aBucket, int aType = TYPE_NOT_INIT ); ///> Assures the iterator is in a valid state. void validate(); ///> Wrapped container - LIB_ITEMS_MAP* m_parent; + typename ITERATOR_ADAPTER::CONTAINER* m_parent; + + ///> Iterator for one of the LIB_ITEMS containers stored in the map + typename ITERATOR_ADAPTER::ITERATOR m_it; ///> Flag indicating whether type filtering is enabled bool m_filter; ///> Type of the currently iterated items (@see KICAD_T) - int m_type; + int m_curType; - ///> Iterator for one of the LIB_ITEMS containers stored in the map - LIB_ITEMS::iterator m_it; - - // Range of valid types handled by the iterator - static constexpr KICAD_T FIRST_TYPE = LIB_ARC_T; - static constexpr KICAD_T LAST_TYPE = LIB_FIELD_T; - - friend class LIB_ITEMS_LIST; + friend class LIB_ITEMS_CONTAINER; }; + ///> The non-const iterator + typedef ITERATOR_BASE< LIB_ITEM > ITERATOR; + ///> The const iterator + typedef ITERATOR_BASE< const LIB_ITEM > CONST_ITERATOR; - LIB_ITEMS_LIST( LIB_ITEMS_MAP& aData ) - : m_data( aData ) + + LIB_ITEMS_CONTAINER() { } - ITERATOR begin( int aType = TYPE_NOT_INIT ) const; - ITERATOR end( int aType = TYPE_NOT_INIT ) const; - void push_back( LIB_ITEM* aItem ); ITERATOR erase( const ITERATOR& aIterator ); - size_t size() const; - bool empty() const; - void sort(); + ITERATOR begin( int aType = TYPE_NOT_INIT ); + ITERATOR end( int aType = TYPE_NOT_INIT ); + CONST_ITERATOR begin( int aType = TYPE_NOT_INIT ) const; + CONST_ITERATOR end( int aType = TYPE_NOT_INIT ) const; - LIB_ITEM& operator[]( unsigned int aIdx ); - const LIB_ITEM& operator[]( unsigned int aIdx ) const; + size_t size( int aType = TYPE_NOT_INIT ) const; + bool empty( int aType = TYPE_NOT_INIT ) const; + void sort(); + void unique(); + + LIB_ITEMS& operator[]( int aType ); + const LIB_ITEMS& operator[]( int aType ) const; + + // Range of valid types handled by the iterator + static constexpr KICAD_T FIRST_TYPE = LIB_ARC_T; + static constexpr KICAD_T LAST_TYPE = LIB_FIELD_T; + static constexpr size_t TYPES_COUNT = LAST_TYPE - FIRST_TYPE + 1; private: - ///> Wrapped container - LIB_ITEMS_MAP& m_data; + ///> Get first non-empty type or first type if all are empty. + size_t first() const; + + ///> Get last non-empty type or first type if all are empty. + size_t last() const; + + ///> Contained items by type + LIB_ITEMS m_data[ TYPES_COUNT ]; }; +/* + * Definitions for non-const iterator + */ +template<> +struct LIB_ITEMS_CONTAINER::ITERATOR_ADAPTER< LIB_ITEM > +{ + typedef LIB_ITEMS::iterator ITERATOR; + typedef LIB_ITEMS_CONTAINER CONTAINER; +}; + +/* + * Definitions for const iterator + */ +template<> +struct LIB_ITEMS_CONTAINER::ITERATOR_ADAPTER< const LIB_ITEM > +{ + typedef LIB_ITEMS::const_iterator ITERATOR; + typedef const LIB_ITEMS_CONTAINER CONTAINER; +}; #endif /* LIB_ITEMS_H */ diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp index 9200ef1cfa..3355ae8298 100644 --- a/eeschema/libeditframe.cpp +++ b/eeschema/libeditframe.cpp @@ -1315,7 +1315,7 @@ LIB_ITEM* LIB_EDIT_FRAME::locateItem( const wxPoint& aPosition, const KICAD_T aF LIB_ITEM* item = NULL; - m_collectedItems.Collect( part->GetDrawItemList(), aFilterList, aPosition, + m_collectedItems.Collect( part->GetDrawItems(), aFilterList, aPosition, m_unit, m_convert ); if( m_collectedItems.GetCount() == 0 ) diff --git a/eeschema/symbedit.cpp b/eeschema/symbedit.cpp index d02a618a63..004bf4ed3b 100644 --- a/eeschema/symbedit.cpp +++ b/eeschema/symbedit.cpp @@ -110,7 +110,7 @@ void LIB_EDIT_FRAME::LoadOneSymbol() wxCHECK_RET( !aliasNames.IsEmpty(), "No aliases found in library " + filename ); LIB_PART* first = lib->FindAlias( aliasNames[0] )->GetPart(); - LIB_ITEMS_LIST& drawList = first->GetDrawItemList(); + LIB_ITEMS_CONTAINER& drawList = first->GetDrawItems(); for( LIB_ITEM& item : drawList ) { @@ -146,7 +146,7 @@ void LIB_EDIT_FRAME::SaveOneSymbol() SEARCH_STACK* search = prj.SchSearchS(); LIB_PART* part = GetCurPart(); - if( !part || part->GetDrawItemList().empty() ) + if( !part || part->GetDrawItems().empty() ) return; wxString default_path = prj.GetRString( PROJECT::SCH_LIB_PATH ); @@ -213,7 +213,7 @@ void LIB_EDIT_FRAME::SaveOneSymbol() part->GetValueField().Save( formatter ); formatter.Print( 0, "DRAW\n" ); - LIB_ITEMS_LIST& drawList = part->GetDrawItemList(); + LIB_ITEMS_CONTAINER& drawList = part->GetDrawItems(); for( LIB_ITEM& item : drawList ) {