* improve performance of big maps loading, undo/redo dramatically

determinant factor is amount of nodes in one container
This commit is contained in:
Garux 2021-03-20 02:29:11 +03:00
parent c0c9f49433
commit 812679236d
2 changed files with 69 additions and 21 deletions

View File

@ -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.
/// It's illegal to modify inserted values directly!
/// \param Value Uniquely identifies itself. Must provide a copy-constructor and an equality operator.
template<typename Value>
class UnsortedSet
@ -69,6 +70,38 @@ typedef typename Values::iterator iterator;
typedef typename Values::const_iterator const_iterator;
typedef typename Values::reverse_iterator 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(){
return m_values.begin();
@ -103,23 +136,32 @@ std::size_t size() const {
}
void clear(){
m_values.clear();
m_set.clear();
}
void swap( UnsortedSet& other ){
std::swap( m_values, other.m_values );
std::swap( m_set, other.m_set );
}
iterator insert( const Value& value ){
ASSERT_MESSAGE( find( value ) == end(), "UnsortedSet::insert: already added" );
init_set();
m_values.push_back( value );
const bool inserted = m_set.emplace( --end() ).second;
ASSERT_MESSAGE( inserted, "UnsortedSet::insert: already added" );
return --end();
}
void erase( const Value& value ){
iterator i = find( value );
ASSERT_MESSAGE( i != end(), "UnsortedSet::erase: not found" );
m_values.erase( i );
init_set();
const auto it = m_set.find( value );
ASSERT_MESSAGE( it != m_set.end(), "UnsortedSet::erase: not found" );
m_values.erase( *it );
m_set.erase( it );
}
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 );
}
iterator find( const Value& value ){
return std::find( begin(), end(), value );
return m_values.find( value );
}
};

View File

@ -745,6 +745,10 @@ class GraphTreeNode
{
typedef std::map<std::pair<CopiedString, scene::Node*>, GraphTreeNode*> 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:
Reference<scene::Instance> m_instance;
GraphTreeNode* m_parent;
@ -761,6 +765,11 @@ GraphTreeNode( scene::Instance& instance ) : m_instance( instance ), m_parent( 0
m_instance.get().setChildSelectedChangedCallback( Callback() );
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(){
return m_childnodes.begin();
@ -775,25 +784,30 @@ size_type size() const {
bool empty() const {
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 i = m_childnodes.insert( value ).first;
( *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;
}
void erase( iterator i ){
m_list.erase( i->second->m_parentListIterator );
m_childnodes.erase( i );
}
iterator find( const key_type& 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(){
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 )
{
std::size_t index = 0;
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" );
gtk_tree_path_prepend_index( path, gint( node->getIndex() ) );
}
return path;