improve class observable

This commit is contained in:
decimad 2017-01-02 08:17:10 +01:00 committed by Maciej Suminski
parent 5a4e247564
commit 32a125a767
2 changed files with 67 additions and 42 deletions

View File

@ -62,20 +62,39 @@ namespace UTIL {
{ {
} }
void OBSERVABLE_BASE::IMPL::enter_iteration()
{
++iteration_count_;
}
void OBSERVABLE_BASE::IMPL::leave_iteration()
{
--iteration_count_;
if(iteration_count_ == 0) {
collect();
}
}
bool OBSERVABLE_BASE::IMPL::is_iterating() const
{
return iteration_count_ != 0;
}
void OBSERVABLE_BASE::IMPL::add_observer( void* observer )
{
assert( !is_iterating() );
observers_.push_back( observer );
}
void OBSERVABLE_BASE::IMPL::remove_observer( void* observer ) void OBSERVABLE_BASE::IMPL::remove_observer( void* observer )
{ {
if(iteration_count_) { auto it = std::find( observers_.begin(), observers_.end(), observer );
for(auto*& ptr : observers_) {
if(ptr == observer) { if(is_iterating()) {
ptr = nullptr; *it = nullptr;
}
}
} }
else { else {
collect(); observers_.erase( it );
if(observers_.empty() && owned_by_) {
owned_by_->on_observers_empty();
}
} }
} }
@ -122,6 +141,7 @@ namespace UTIL {
{ {
if(token_) { if(token_) {
token_->remove_observer( observer_ ); token_->remove_observer( observer_ );
token_.reset();
} }
} }
@ -140,19 +160,6 @@ namespace UTIL {
{ {
} }
size_t OBSERVABLE_BASE::size() const {
if(impl_) {
return impl_->observers_.size();
}
else {
return 0;
}
}
void OBSERVABLE_BASE::remove_observer( void* observer ) {
assert( impl_ );
impl_->remove_observer( observer );
}
void OBSERVABLE_BASE::allocate_impl() { void OBSERVABLE_BASE::allocate_impl() {
if(!impl_) { if(!impl_) {
@ -174,26 +181,47 @@ namespace UTIL {
impl_.reset(); impl_.reset();
} }
std::shared_ptr<OBSERVABLE_BASE::IMPL> OBSERVABLE_BASE::get_shared_impl()
{
allocate_shared_impl();
return impl_;
}
void OBSERVABLE_BASE::add_observer( void* observer ) {
allocate_impl();
impl_->add_observer( observer );
}
void OBSERVABLE_BASE::remove_observer( void* observer ) {
assert( impl_ );
impl_->remove_observer( observer );
}
void OBSERVABLE_BASE::enter_iteration() { void OBSERVABLE_BASE::enter_iteration() {
if(impl_) { if(impl_) {
++impl_->iteration_count_; impl_->enter_iteration();
} }
} }
void OBSERVABLE_BASE::leave_iteration() { void OBSERVABLE_BASE::leave_iteration() {
if(impl_) { if(impl_) {
--impl_->iteration_count_; impl_->leave_iteration();
if(impl_->iteration_count_ == 0) {
if(!impl_->is_shared() && impl_.use_count() == 1) { if( !impl_->is_iterating() && !impl_->is_shared() && impl_.use_count() == 1 ) {
impl_.reset(); impl_.reset();
}
else {
impl_->collect();
}
} }
} }
} }
size_t OBSERVABLE_BASE::size() const {
if(impl_) {
return impl_->observers_.size();
}
else {
return 0;
}
}
void OBSERVABLE_BASE::on_observers_empty() void OBSERVABLE_BASE::on_observers_empty()
{ {
// called by an impl that is owned by this, ie. it is a non-shared impl // called by an impl that is owned by this, ie. it is a non-shared impl
@ -201,16 +229,7 @@ namespace UTIL {
deallocate_impl(); deallocate_impl();
} }
std::shared_ptr<OBSERVABLE_BASE::IMPL> OBSERVABLE_BASE::get_shared_impl()
{
allocate_shared_impl();
return impl_;
}
void OBSERVABLE_BASE::add_observer( void* observer ) {
allocate_impl();
impl_->observers_.push_back( observer );
}
} }

View File

@ -64,9 +64,15 @@ namespace UTIL {
void set_shared(); void set_shared();
~IMPL(); ~IMPL();
void add_observer( void* observer );
void remove_observer( void* observer ); void remove_observer( void* observer );
void collect(); void collect();
bool is_iterating() const;
void enter_iteration();
void leave_iteration();
std::vector<void*> observers_; std::vector<void*> observers_;
unsigned int iteration_count_; unsigned int iteration_count_;
OBSERVABLE_BASE* owned_by_; OBSERVABLE_BASE* owned_by_;
@ -147,7 +153,7 @@ namespace UTIL {
*/ */
void SubscribeUnmanaged( ObserverInterface* aObserver ) void SubscribeUnmanaged( ObserverInterface* aObserver )
{ {
return OBSERVABLE_BASE::add_observer_unmanaged( static_cast<void*>(aObserver) ); OBSERVABLE_BASE::add_observer( static_cast<void*>(aObserver) );
} }
/** /**