Turned LIB_ITEMS_CONTAINER into a template
This commit is contained in:
parent
55bc8da726
commit
1edaa8090d
|
@ -138,7 +138,6 @@ set( EESCHEMA_SRCS
|
||||||
lib_draw_item.cpp
|
lib_draw_item.cpp
|
||||||
lib_export.cpp
|
lib_export.cpp
|
||||||
lib_field.cpp
|
lib_field.cpp
|
||||||
lib_items.cpp
|
|
||||||
lib_pin.cpp
|
lib_pin.cpp
|
||||||
lib_polyline.cpp
|
lib_polyline.cpp
|
||||||
lib_rectangle.cpp
|
lib_rectangle.cpp
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
#include <lib_id.h>
|
#include <lib_id.h>
|
||||||
#include <lib_draw_item.h>
|
#include <lib_draw_item.h>
|
||||||
#include <lib_field.h>
|
#include <lib_field.h>
|
||||||
#include <lib_items.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <multivector.h>
|
||||||
|
|
||||||
class EDA_RECT;
|
class EDA_RECT;
|
||||||
class LINE_READER;
|
class LINE_READER;
|
||||||
|
@ -49,6 +49,8 @@ class LIB_FIELD;
|
||||||
typedef std::vector<LIB_ALIAS*> LIB_ALIASES;
|
typedef std::vector<LIB_ALIAS*> LIB_ALIASES;
|
||||||
typedef std::shared_ptr<LIB_PART> PART_SPTR; ///< shared pointer to LIB_PART
|
typedef std::shared_ptr<LIB_PART> PART_SPTR; ///< shared pointer to LIB_PART
|
||||||
typedef std::weak_ptr<LIB_PART> PART_REF; ///< weak pointer to LIB_PART
|
typedef std::weak_ptr<LIB_PART> PART_REF; ///< weak pointer to LIB_PART
|
||||||
|
typedef MULTIVECTOR<LIB_ITEM, LIB_ARC_T, LIB_FIELD_T> LIB_ITEMS_CONTAINER;
|
||||||
|
typedef LIB_ITEMS_CONTAINER::ITEM_PTR_VECTOR LIB_ITEMS;
|
||||||
|
|
||||||
|
|
||||||
/* values for member .m_options */
|
/* values for member .m_options */
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <general.h>
|
#include <general.h>
|
||||||
#include <transform.h>
|
#include <transform.h>
|
||||||
#include <lib_collectors.h>
|
#include <lib_collectors.h>
|
||||||
#include <lib_items.h>
|
|
||||||
|
|
||||||
|
|
||||||
const KICAD_T LIB_COLLECTOR::AllItems[] = {
|
const KICAD_T LIB_COLLECTOR::AllItems[] = {
|
||||||
|
|
|
@ -27,13 +27,10 @@
|
||||||
|
|
||||||
|
|
||||||
#include <class_collector.h>
|
#include <class_collector.h>
|
||||||
#include <lib_draw_item.h>
|
#include <class_libentry.h>
|
||||||
|
|
||||||
|
|
||||||
class LIB_ITEMS_CONTAINER;
|
|
||||||
class LIB_COLLECTOR;
|
class LIB_COLLECTOR;
|
||||||
|
|
||||||
|
|
||||||
class LIB_COLLECTOR_DATA
|
class LIB_COLLECTOR_DATA
|
||||||
{
|
{
|
||||||
int m_unit;
|
int m_unit;
|
||||||
|
|
|
@ -1,223 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright 2017 CERN
|
|
||||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
||||||
* @author Bernhard Stegmaier <stegmaier@sw-systems.de>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <lib_items.h>
|
|
||||||
#include <lib_draw_item.h>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <wx/debug.h>
|
|
||||||
|
|
||||||
|
|
||||||
void LIB_ITEMS_CONTAINER::push_back( LIB_ITEM* aItem )
|
|
||||||
{
|
|
||||||
operator[]( aItem->Type() ).push_back( aItem );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LIB_ITEMS_CONTAINER::ITERATOR LIB_ITEMS_CONTAINER::erase(
|
|
||||||
const LIB_ITEMS_CONTAINER::ITERATOR& aIterator )
|
|
||||||
{
|
|
||||||
LIB_ITEMS_CONTAINER::ITERATOR it( aIterator );
|
|
||||||
it.m_it = (*aIterator.m_parent)[ aIterator.m_curType ].erase( aIterator.m_it );
|
|
||||||
it.validate();
|
|
||||||
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LIB_ITEMS_CONTAINER::ITERATOR LIB_ITEMS_CONTAINER::begin( int aType )
|
|
||||||
{
|
|
||||||
size_t bucket = ( aType != TYPE_NOT_INIT ) ? aType : first();
|
|
||||||
return ITERATOR( this, operator[]( bucket ).begin(), bucket, aType );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LIB_ITEMS_CONTAINER::ITERATOR LIB_ITEMS_CONTAINER::end( int aType )
|
|
||||||
{
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
return operator[]( aType ).size();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
size_t cnt = 0;
|
|
||||||
|
|
||||||
for( int i = 0; i < TYPES_COUNT; ++i)
|
|
||||||
cnt += m_data[ i ].size();
|
|
||||||
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool LIB_ITEMS_CONTAINER::empty( int aType ) const
|
|
||||||
{
|
|
||||||
return ( size( aType ) == 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LIB_ITEMS_CONTAINER::sort()
|
|
||||||
{
|
|
||||||
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<ITEM_TYPE>& LIB_ITEMS_CONTAINER::ITERATOR_BASE<ITEM_TYPE>::operator++()
|
|
||||||
{
|
|
||||||
if( m_it != (*m_parent)[ m_curType ].end() )
|
|
||||||
++m_it;
|
|
||||||
|
|
||||||
validate();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template< typename ITEM_TYPE >
|
|
||||||
bool LIB_ITEMS_CONTAINER::ITERATOR_BASE<ITEM_TYPE>::operator!=(
|
|
||||||
const LIB_ITEMS_CONTAINER::ITERATOR_BASE<ITEM_TYPE>& aOther ) const
|
|
||||||
{
|
|
||||||
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<ITEM_TYPE>::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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template< typename ITEM_TYPE >
|
|
||||||
void LIB_ITEMS_CONTAINER::ITERATOR_BASE<ITEM_TYPE>::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_filter && m_it == (*m_parent)[ m_curType ].end() )
|
|
||||||
{
|
|
||||||
// switch to the next type (look for a not empty container)
|
|
||||||
int nextType = m_curType;
|
|
||||||
|
|
||||||
do
|
|
||||||
++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( nextType <= LAST_TYPE )
|
|
||||||
{
|
|
||||||
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 >;
|
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
||||||
*
|
|
||||||
* Copyright 2017 CERN
|
|
||||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
||||||
* @author Bernhard Stegmaier <stegmaier@sw-systems.de>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, you may find one here:
|
|
||||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
||||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
||||||
* or you may write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LIB_ITEMS_H
|
|
||||||
#define LIB_ITEMS_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LIB_ITEM containers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <core/typeinfo.h>
|
|
||||||
#include <boost/ptr_container/ptr_vector.hpp>
|
|
||||||
|
|
||||||
class LIB_ITEM;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for defining a list of library draw object pointers. The Boost
|
|
||||||
* pointer containers are responsible for deleting object pointers placed
|
|
||||||
* in them. If you access a object pointer from the list, do not delete
|
|
||||||
* it directly.
|
|
||||||
*/
|
|
||||||
typedef boost::ptr_vector<LIB_ITEM> LIB_ITEMS;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LIB_ITEM container class. Provides both access as a flat list as well as
|
|
||||||
* access by type of item.
|
|
||||||
*/
|
|
||||||
class LIB_ITEMS_CONTAINER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* 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_BASE& operator++();
|
|
||||||
|
|
||||||
ITEM_TYPE& operator*()
|
|
||||||
{
|
|
||||||
return *m_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
ITEM_TYPE* operator->()
|
|
||||||
{
|
|
||||||
return &( *m_it );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=( const ITERATOR_BASE& aOther ) const;
|
|
||||||
|
|
||||||
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_BASE( typename ITERATOR_ADAPTER<ITEM_TYPE>::CONTAINER* aItems,
|
|
||||||
typename ITERATOR_ADAPTER<ITEM_TYPE>::ITERATOR aIt,
|
|
||||||
int aBucket, int aType = TYPE_NOT_INIT );
|
|
||||||
|
|
||||||
///> Assures the iterator is in a valid state.
|
|
||||||
void validate();
|
|
||||||
|
|
||||||
///> Wrapped container
|
|
||||||
typename ITERATOR_ADAPTER<ITEM_TYPE>::CONTAINER* m_parent;
|
|
||||||
|
|
||||||
///> Iterator for one of the LIB_ITEMS containers stored in the map
|
|
||||||
typename ITERATOR_ADAPTER<ITEM_TYPE>::ITERATOR m_it;
|
|
||||||
|
|
||||||
///> Flag indicating whether type filtering is enabled
|
|
||||||
bool m_filter;
|
|
||||||
|
|
||||||
///> Type of the currently iterated items (@see KICAD_T)
|
|
||||||
int m_curType;
|
|
||||||
|
|
||||||
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_CONTAINER()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_back( LIB_ITEM* aItem );
|
|
||||||
ITERATOR erase( const ITERATOR& aIterator );
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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:
|
|
||||||
///> 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 */
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright 2017 CERN
|
||||||
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||||
|
* @author Bernhard Stegmaier <stegmaier@sw-systems.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MULTIVECTOR_H
|
||||||
|
#define MULTIVECTOR_H
|
||||||
|
|
||||||
|
#include <boost/ptr_container/ptr_vector.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multivector container type.
|
||||||
|
*
|
||||||
|
* Keeps items segregated by their type in multiple ptr_vectors. Provides both
|
||||||
|
* access as a flat list as well as access by type of item.
|
||||||
|
*
|
||||||
|
* T is the stored type, needs to provide Type() method used to segregate items.
|
||||||
|
* FIRST_TYPE_VAL is the lower boundary value of the types stored in the container.
|
||||||
|
* LAST_TYPE_VAL is the upper boundary value of the types stored in the container.
|
||||||
|
*/
|
||||||
|
template<typename T, int FIRST_TYPE_VAL, int LAST_TYPE_VAL>
|
||||||
|
class MULTIVECTOR
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Type value to indicate no specific type. Mostly used to access the container as a flat list
|
||||||
|
* or to return data for the whole container.
|
||||||
|
*/
|
||||||
|
static constexpr int UNDEFINED_TYPE = 0;
|
||||||
|
static_assert( FIRST_TYPE_VAL > UNDEFINED_TYPE, "FIRST_TYPE_VAL has to be greater than UNDEFINED_TYPE" );
|
||||||
|
static_assert( FIRST_TYPE_VAL < LAST_TYPE_VAL, "FIRST_TYPE_VAL has to be greater than LAST_TYPE_VAL" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for defining a list of library draw object pointers. The Boost
|
||||||
|
* pointer containers are responsible for deleting object pointers placed
|
||||||
|
* in them. If you access a object pointer from the list, do not delete
|
||||||
|
* it directly.
|
||||||
|
*/
|
||||||
|
typedef boost::ptr_vector<T> ITEM_PTR_VECTOR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic implementation of a flat const/non-const iterator over contained items.
|
||||||
|
*/
|
||||||
|
template<typename ITEM_TYPE, typename ITEM_CONTAINER, typename ITEM_CONTAINER_IT>
|
||||||
|
class ITERATOR_BASE
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ITEM_TYPE& operator*()
|
||||||
|
{
|
||||||
|
return *m_it;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITEM_TYPE* operator->()
|
||||||
|
{
|
||||||
|
return &( *m_it );
|
||||||
|
}
|
||||||
|
|
||||||
|
ITERATOR_BASE& operator++()
|
||||||
|
{
|
||||||
|
if( m_it != (*m_parent)[ m_curType ].end() )
|
||||||
|
++m_it;
|
||||||
|
|
||||||
|
validate();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=( const ITERATOR_BASE& aOther ) const
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 UNDEFINED_TYPE, there is no
|
||||||
|
* filtering and all item types are accessible by the iterator.
|
||||||
|
*/
|
||||||
|
ITERATOR_BASE( ITEM_CONTAINER* aItems, ITEM_CONTAINER_IT aIt,
|
||||||
|
int aBucket, int aType = UNDEFINED_TYPE )
|
||||||
|
: m_parent( aItems ), m_it( aIt ), m_curType( aBucket )
|
||||||
|
{
|
||||||
|
m_filter = ( aType != UNDEFINED_TYPE );
|
||||||
|
}
|
||||||
|
|
||||||
|
///> Assures the iterator is in a valid state.
|
||||||
|
void 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_filter && m_it == (*m_parent)[ m_curType ].end() )
|
||||||
|
{
|
||||||
|
// switch to the next type (look for a not empty container)
|
||||||
|
int nextType = m_curType;
|
||||||
|
|
||||||
|
do
|
||||||
|
++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( nextType <= LAST_TYPE )
|
||||||
|
{
|
||||||
|
m_curType = nextType;
|
||||||
|
m_it = (*m_parent)[ m_curType ].begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///> Wrapped container
|
||||||
|
ITEM_CONTAINER* m_parent;
|
||||||
|
|
||||||
|
///> Iterator for one of the ptr_vector containers stored in the array
|
||||||
|
ITEM_CONTAINER_IT m_it;
|
||||||
|
|
||||||
|
///> Flag indicating whether type filtering is enabled
|
||||||
|
bool m_filter;
|
||||||
|
|
||||||
|
///> Type of the currently iterated items
|
||||||
|
int m_curType;
|
||||||
|
|
||||||
|
friend class MULTIVECTOR;
|
||||||
|
};
|
||||||
|
|
||||||
|
///> The non-const iterator
|
||||||
|
typedef ITERATOR_BASE<T, MULTIVECTOR<T, FIRST_TYPE_VAL, LAST_TYPE_VAL>, typename ITEM_PTR_VECTOR::iterator> ITERATOR;
|
||||||
|
///> The const iterator
|
||||||
|
typedef ITERATOR_BASE<const T, const MULTIVECTOR<T, FIRST_TYPE_VAL, LAST_TYPE_VAL>, typename ITEM_PTR_VECTOR::const_iterator> CONST_ITERATOR;
|
||||||
|
|
||||||
|
|
||||||
|
MULTIVECTOR()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back( T* aItem )
|
||||||
|
{
|
||||||
|
operator[]( aItem->Type() ).push_back( aItem );
|
||||||
|
}
|
||||||
|
|
||||||
|
ITERATOR erase( const ITERATOR& aIterator )
|
||||||
|
{
|
||||||
|
ITERATOR it( aIterator );
|
||||||
|
it.m_it = (*aIterator.m_parent)[ aIterator.m_curType ].erase( aIterator.m_it );
|
||||||
|
it.validate();
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITERATOR begin( int aType = UNDEFINED_TYPE )
|
||||||
|
{
|
||||||
|
int bucket = ( aType != UNDEFINED_TYPE ) ? aType : first();
|
||||||
|
return ITERATOR( this, operator[]( bucket ).begin(), bucket, aType );
|
||||||
|
}
|
||||||
|
|
||||||
|
ITERATOR end( int aType = UNDEFINED_TYPE )
|
||||||
|
{
|
||||||
|
int bucket = ( aType != UNDEFINED_TYPE ) ? aType : last();
|
||||||
|
return ITERATOR( this, operator[]( bucket ).end(), bucket, aType );
|
||||||
|
}
|
||||||
|
|
||||||
|
CONST_ITERATOR begin( int aType = UNDEFINED_TYPE ) const
|
||||||
|
{
|
||||||
|
int bucket = ( aType != UNDEFINED_TYPE ) ? aType : first();
|
||||||
|
return CONST_ITERATOR( this, operator[]( bucket ).begin(), bucket, aType );
|
||||||
|
}
|
||||||
|
|
||||||
|
CONST_ITERATOR end( int aType = UNDEFINED_TYPE ) const
|
||||||
|
{
|
||||||
|
int bucket = ( aType != UNDEFINED_TYPE ) ? aType : last();
|
||||||
|
return CONST_ITERATOR( this, operator[]( bucket ).end(), bucket, aType );
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size( int aType = UNDEFINED_TYPE )
|
||||||
|
{
|
||||||
|
if( aType != UNDEFINED_TYPE )
|
||||||
|
{
|
||||||
|
return operator[]( aType ).size();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t cnt = 0;
|
||||||
|
|
||||||
|
for( int i = 0; i < TYPES_COUNT; ++i)
|
||||||
|
cnt += m_data[ i ].size();
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty( int aType = UNDEFINED_TYPE )
|
||||||
|
{
|
||||||
|
return ( size( aType ) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void sort()
|
||||||
|
{
|
||||||
|
for( int i = 0; i < TYPES_COUNT; ++i )
|
||||||
|
m_data[ i ].sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void unique()
|
||||||
|
{
|
||||||
|
for( int i = 0; i < TYPES_COUNT; ++i )
|
||||||
|
m_data[ i ].unique();
|
||||||
|
}
|
||||||
|
|
||||||
|
ITEM_PTR_VECTOR& operator[]( int aType )
|
||||||
|
{
|
||||||
|
if( ( aType < FIRST_TYPE ) || ( aType > LAST_TYPE ) )
|
||||||
|
throw std::out_of_range( "MULTIVECTOR out of range" );
|
||||||
|
|
||||||
|
return m_data[ aType - FIRST_TYPE ];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ITEM_PTR_VECTOR& operator[]( int aType ) const
|
||||||
|
{
|
||||||
|
if( ( aType < FIRST_TYPE ) || ( aType > LAST_TYPE ) )
|
||||||
|
throw std::out_of_range( "MULTIVECTOR out of range" );
|
||||||
|
|
||||||
|
return m_data[ aType - FIRST_TYPE ];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range of valid types handled by the iterator
|
||||||
|
static constexpr int FIRST_TYPE = FIRST_TYPE_VAL;
|
||||||
|
static constexpr int LAST_TYPE = LAST_TYPE_VAL;
|
||||||
|
static constexpr size_t TYPES_COUNT = LAST_TYPE - FIRST_TYPE + 1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
///> Get first non-empty type or first type if all are empty.
|
||||||
|
int first() const
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while( ( i < TYPES_COUNT ) && ( m_data[ i ].empty() ) )
|
||||||
|
++i;
|
||||||
|
|
||||||
|
return ( i == TYPES_COUNT ) ? FIRST_TYPE : FIRST_TYPE + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///> Get last non-empty type or first type if all are empty.
|
||||||
|
int last() const
|
||||||
|
{
|
||||||
|
int i = TYPES_COUNT - 1;
|
||||||
|
|
||||||
|
while( ( i >= 0 ) && ( m_data[ i ].empty() ) )
|
||||||
|
--i;
|
||||||
|
|
||||||
|
return ( i < 0 ) ? FIRST_TYPE : FIRST_TYPE + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
///> Contained items by type
|
||||||
|
ITEM_PTR_VECTOR m_data[TYPES_COUNT];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MULTIVECTOR_H */
|
Loading…
Reference in New Issue