You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
5.8 KiB

  1. /*
  2. * This program source code file is part of KICAD, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 Kicad Developers, see change_log.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include "observable.h"
  24. #include <algorithm>
  25. namespace UTIL {
  26. namespace DETAIL {
  27. template<typename T>
  28. struct equals {
  29. equals( const T& val ) : val_( val ) {}
  30. bool operator()( const T& val ) const
  31. {
  32. return val == val_;
  33. }
  34. private:
  35. const T& val_;
  36. };
  37. OBSERVABLE_BASE::IMPL::IMPL( OBSERVABLE_BASE* owned_by )
  38. : iteration_count_( 0 ), owned_by_( owned_by )
  39. {}
  40. bool OBSERVABLE_BASE::IMPL::is_shared() const
  41. {
  42. return owned_by_ == nullptr;
  43. }
  44. void OBSERVABLE_BASE::IMPL::set_shared()
  45. {
  46. owned_by_ = nullptr;
  47. }
  48. OBSERVABLE_BASE::IMPL::~IMPL()
  49. {
  50. }
  51. void OBSERVABLE_BASE::IMPL::enter_iteration()
  52. {
  53. ++iteration_count_;
  54. }
  55. void OBSERVABLE_BASE::IMPL::leave_iteration()
  56. {
  57. --iteration_count_;
  58. if( iteration_count_ == 0 )
  59. collect();
  60. }
  61. bool OBSERVABLE_BASE::IMPL::is_iterating() const
  62. {
  63. return iteration_count_ != 0;
  64. }
  65. void OBSERVABLE_BASE::IMPL::add_observer( void* observer )
  66. {
  67. assert( !is_iterating() );
  68. observers_.push_back( observer );
  69. }
  70. void OBSERVABLE_BASE::IMPL::remove_observer( void* observer )
  71. {
  72. auto it = std::find( observers_.begin(), observers_.end(), observer );
  73. if( it == observers_.end() )
  74. {
  75. assert( false );
  76. return;
  77. }
  78. if( is_iterating() )
  79. *it = nullptr;
  80. else
  81. observers_.erase( it );
  82. }
  83. void OBSERVABLE_BASE::IMPL::collect()
  84. {
  85. auto it = std::remove_if( observers_.begin(), observers_.end(), DETAIL::equals<void*>( nullptr ) );
  86. observers_.erase( it, observers_.end() );
  87. }
  88. }
  89. LINK::LINK()
  90. : observer_( nullptr )
  91. {
  92. }
  93. LINK::LINK( std::shared_ptr<DETAIL::OBSERVABLE_BASE::IMPL> token, void* observer )
  94. : token_( std::move( token ) ), observer_( observer )
  95. {
  96. }
  97. LINK::LINK( LINK&& other )
  98. : token_( std::move( other.token_ ) ), observer_( other.observer_ )
  99. {
  100. other.token_.reset();
  101. }
  102. LINK& LINK::operator=( LINK&& other )
  103. {
  104. token_ = std::move( other.token_ );
  105. other.token_.reset();
  106. observer_ = other.observer_;
  107. return *this;
  108. }
  109. LINK::operator bool() const
  110. {
  111. return token_ ? true : false;
  112. }
  113. LINK::~LINK()
  114. {
  115. reset();
  116. }
  117. void LINK::reset()
  118. {
  119. if(token_)
  120. {
  121. token_->remove_observer( observer_ );
  122. token_.reset();
  123. }
  124. }
  125. namespace DETAIL {
  126. OBSERVABLE_BASE::OBSERVABLE_BASE()
  127. {
  128. }
  129. OBSERVABLE_BASE::OBSERVABLE_BASE( OBSERVABLE_BASE& other )
  130. : impl_( other.get_shared_impl() )
  131. {
  132. }
  133. OBSERVABLE_BASE::~OBSERVABLE_BASE()
  134. {
  135. }
  136. void OBSERVABLE_BASE::allocate_impl()
  137. {
  138. if(!impl_)
  139. impl_ = std::make_shared<IMPL>( this );
  140. }
  141. void OBSERVABLE_BASE::allocate_shared_impl()
  142. {
  143. if(!impl_)
  144. impl_ = std::make_shared<IMPL>();
  145. else
  146. impl_->set_shared();
  147. }
  148. void OBSERVABLE_BASE::deallocate_impl() {
  149. impl_.reset();
  150. }
  151. std::shared_ptr<OBSERVABLE_BASE::IMPL> OBSERVABLE_BASE::get_shared_impl()
  152. {
  153. allocate_shared_impl();
  154. return impl_;
  155. }
  156. void OBSERVABLE_BASE::add_observer( void* observer )
  157. {
  158. allocate_impl();
  159. impl_->add_observer( observer );
  160. }
  161. void OBSERVABLE_BASE::remove_observer( void* observer )
  162. {
  163. assert( impl_ );
  164. impl_->remove_observer( observer );
  165. }
  166. void OBSERVABLE_BASE::enter_iteration()
  167. {
  168. if( impl_ )
  169. impl_->enter_iteration();
  170. }
  171. void OBSERVABLE_BASE::leave_iteration()
  172. {
  173. if( impl_)
  174. {
  175. impl_->leave_iteration();
  176. if( !impl_->is_iterating() && !impl_->is_shared() && impl_.use_count() == 1 )
  177. impl_.reset();
  178. }
  179. }
  180. size_t OBSERVABLE_BASE::size() const
  181. {
  182. if( impl_ )
  183. return impl_->observers_.size();
  184. else
  185. return 0;
  186. }
  187. void OBSERVABLE_BASE::on_observers_empty()
  188. {
  189. // called by an impl that is owned by this, ie. it is a non-shared impl
  190. // also it is not iterating
  191. deallocate_impl();
  192. }
  193. }
  194. }