* improve performance of big maps loading, undo/redo dramatically
determinant factor is amount of nodes in one container
This commit is contained in:
parent
c0c9f49433
commit
812679236d
|
|
@ -58,6 +58,7 @@ const Type& get() const {
|
||||||
|
|
||||||
|
|
||||||
/// \brief An adaptor to make std::list into a Unique Sequence - which cannot contain the same value more than once.
|
/// \brief An adaptor to make std::list into a Unique Sequence - which cannot contain the same value more than once.
|
||||||
|
/// It's illegal to modify inserted values directly!
|
||||||
/// \param Value Uniquely identifies itself. Must provide a copy-constructor and an equality operator.
|
/// \param Value Uniquely identifies itself. Must provide a copy-constructor and an equality operator.
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
class UnsortedSet
|
class UnsortedSet
|
||||||
|
|
@ -69,6 +70,38 @@ typedef typename Values::iterator iterator;
|
||||||
typedef typename Values::const_iterator const_iterator;
|
typedef typename Values::const_iterator const_iterator;
|
||||||
typedef typename Values::reverse_iterator reverse_iterator;
|
typedef typename Values::reverse_iterator reverse_iterator;
|
||||||
typedef typename Values::const_reverse_iterator const_reverse_iterator;
|
typedef typename Values::const_reverse_iterator const_reverse_iterator;
|
||||||
|
private:
|
||||||
|
struct Compare{
|
||||||
|
using is_transparent = void;
|
||||||
|
|
||||||
|
bool operator()( const iterator& one, const iterator& other ) const {
|
||||||
|
return *one < *other;
|
||||||
|
}
|
||||||
|
bool operator()( const Value& va, const iterator& it ) const {
|
||||||
|
return va < *it;
|
||||||
|
}
|
||||||
|
bool operator()( const iterator& it, const Value& va ) const {
|
||||||
|
return *it < va;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::set<iterator, Compare> m_set; // store sorted iterators for fast lookup
|
||||||
|
void init_set(){ // only load set, when lookup is needed
|
||||||
|
if( m_set.empty() )
|
||||||
|
for( auto it = begin(); it != end(); ++it )
|
||||||
|
m_set.emplace( it );
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
UnsortedSet() = default;
|
||||||
|
UnsortedSet( const UnsortedSet& other ) : m_values( other.m_values ), m_set(){
|
||||||
|
}
|
||||||
|
UnsortedSet( UnsortedSet&& ) noexcept = default;
|
||||||
|
UnsortedSet& operator=( const UnsortedSet& other ){
|
||||||
|
m_values = other.m_values;
|
||||||
|
m_set.clear();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
UnsortedSet& operator=( UnsortedSet&& ) noexcept = default;
|
||||||
|
|
||||||
iterator begin(){
|
iterator begin(){
|
||||||
return m_values.begin();
|
return m_values.begin();
|
||||||
|
|
@ -103,23 +136,32 @@ std::size_t size() const {
|
||||||
}
|
}
|
||||||
void clear(){
|
void clear(){
|
||||||
m_values.clear();
|
m_values.clear();
|
||||||
|
m_set.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap( UnsortedSet& other ){
|
void swap( UnsortedSet& other ){
|
||||||
std::swap( m_values, other.m_values );
|
std::swap( m_values, other.m_values );
|
||||||
|
std::swap( m_set, other.m_set );
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator insert( const Value& value ){
|
iterator insert( const Value& value ){
|
||||||
ASSERT_MESSAGE( find( value ) == end(), "UnsortedSet::insert: already added" );
|
init_set();
|
||||||
m_values.push_back( value );
|
m_values.push_back( value );
|
||||||
|
const bool inserted = m_set.emplace( --end() ).second;
|
||||||
|
ASSERT_MESSAGE( inserted, "UnsortedSet::insert: already added" );
|
||||||
return --end();
|
return --end();
|
||||||
}
|
}
|
||||||
void erase( const Value& value ){
|
void erase( const Value& value ){
|
||||||
iterator i = find( value );
|
init_set();
|
||||||
ASSERT_MESSAGE( i != end(), "UnsortedSet::erase: not found" );
|
const auto it = m_set.find( value );
|
||||||
m_values.erase( i );
|
ASSERT_MESSAGE( it != m_set.end(), "UnsortedSet::erase: not found" );
|
||||||
|
m_values.erase( *it );
|
||||||
|
m_set.erase( it );
|
||||||
}
|
}
|
||||||
iterator find( const Value& value ){
|
iterator find( const Value& value ){
|
||||||
return std::find( begin(), end(), value );
|
init_set();
|
||||||
|
const auto it = m_set.find( value );
|
||||||
|
return it == m_set.end()? m_values.end() : *it;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -274,7 +316,7 @@ void erase( const Value& value ){
|
||||||
m_values.erase( i );
|
m_values.erase( i );
|
||||||
}
|
}
|
||||||
iterator find( const Value& value ){
|
iterator find( const Value& value ){
|
||||||
return std::find( begin(), end(), value );
|
return m_values.find( value );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -745,6 +745,10 @@ class GraphTreeNode
|
||||||
{
|
{
|
||||||
typedef std::map<std::pair<CopiedString, scene::Node*>, GraphTreeNode*> ChildNodes;
|
typedef std::map<std::pair<CopiedString, scene::Node*>, GraphTreeNode*> ChildNodes;
|
||||||
ChildNodes m_childnodes;
|
ChildNodes m_childnodes;
|
||||||
|
|
||||||
|
std::list<char> m_list; // dummy list for child index identification
|
||||||
|
std::list<char>::const_iterator m_parentListIterator; // iterator from parent's list
|
||||||
|
bool m_searchFromEnd = false; //silly optimization
|
||||||
public:
|
public:
|
||||||
Reference<scene::Instance> m_instance;
|
Reference<scene::Instance> m_instance;
|
||||||
GraphTreeNode* m_parent;
|
GraphTreeNode* m_parent;
|
||||||
|
|
@ -761,6 +765,11 @@ GraphTreeNode( scene::Instance& instance ) : m_instance( instance ), m_parent( 0
|
||||||
m_instance.get().setChildSelectedChangedCallback( Callback() );
|
m_instance.get().setChildSelectedChangedCallback( Callback() );
|
||||||
ASSERT_MESSAGE( empty(), "GraphTreeNode::~GraphTreeNode: memory leak" );
|
ASSERT_MESSAGE( empty(), "GraphTreeNode::~GraphTreeNode: memory leak" );
|
||||||
}
|
}
|
||||||
|
GraphTreeNode() = delete;
|
||||||
|
GraphTreeNode( const GraphTreeNode& ) = delete;
|
||||||
|
GraphTreeNode( GraphTreeNode&& ) noexcept = delete;
|
||||||
|
GraphTreeNode& operator=( const GraphTreeNode& ) = delete;
|
||||||
|
GraphTreeNode& operator=( GraphTreeNode&& ) noexcept = delete;
|
||||||
|
|
||||||
iterator begin(){
|
iterator begin(){
|
||||||
return m_childnodes.begin();
|
return m_childnodes.begin();
|
||||||
|
|
@ -775,25 +784,30 @@ size_type size() const {
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return m_childnodes.empty();
|
return m_childnodes.empty();
|
||||||
}
|
}
|
||||||
|
// may not be called on the root node!
|
||||||
|
int getIndex() const {
|
||||||
|
const int idx = m_parent->m_searchFromEnd?
|
||||||
|
m_parent->m_list.size() - std::distance( m_parentListIterator, m_parent->m_list.cend() ) :
|
||||||
|
std::distance( m_parent->m_list.cbegin(), m_parentListIterator );
|
||||||
|
m_parent->m_searchFromEnd = idx * 2 > int( m_parent->size() );
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
iterator insert( const value_type& value ){
|
iterator insert( const value_type& value ){
|
||||||
iterator i = m_childnodes.insert( value ).first;
|
iterator i = m_childnodes.insert( value ).first;
|
||||||
( *i ).second->m_parent = this;
|
( *i ).second->m_parent = this;
|
||||||
|
const auto pos = std::next( i ) == end()? m_list.end() : std::next( i )->second->m_parentListIterator;
|
||||||
|
i->second->m_parentListIterator = m_list.insert( pos, 'a' );
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
void erase( iterator i ){
|
void erase( iterator i ){
|
||||||
|
m_list.erase( i->second->m_parentListIterator );
|
||||||
m_childnodes.erase( i );
|
m_childnodes.erase( i );
|
||||||
}
|
}
|
||||||
iterator find( const key_type& key ){
|
iterator find( const key_type& key ){
|
||||||
return m_childnodes.find( key );
|
return m_childnodes.find( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap( GraphTreeNode& other ){
|
|
||||||
std::swap( m_parent, other.m_parent );
|
|
||||||
std::swap( m_childnodes, other.m_childnodes );
|
|
||||||
std::swap( m_instance, other.m_instance );
|
|
||||||
}
|
|
||||||
|
|
||||||
void rowChanged(){
|
void rowChanged(){
|
||||||
graph_tree_model_row_changed( *this );
|
graph_tree_model_row_changed( *this );
|
||||||
}
|
}
|
||||||
|
|
@ -884,15 +898,7 @@ static GtkTreePath* graph_tree_model_get_path( GtkTreeModel* tree_model, GtkTree
|
||||||
|
|
||||||
for ( GraphTreeNode* node = ( *graph_iterator_read_tree_iter( iter ) ).second; node != graph; node = node->m_parent )
|
for ( GraphTreeNode* node = ( *graph_iterator_read_tree_iter( iter ) ).second; node != graph; node = node->m_parent )
|
||||||
{
|
{
|
||||||
std::size_t index = 0;
|
gtk_tree_path_prepend_index( path, gint( node->getIndex() ) );
|
||||||
for ( GraphTreeNode::iterator i = node->m_parent->begin(); i != node->m_parent->end(); ++i, ++index )
|
|
||||||
{
|
|
||||||
if ( ( *i ).second == node ) {
|
|
||||||
gtk_tree_path_prepend_index( path, gint( index ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT_MESSAGE( index != node->m_parent->size(), "error resolving tree path" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user