Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
basic_algos.hpp
Go to the documentation of this file.
1 /*
2  * Author: Sven Gothel <sgothel@jausoft.com>
3  * Copyright (c) 2020 Gothel Software e.K.
4  * Copyright (c) 2020 ZAFENA AB
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #ifndef JAU_BASIC_ALGOS_HPP_
27 #define JAU_BASIC_ALGOS_HPP_
28 
29 #include <mutex>
30 #include <type_traits>
31 
32 #include <jau/cow_iterator.hpp>
33 
34 namespace jau {
35 
36  /**
37  * Call on release allows the user to pass a function
38  * to be called at destruction of this instance.
39  * <p>
40  * One goal was to provide a thread exit cleanup facility,
41  * setting a 'is_running' flag to false when the thread exists
42  * normally or abnormally.
43  * <pre>
44  * jau::relaxed_atomic_bool is_running = true;
45  *
46  * void some_thread_func() {
47  * thread_local jau::call_on_release lili([&]() {
48  * is_running = false;
49  * });
50  * ...
51  * do some work here, which might get cancelled
52  * ..
53  * }
54  * </pre>
55  * </p>
56  * @tparam UnaryFunction user provided function to be called @ dtor
57  */
58  template <class UnaryFunction> class call_on_release {
59  private:
60  UnaryFunction f;
61 
62  public:
63  call_on_release(UnaryFunction release_func) noexcept : f(release_func) {}
64  ~call_on_release() noexcept { f(); }
65  call_on_release(const call_on_release&) = delete;
67  call_on_release& operator=(const call_on_release&) volatile = delete;
68  };
69 
70  /****************************************************************************************
71  ****************************************************************************************/
72 
73  /**
74  * Like std::find() of 'algorithm'
75  * <p>
76  * Only exists here as performance analysis over O(n*n) complexity
77  * exposes std::find() to be approximately 3x slower.<br>
78  * See test/test_cow_darray_perf01.cpp
79  * </p>
80  * @tparam InputIt the iterator type
81  * @tparam T the data type
82  * @param first range start of elements to examine
83  * @param last range end of elements to examine, exclusive
84  * @param value reference value for comparison
85  * @return Iterator to the first element satisfying the condition or last if no such element is found.
86  */
87  template<class InputIt, class T>
88  constexpr InputIt find(InputIt first, InputIt last, const T& value)
89  {
90  for (; first != last; ++first) {
91  if (*first == value) {
92  return first;
93  }
94  }
95  return last; // implicit move since C++11
96  }
97 
98  /**
99  * Like std::find_if() of 'algorithm'
100  * <p>
101  * Only exists here as performance analysis over O(n*n) complexity
102  * exposes std::find_if() to be approximately 3x slower for 1000 x 1000.<br>
103  * See test/test_cow_darray_perf01.cpp
104  * </p>
105  * @tparam InputIt the iterator type
106  * @tparam UnaryPredicate
107  * @param first range start of elements to examine
108  * @param last range end of elements to examine, exclusive
109  * @param p unary predicate which returns ​true for the desired element.
110  * @return Iterator to the first element satisfying the condition or last if no such element is found.
111  */
112  template<class InputIt, class UnaryPredicate>
113  constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate p)
114  {
115  for (; first != last; ++first) {
116  if (p(*first)) {
117  return first;
118  }
119  }
120  return last; // implicit move since C++11
121  }
122 
123  /**
124  * Like std::find_if_not() of 'algorithm'
125  * <p>
126  * Only exists here as performance analysis over O(n*n) complexity
127  * exposes std::find_if_not() to be approximately 3x slower for 1000 x 1000.<br>
128  * See test/test_cow_darray_perf01.cpp
129  * </p>
130  * @tparam InputIt the iterator type
131  * @tparam UnaryPredicate
132  * @param first range start of elements to examine
133  * @param last range end of elements to examine, exclusive
134  * @param q unary predicate which returns ​false for the desired element.
135  * @return Iterator to the first element satisfying the condition or last if no such element is found.
136  */
137  template<class InputIt, class UnaryPredicate>
138  constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q)
139  {
140  for (; first != last; ++first) {
141  if (!q(*first)) {
142  return first;
143  }
144  }
145  return last; // implicit move since C++11
146  }
147 
148  /**
149  * Like std::for_each() of 'algorithm'
150  * <p>
151  * Only exists here as performance analysis over O(n*n) complexity
152  * exposes std::for_each() to be 'a little' slower for 1000 x 1000.<br>
153  * See test/test_cow_darray_perf01.cpp
154  * </p>
155  * @tparam InputIt the iterator type
156  * @tparam UnaryFunction
157  * @param first range start of elements to apply the function
158  * @param last range end of elements to apply the function
159  * @param f the function object, like <code>void fun(const Type &a)</code>
160  * @return the function
161  */
162  template<class InputIt, class UnaryFunction>
163  constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
164  {
165  for (; first != last; ++first) {
166  f(*first);
167  }
168  return f; // implicit move since C++11
169  }
170 
171  /****************************************************************************************
172  ****************************************************************************************/
173 
174  /**
175  * Like jau::for_each(), see above.
176  * <p>
177  * Additionally this template function removes
178  * the <code>const</code> qualifier
179  * of the <code>UnaryFunction</code> sole argument.<br>
180  * The latter is retrieved by dereferencing the iterator,
181  * which might expose the <code>const</code> qualifier if
182  * the iterator is a <code>const_iterator</code>.
183  * </p>
184  * <p>
185  * Implementation casts argument in the following fashion
186  * <code>const_cast<value_type*>(&arg)</code>,
187  * allowing to use <code>const_iterator</code> and subsequent
188  * non-const features of the argument, see below.
189  * </p>
190  * <p>
191  * Such situations may occur when preferring to use
192  * the <code>const_iterator</code> over non-const.<br>
193  * jau::cow_darray is such a scenario, where one might
194  * not mutate the elements of the container itself
195  * but needs to invoke non-const functions <i>in good faith</i>.<br>
196  * Here we can avoid costly side-effects of copying the CoW storage for later replacement.<br>
197  * See jau::cow_ro_iterator and jau::cow_rw_iterator
198  * in conjunction with jau::cow_darray.
199  * </p>
200  * <p>
201  * Requirements for the given IteratorIt type are to
202  * have typename <code>InputIt::value_type</code> available.
203  * </p>
204  * @tparam InputIt the iterator type, which might be a 'const_iterator' for non const types.
205  * @tparam UnaryFunction
206  * @param first range start of elements to apply the function
207  * @param last range end of elements to apply the function
208  * @param f the function object, like <code>void fun(const Type &a)</code>
209  * @return the function
210  * @see jau::cow_darray
211  * @see jau::cow_ro_iterator
212  * @see jau::cow_rw_iterator
213  */
214  template<class InputIt, class UnaryFunction>
215  constexpr UnaryFunction for_each_fidelity(InputIt first, InputIt last, UnaryFunction f)
216  {
217  typedef typename InputIt::value_type value_type;
218 
219  for (; first != last; ++first) {
220  f( *const_cast<value_type*>( & (*first) ) );
221  }
222  return f; // implicit move since C++11
223  }
224 
225  /****************************************************************************************
226  ****************************************************************************************/
227 
228  /**
229  * Custom for_each template, same as jau::for_each but using a mutex.
230  * <p>
231  * Method performs UnaryFunction on all elements [first..last).
232  * </p>
233  * <p>
234  * This method also utilizes a given mutex to ensure thread-safety,
235  * by operating within an RAII-style std::lock_guard block.
236  * </p>
237  */
238  template<class Mutex, class InputIt, class UnaryFunction>
239  constexpr UnaryFunction for_each_mtx(Mutex &mtx, InputIt first, InputIt last, UnaryFunction f)
240  {
241  const std::lock_guard<Mutex> lock(mtx); // RAII-style acquire and relinquish via destructor
242 
243  for (; first != last; ++first) {
244  f(*first);
245  }
246  return f; // implicit move since C++11
247  }
248 
249  /**
250  * Custom for_each template, using indices instead of iterators,
251  * allowing container to be modified within lambda 'callback'.
252  * <p>
253  * Method performs UnaryFunction on all elements [0..n-1],
254  * where n is being retrieved once before the loop!
255  * </p>
256  */
257  template<class InputArray, class UnaryFunction>
258  constexpr UnaryFunction for_each_idx(InputArray &array, UnaryFunction f)
259  {
260  const size_t size = array.size();
261  for (size_t i = 0; i < size; ++i) {
262  f(array[i]);
263  }
264  return f; // implicit move since C++11
265  }
266 
267  /**
268  * Custom for_each template,
269  * same as jau::for_each but using indices instead of iterators and a mutex.
270  * <p>
271  * Method performs UnaryFunction on all elements [0..n-1],
272  * where n is being retrieved once before the loop!
273  * </p>
274  * <p>
275  * This method also utilizes a given mutex to ensure thread-safety,
276  * by operating within an RAII-style std::lock_guard block.
277  * </p>
278  */
279  template<class Mutex, class InputArray, class UnaryFunction>
280  constexpr UnaryFunction for_each_idx_mtx(Mutex &mtx, InputArray &array, UnaryFunction f)
281  {
282  const std::lock_guard<Mutex> lock(mtx); // RAII-style acquire and relinquish via destructor
283 
284  const size_t size = array.size();
285  for (size_t i = 0; i < size; ++i) {
286  f(array[i]);
287  }
288  return f; // implicit move since C++11
289  }
290 
291  /****************************************************************************************
292  ****************************************************************************************/
293 
294  template<class T>
295  const typename T::value_type * find_const(T& data, typename T::value_type const & elem,
296  std::enable_if_t< is_cow_type<T>::value, bool> = true ) noexcept
297  {
298  for (typename T::const_iterator first = data.cbegin(); !first.is_end(); ++first) {
299  if (*first == elem) {
300  return &(*first);
301  }
302  }
303  return nullptr;
304  }
305  template<class T>
306  const typename T::value_type * find_const(T& data, typename T::value_type const & elem,
307  std::enable_if_t< !is_cow_type<T>::value, bool> = true ) noexcept
308  {
309  typename T::const_iterator first = data.cbegin();
310  typename T::const_iterator last = data.cend();
311  for (; first != last; ++first) {
312  if (*first == elem) {
313  return &(*first);
314  }
315  }
316  return nullptr;
317  }
318 
319  /****************************************************************************************
320  ****************************************************************************************/
321 
322  template<class T, class UnaryFunction>
323  constexpr UnaryFunction for_each_const(T& data, UnaryFunction f,
324  std::enable_if_t< is_cow_type<T>::value, bool> = true ) noexcept
325  {
326  for (typename T::const_iterator first = data.cbegin(); !first.is_end(); ++first) {
327  f(*first);
328  }
329  return f; // implicit move since C++11
330  }
331  template<class T, class UnaryFunction>
332  constexpr UnaryFunction for_each_const(T& data, UnaryFunction f,
333  std::enable_if_t< !is_cow_type<T>::value, bool> = true ) noexcept
334  {
335  typename T::const_iterator first = data.cbegin();
336  typename T::const_iterator last = data.cend();
337  for (; first != last; ++first) {
338  f(*first);
339  }
340  return f; // implicit move since C++11
341  }
342 
343  /****************************************************************************************
344  ****************************************************************************************/
345 
346  /**
347  * See jau::for_each_fidelity()
348  */
349  template<class T, class UnaryFunction>
350  constexpr UnaryFunction for_each_fidelity(T& data, UnaryFunction f,
351  std::enable_if_t< is_cow_type<T>::value, bool> = true ) noexcept
352  {
353  for (typename T::const_iterator first = data.cbegin(); !first.is_end(); ++first) {
354  f( *const_cast<typename T::value_type*>( & (*first) ) );
355  }
356  return f; // implicit move since C++11
357  }
358  /**
359  * See jau::for_each_fidelity()
360  */
361  template<class T, class UnaryFunction>
362  constexpr UnaryFunction for_each_fidelity(T& data, UnaryFunction f,
363  std::enable_if_t< !is_cow_type<T>::value, bool> = true ) noexcept
364  {
365  typename T::const_iterator first = data.cbegin();
366  typename T::const_iterator last = data.cend();
367  for (; first != last; ++first) {
368  f( *const_cast<typename T::value_type*>( & (*first) ) );
369  }
370  return f; // implicit move since C++11
371  }
372 
373 } // namespace jau
374 
375 #endif /* JAU_BASIC_ALGOS_HPP_ */
jau::find_if_not
constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPredicate q)
Like std::find_if_not() of 'algorithm'.
Definition: basic_algos.hpp:138
jau::call_on_release::~call_on_release
~call_on_release() noexcept
Definition: basic_algos.hpp:64
jau::for_each_fidelity
constexpr UnaryFunction for_each_fidelity(InputIt first, InputIt last, UnaryFunction f)
Like jau::for_each(), see above.
Definition: basic_algos.hpp:215
jau::call_on_release::call_on_release
call_on_release(UnaryFunction release_func) noexcept
Definition: basic_algos.hpp:63
jau::call_on_release
Call on release allows the user to pass a function to be called at destruction of this instance.
Definition: basic_algos.hpp:58
jau::call_on_release::operator=
call_on_release & operator=(const call_on_release &)=delete
jau::for_each_mtx
constexpr UnaryFunction for_each_mtx(Mutex &mtx, InputIt first, InputIt last, UnaryFunction f)
Custom for_each template, same as jau::for_each but using a mutex.
Definition: basic_algos.hpp:239
jau::for_each
constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
Like std::for_each() of 'algorithm'.
Definition: basic_algos.hpp:163
jau
Definition: basic_algos.hpp:34
jau::is_cow_type
template< class T > is_cow_type<T>::value compile-time Type Trait, determining whether the given temp...
Definition: cow_iterator.hpp:1039
cow_iterator.hpp
jau::call_on_release::call_on_release
call_on_release(const call_on_release &)=delete
jau::find_const
const T::value_type * find_const(T &data, typename T::value_type const &elem, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
Definition: basic_algos.hpp:295
jau::for_each_const
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
Definition: basic_algos.hpp:323
jau::find
constexpr InputIt find(InputIt first, InputIt last, const T &value)
Like std::find() of 'algorithm'.
Definition: basic_algos.hpp:88
jau::call_on_release::operator=
call_on_release & operator=(const call_on_release &) volatile=delete
jau::for_each_idx
constexpr UnaryFunction for_each_idx(InputArray &array, UnaryFunction f)
Custom for_each template, using indices instead of iterators, allowing container to be modified withi...
Definition: basic_algos.hpp:258
jau::for_each_idx_mtx
constexpr UnaryFunction for_each_idx_mtx(Mutex &mtx, InputArray &array, UnaryFunction f)
Custom for_each template, same as jau::for_each but using indices instead of iterators and a mutex.
Definition: basic_algos.hpp:280
jau::find_if
constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate p)
Like std::find_if() of 'algorithm'.
Definition: basic_algos.hpp:113