LibreOffice Module slideshow (master) 1
listenercontainer.hxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
20#define INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
21
22#include <algorithm>
23#include <memory>
24#include <vector>
25#include <iterator>
26
27namespace slideshow::internal {
28
30{
31 struct EmptyGuard{ explicit EmptyGuard(EmptyBase) {} };
33 {
35 static void clear() {}
36 };
37
40};
41
42template< typename result_type, typename ListenerTargetT > struct FunctionApply
43{
44 template<typename FuncT> static bool apply(
45 FuncT func,
46 ListenerTargetT const& rArg )
47 {
48 return func(rArg);
49 }
50};
51
52template<typename ListenerTargetT> struct FunctionApply<void,ListenerTargetT>
53{
54 template<typename FuncT> static bool apply(
55 FuncT func,
56 ListenerTargetT const& rArg )
57 {
58 func(rArg);
59 return true;
60 }
61};
62
63template< typename ListenerT > struct ListenerOperations
64{
66 template< typename ContainerT,
67 typename FuncT >
68 static bool notifySingleListener( ContainerT& rContainer,
69 FuncT func )
70 {
71 // true: a handler in this queue processed the event
72 // false: no handler in this queue finally processed the event
73 return std::any_of( rContainer.begin(),
74 rContainer.end(),
75 func );
76 }
77
79 template< typename ContainerT,
80 typename FuncT >
81 static bool notifyAllListeners( ContainerT& rContainer,
82 FuncT func )
83 {
84 bool bRet(false);
85 for( const auto& rCurr : rContainer )
86 {
87 if( FunctionApply< typename ::std::invoke_result< FuncT, const typename ContainerT::value_type& >::type,
88 typename ContainerT::value_type >::apply(
89 func,
90 rCurr) )
91 {
92 bRet = true;
93 }
94 }
95
96 // true: at least one handler returned true
97 // false: not a single handler returned true
98 return bRet;
99 }
100
102 template< typename ContainerT >
103 static void pruneListeners( ContainerT&, size_t )
104 {
105 }
106};
107
108template< typename ListenerTargetT >
109struct ListenerOperations< std::weak_ptr<ListenerTargetT> >
110{
111 template< typename ContainerT,
112 typename FuncT >
113 static bool notifySingleListener( ContainerT& rContainer,
114 FuncT func )
115 {
116 for( const auto& rCurr : rContainer )
117 {
118 std::shared_ptr<ListenerTargetT> pListener( rCurr.lock() );
119
120 if( pListener && func(pListener) )
121 return true;
122 }
123
124 return false;
125 }
126
127 template< typename ContainerT,
128 typename FuncT >
129 static bool notifyAllListeners( ContainerT& rContainer,
130 FuncT func )
131 {
132 bool bRet(false);
133 for( const auto& rCurr : rContainer )
134 {
135 std::shared_ptr<ListenerTargetT> pListener( rCurr.lock() );
136
137 if( pListener.get() &&
138 FunctionApply<typename ::std::invoke_result<FuncT, std::shared_ptr<ListenerTargetT> const&>::type,
139 std::shared_ptr<ListenerTargetT> >::apply(func,pListener) )
140 {
141 bRet = true;
142 }
143 }
144
145 return bRet;
146 }
147 template< typename ContainerT >
148 static void pruneListeners( ContainerT& rContainer,
149 size_t nSizeThreshold )
150 {
151 if( rContainer.size() <= nSizeThreshold )
152 return;
153
154 ContainerT aAliveListeners;
155 aAliveListeners.reserve(rContainer.size());
156
157 for( const auto& rCurr : rContainer )
158 {
159 if( !rCurr.expired() )
160 aAliveListeners.push_back( rCurr );
161 }
162
163 std::swap( rContainer, aAliveListeners );
164 }
165};
166
187template< typename ListenerT,
188 typename MutexHolderBaseT,
189 typename ContainerT=std::vector<ListenerT>,
190 size_t MaxDeceasedListenerUllage=16 > class ListenerContainerBase : public MutexHolderBaseT
191{
192 typedef typename MutexHolderBaseT::Guard Guard;
193 typedef typename MutexHolderBaseT::ClearableGuard ClearableGuard;
194
195public:
196 typedef ListenerT listener_type;
197 typedef ContainerT container_type;
198
205 bool isEmpty() const
206 {
207 Guard aGuard(*this);
208 return maListeners.empty();
209 }
210
215 bool isAdded( listener_type const& rListener ) const
216 {
217 Guard aGuard(*this);
218
219 const typename container_type::const_iterator aEnd( maListeners.end() );
220 if( std::find( maListeners.begin(),
221 aEnd,
222 rListener ) != aEnd )
223 {
224 return true; // already added
225 }
226
227 return false;
228 }
229
235 void add( listener_type const& rListener )
236 {
237 Guard aGuard(*this);
238
239 // ensure uniqueness
240 if( isAdded(rListener) )
241 return; // already added
242
243 maListeners.push_back( rListener );
244
247 MaxDeceasedListenerUllage);
248 }
249
264 bool addSorted( listener_type const& rListener )
265 {
266 Guard aGuard(*this);
267
268 // ensure uniqueness
269 if( isAdded(rListener) )
270 return false; // already added
271
272 maListeners.push_back( rListener );
273
274 // a single entry does not need to be sorted
275 if( maListeners.size() > 1 )
276 {
277 std::inplace_merge(
278 maListeners.begin(),
279 std::prev(maListeners.end()),
280 maListeners.end() );
281 }
282
285 MaxDeceasedListenerUllage);
286
287 return true;
288 }
289
298 bool remove( listener_type const& rListener )
299 {
300 Guard aGuard(*this);
301
302 const typename container_type::iterator aEnd( maListeners.end() );
303 typename container_type::iterator aIter;
304 if( (aIter=std::remove(maListeners.begin(),
305 aEnd,
306 rListener)) == aEnd )
307 {
308 return false; // listener not found
309 }
310
311 maListeners.erase( aIter, aEnd );
312
313 return true;
314 }
315
317 void clear()
318 {
319 Guard aGuard(*this);
320
321 maListeners.clear();
322 }
323
336 template< typename FuncT > bool apply( FuncT func ) const
337 {
338 ClearableGuard aGuard(*this);
339
340 // generate a local copy of all handlers, to make method
341 // reentrant and thread-safe.
342 container_type const local( maListeners );
343 aGuard.clear();
344
345 const bool bRet(
347 local,
348 func ));
349
350 {
351 Guard aGuard2(*this);
353 const_cast<container_type&>(maListeners),
354 MaxDeceasedListenerUllage);
355 }
356
357 return bRet;
358 }
359
372 template< typename FuncT > bool applyAll( FuncT func ) const
373 {
374 ClearableGuard aGuard(*this);
375
376 // generate a local copy of all handlers, to make method
377 // reentrant and thread-safe.
378 container_type const local( maListeners );
379 aGuard.clear();
380
381 const bool bRet(
383 local,
384 func ));
385
386 {
387 Guard aGuard2(*this);
389 const_cast<container_type&>(maListeners),
390 MaxDeceasedListenerUllage);
391 }
392
393 return bRet;
394 }
395
396private:
397 ContainerT maListeners;
398};
399
400
406template< typename ListenerT,
407 typename ContainerT=std::vector<ListenerT> >
409 EmptyBase,
410 ContainerT>
411{
412};
413
414} // namespace slideshow::internal
415
416#endif // INCLUDED_SLIDESHOW_SOURCE_INC_LISTENERCONTAINER_HXX
417
418/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Container for objects that can be notified.
bool isAdded(listener_type const &rListener) const
Check whether given listener is already added.
bool apply(FuncT func) const
Apply functor to one listener.
bool remove(listener_type const &rListener)
Remove listener from container.
bool isEmpty() const
Check whether listener container is empty.
bool applyAll(FuncT func) const
Apply functor to all listeners.
MutexHolderBaseT::ClearableGuard ClearableGuard
bool addSorted(listener_type const &rListener)
Add new listener into sorted container.
void clear()
Removes all listeners in one go.
void add(listener_type const &rListener)
Add new listener.
ListenerContainer variant that does not serialize access.
static bool apply(FuncT func, ListenerTargetT const &rArg)
static bool apply(FuncT func, ListenerTargetT const &rArg)
static void pruneListeners(ContainerT &rContainer, size_t nSizeThreshold)
static bool notifyAllListeners(ContainerT &rContainer, FuncT func)
Notify all listeners.
static bool notifySingleListener(ContainerT &rContainer, FuncT func)
Notify a single one of the listeners.
static void pruneListeners(ContainerT &, size_t)
Prune container from deceased listeners.