1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 #ifndef INCLUDED_SLIDESHOW_LISTENERCONTAINER_HXX 24 #define INCLUDED_SLIDESHOW_LISTENERCONTAINER_HXX 25 26 #include <osl/mutex.hxx> 27 #include <boost/version.hpp> 28 #if BOOST_VERSION < 106700 29 # include <boost/utility.hpp> 30 #else 31 # include <boost/next_prior.hpp> 32 #endif 33 #include <algorithm> 34 #include <vector> 35 36 #include "listenercontainerimpl.hxx" 37 38 namespace slideshow { 39 namespace internal { 40 41 /** Container for objects that can be notified. 42 43 This templatized container holds listener objects, than can get 44 notified (by calling certain methods on them). 45 46 @tpl Listener 47 Type for the listener objects to be held 48 49 @tpl ContainerT 50 Full type of the container to store the listener objects. Defaults 51 to std::vector<ListenerT> 52 53 @tpl MaxDeceasedListenerUllage 54 Threshold, from which upwards the listener container gets 55 pruned. Avoids frequent copying of nearly empty containers. 56 57 @attention internal class, not to be used. functionality is 58 incomplete, please use the Thread(Un)safeListenerContainer types 59 from below 60 */ 61 template< typename ListenerT, 62 typename MutexHolderBaseT, 63 typename ContainerT=std::vector<ListenerT>, 64 size_t MaxDeceasedListenerUllage=16 > class ListenerContainerBase : public MutexHolderBaseT 65 { 66 typedef typename MutexHolderBaseT::Guard Guard; 67 typedef typename MutexHolderBaseT::ClearableGuard ClearableGuard; 68 69 public: 70 typedef ListenerT listener_type; 71 typedef ContainerT container_type; 72 typedef MutexHolderBaseT mutex_type; 73 74 /** Check whether listener container is empty 75 76 @return true, if currently no listeners registered. Note that 77 in a multi-threaded scenario, without external synchronisation 78 to this object, the return value might become wrong at any time. 79 */ isEmpty() const80 bool isEmpty() const 81 { 82 Guard aGuard(*this); 83 return maListeners.empty(); 84 } 85 86 /** Check whether given listener is already added 87 88 @return true, if given listener is already added. 89 */ isAdded(listener_type const & rListener) const90 bool isAdded( listener_type const& rListener ) const 91 { 92 Guard aGuard(*this); 93 94 const typename container_type::const_iterator aEnd( maListeners.end() ); 95 if( std::find( maListeners.begin(), 96 aEnd, 97 rListener ) != aEnd ) 98 { 99 return true; // already added 100 } 101 102 return false; 103 } 104 105 /** Add new listener 106 107 @param rListener 108 Listener to add 109 110 @return false, if the listener is already added, true 111 otherwise 112 */ add(listener_type const & rListener)113 bool add( listener_type const& rListener ) 114 { 115 Guard aGuard(*this); 116 117 // ensure uniqueness 118 if( isAdded(rListener) ) 119 return false; // already added 120 121 maListeners.push_back( rListener ); 122 123 ListenerOperations<ListenerT>::pruneListeners( 124 maListeners, 125 MaxDeceasedListenerUllage); 126 127 return true; 128 } 129 130 /** Add new listener into sorted container 131 132 The stored listeners are kept sorted (using this method 133 requires listener_type to have operator< defined on it). Make 134 sure to call addSorted() for <em>each</em> listener to add to 135 this container - sorting is performed under the assumption 136 that existing entries are already sorted. 137 138 @param rListener 139 Listener to add 140 141 @return false, if the listener is already added, true 142 otherwise 143 */ addSorted(listener_type const & rListener)144 bool addSorted( listener_type const& rListener ) 145 { 146 Guard aGuard(*this); 147 148 // ensure uniqueness 149 if( isAdded(rListener) ) 150 return false; // already added 151 152 maListeners.push_back( rListener ); 153 154 // a single entry does not need to be sorted 155 if( maListeners.size() > 1 ) 156 { 157 std::inplace_merge( 158 maListeners.begin(), 159 boost::prior(maListeners.end()), 160 maListeners.end() ); 161 } 162 163 ListenerOperations<ListenerT>::pruneListeners( 164 maListeners, 165 MaxDeceasedListenerUllage); 166 167 return true; 168 } 169 170 /** Remove listener from container 171 172 @param rListener 173 The listener to remove 174 175 @return false, if listener not found in container, true 176 otherwise 177 */ remove(listener_type const & rListener)178 bool remove( listener_type const& rListener ) 179 { 180 Guard aGuard(*this); 181 182 const typename container_type::iterator aEnd( maListeners.end() ); 183 typename container_type::iterator aIter; 184 if( (aIter=std::remove(maListeners.begin(), 185 aEnd, 186 rListener)) == aEnd ) 187 { 188 return false; // listener not found 189 } 190 191 maListeners.erase( aIter, aEnd ); 192 193 return true; 194 } 195 196 /// Removes all listeners in one go clear()197 void clear() 198 { 199 Guard aGuard(*this); 200 201 maListeners.clear(); 202 } 203 204 /** Apply functor to one listener 205 206 This method applies functor to one of the listeners. Starting 207 with the first entry of the container, the functor is called 208 with the listener entries, until it returns true. 209 210 @param func 211 Given functor is called with listeners, until it returns true 212 213 @return true, if functor was successfully applied to a 214 listener 215 */ apply(FuncT func) const216 template< typename FuncT > bool apply( FuncT func ) const 217 { 218 ClearableGuard aGuard(*this); 219 220 // generate a local copy of all handlers, to make method 221 // reentrant and thread-safe. 222 container_type const local( maListeners ); 223 aGuard.clear(); 224 225 const bool bRet( 226 ListenerOperations<ListenerT>::notifySingleListener( 227 local, 228 func )); 229 230 { 231 Guard aGuard2(*this); 232 ListenerOperations<ListenerT>::pruneListeners( 233 const_cast<container_type&>(maListeners), 234 MaxDeceasedListenerUllage); 235 } 236 237 return bRet; 238 } 239 240 /** Apply functor to all listeners 241 242 This method applies functor to all of the listeners. Starting 243 with the first entry of the container, the functor is called 244 with the listener entries. 245 246 @param func 247 Given functor is called with listeners. 248 249 @return true, if functor was successfully applied to at least 250 one listener 251 */ applyAll(FuncT func) const252 template< typename FuncT > bool applyAll( FuncT func ) const 253 { 254 ClearableGuard aGuard(*this); 255 256 // generate a local copy of all handlers, to make method 257 // reentrant and thread-safe. 258 container_type const local( maListeners ); 259 aGuard.clear(); 260 261 const bool bRet( 262 ListenerOperations<ListenerT>::notifyAllListeners( 263 local, 264 func )); 265 266 { 267 Guard aGuard2(*this); 268 ListenerOperations<ListenerT>::pruneListeners( 269 const_cast<container_type&>(maListeners), 270 MaxDeceasedListenerUllage); 271 } 272 273 return bRet; 274 } 275 276 private: 277 ContainerT maListeners; 278 }; 279 280 //////////////////////////////////////////////////////////////////////////// 281 282 /** ListenerContainer variant that serialized access 283 284 This ListenerContainer is safe to use in a multi-threaded 285 context. It serializes access to the object, and avoids 286 dead-locking by releasing the object mutex before calling 287 listeners. 288 */ 289 template< typename ListenerT, 290 typename ContainerT=std::vector<ListenerT> > 291 class ThreadSafeListenerContainer : public ListenerContainerBase<ListenerT, 292 MutexBase, 293 ContainerT> 294 { 295 }; 296 297 //////////////////////////////////////////////////////////////////////////// 298 299 /** ListenerContainer variant that does not serialize access 300 301 This ListenerContainer version is not safe to use in a 302 multi-threaded scenario, but has less overhead. 303 */ 304 template< typename ListenerT, 305 typename ContainerT=std::vector<ListenerT> > 306 class ThreadUnsafeListenerContainer : public ListenerContainerBase<ListenerT, 307 EmptyBase, 308 ContainerT> 309 { 310 }; 311 312 } // namespace internal 313 } // namespace slideshow 314 315 #endif /* INCLUDED_SLIDESHOW_LISTENERCONTAINER_HXX */ 316 317