audiotrack: avoid cast, use proper type
[vlc.git] / include / vlc_cxx_helpers.hpp
blob0194e37a35eec4ad2b1431f3b86cf0d93b354135
1 /*****************************************************************************
2 * vlc_cxx_helpers.hpp: C++ helpers
3 *****************************************************************************
4 * Copyright (C) 1998-2018 VLC authors and VideoLAN
6 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifndef VLC_CXX_HELPERS_HPP
24 #define VLC_CXX_HELPERS_HPP
26 /******************************************************************************
27 * C++ memory management helpers
28 ******************************************************************************/
30 #ifdef __cplusplus
32 #include <memory>
33 #include <utility>
34 #include <type_traits>
35 #include <string>
36 #include <stdexcept>
38 #ifdef VLC_THREADS_H_
39 // Ensure we can use vlc_sem_wait_i11e. We can't declare different versions
40 // of the semaphore helper based on vlc_interrupt inclusion, as it would
41 // violate ODR
42 # include <vlc_interrupt.h>
43 #endif
45 namespace vlc
48 namespace
50 // This helpers need static linkage to avoid their signature to change when
51 // building as C++17 (noexcept becomes part of the function signature stating there)
53 // Wraps a pointer with a custom releaser
54 // ex: auto ptr = vlc_wrap_cptr( input_item, &input_item_Release );
56 ///
57 /// Wraps a C pointer into a std::unique_ptr
58 ///
59 /// This will convert a C pointer of type T to a std::unique_ptr<T, R> where
60 /// T is the pointee type, and R is an arbitrary releaser type.
61 ///
62 /// ptr will be automatically released by calling r( ptr ) when falling out of
63 /// scope (whether by returning of by throwing an exception
64 ///
65 /// @param ptr a C pointer
66 /// @param r An instance of a Callable type, that will be invoked with ptr
67 /// as its first and only parameter.
68 template <typename T, typename Releaser>
69 inline auto wrap_cptr( T* ptr, Releaser&& r ) noexcept
70 -> std::unique_ptr<T, typename std::decay<decltype( r )>::type>
72 return std::unique_ptr<T, typename std::decay<decltype( r )>::type>{
73 ptr, std::forward<Releaser>( r )
77 ///
78 /// Wraps a C pointer into a std::unique_ptr
79 ///
80 /// This will convert a C pointer to an array of type T to a
81 /// std::unique_ptr<T[], R> where T is the pointee type, and R is an arbitrary
82 /// releaser type.
83 ///
84 /// ptr will be automatically released by calling r( ptr ) when falling out of
85 /// scope (whether by returning of by throwing an exception
86 ///
87 /// This function is equivalent to wrap_cptr, except that the returned
88 /// unique_ptr provides an operator[] for array access instead of operator* and
89 /// operator->
90 ///
91 /// @param ptr a C pointer
92 /// @param r An instance of a Callable type, that will be invoked with ptr
93 /// as its first and only parameter.
94 template <typename T, typename Releaser>
95 inline auto wrap_carray( T* ptr, Releaser&& r ) noexcept
96 -> std::unique_ptr<T[], typename std::decay<decltype( r )>::type>
98 return std::unique_ptr<T[], typename std::decay<decltype( r )>::type>{
99 ptr, std::forward<Releaser>( r )
104 /// Wraps a C pointer into a std::unique_ptr
106 /// This is a convenience wrapper that will use free() as its releaser
108 template <typename T>
109 inline std::unique_ptr<T, void (*)(void*)> wrap_cptr( T* ptr ) noexcept
111 return wrap_cptr( ptr, &free );
115 /// Wraps a C pointer into a std::unique_ptr
117 /// This is a convenience wrapper that will use free() as its releaser
119 template <typename T>
120 inline std::unique_ptr<T[], void (*)(void*)> wrap_carray( T* ptr ) noexcept
122 return wrap_carray( ptr, &free );
125 } // anonymous namespace
128 /// Wraps a C shared resource having associated Hold() and Release() functions
130 /// This is a RAII wrapper for C shared resources (which are manually managed by
131 /// calling explicitly their Hold() and Release() functions).
133 /// The Hold() and Release() functions must accept exactly one parameter having
134 /// type T* (the raw pointer type). Their return type is irrelevant.
136 /// To create a new shared resource wrapper type for my_type_t, simply declare:
138 /// using MyTypePtr =
139 /// vlc_shared_data_ptr_type(my_type_t, my_type_Hold, my_type_Release);
141 /// Then use it to wrap a raw C pointer:
143 /// my_type_t *raw_ptr = /* ... */;
144 /// MyTypePtr ptr(raw_ptr);
146 // In C++17, the template declaration could be replaced by:
147 // template<typename T, auto HOLD, auto RELEASE>
148 template <typename T, typename H, typename R, H HOLD, R RELEASE>
149 class vlc_shared_data_ptr {
150 T *ptr = nullptr;
152 public:
153 /* default implicit constructor */
154 vlc_shared_data_ptr() = default;
157 * Wrap a shared resource.
159 * If the pointer is not nullptr, and hold is true, then the resource is
160 * hold (the caller shared ownership is preserved).
161 * If hold is false, then the caller transfers the ownership to this
162 * wrapper.
164 * \param ptr the raw pointer (can be nullptr)
165 * \param hold whether the resource must be hold
167 explicit vlc_shared_data_ptr(T *ptr, bool hold = true)
168 : ptr(ptr)
170 if (ptr && hold)
171 HOLD(ptr);
174 vlc_shared_data_ptr(const vlc_shared_data_ptr &other)
175 : vlc_shared_data_ptr(other.ptr) {}
177 vlc_shared_data_ptr(vlc_shared_data_ptr &&other) noexcept
178 : ptr(other.ptr)
180 other.ptr = nullptr;
183 ~vlc_shared_data_ptr()
185 if (ptr)
186 RELEASE(ptr);
189 vlc_shared_data_ptr &operator=(const vlc_shared_data_ptr &other)
191 reset(other.ptr, true);
192 return *this;
195 vlc_shared_data_ptr &operator=(vlc_shared_data_ptr &&other) noexcept
197 reset(other.ptr, false);
198 other.ptr = nullptr;
199 return *this;
202 bool operator==(const vlc_shared_data_ptr &other) const
204 return ptr == other.ptr;
207 bool operator==(std::nullptr_t) const noexcept
209 return ptr == nullptr;
212 bool operator!=(const vlc_shared_data_ptr &other) const
214 return !(*this == other);
217 bool operator!=(std::nullptr_t) const noexcept
219 return ptr != nullptr;
222 explicit operator bool() const
224 return ptr;
227 T &operator*() const
229 return *ptr;
232 T *operator->() const
234 return ptr;
237 T *get() const
239 return ptr;
243 * Reset the shared resource.
245 * ptr.reset(rawptr, hold);
247 * is semantically equivalent to:
249 * ptr = vlc_shared_data_ptr<...>(rawptr, hold);
251 * If the pointer is not nullptr, and hold is true, then the resource is
252 * hold (the caller shared ownership is preserved).
253 * If hold is false, then the caller transfers the ownership to this
254 * wrapper.
256 * \param ptr the raw pointer (can be nullptr)
257 * \param hold whether the resource must be hold
259 void reset(T *newptr = nullptr, bool hold = true)
261 if (newptr && hold)
262 HOLD(newptr);
263 if (ptr)
264 RELEASE(ptr);
265 ptr = newptr;
269 // useful due to the unnecessarily complex template declaration before C++17
270 #define vlc_shared_data_ptr_type(type, hold, release) \
271 ::vlc::vlc_shared_data_ptr<type, decltype(&hold), decltype(&release), \
272 &hold, &release>
274 #ifdef VLC_THREADS_H_
276 namespace threads
279 class mutex
281 public:
282 mutex() noexcept
284 vlc_mutex_init( &m_mutex );
287 mutex( const mutex& ) = delete;
288 mutex& operator=( const mutex& ) = delete;
289 mutex( mutex&& ) = delete;
290 mutex& operator=( mutex&& ) = delete;
292 void lock() noexcept
294 vlc_mutex_lock( &m_mutex );
296 void unlock() noexcept
298 vlc_mutex_unlock( &m_mutex );
301 private:
302 vlc_mutex_t m_mutex;
303 friend class condition_variable;
304 friend class mutex_locker;
307 class condition_variable
309 public:
310 condition_variable() noexcept
312 vlc_cond_init( &m_cond );
314 void signal() noexcept
316 vlc_cond_signal( &m_cond );
318 void broadcast() noexcept
320 vlc_cond_broadcast( &m_cond );
322 void wait( mutex& mutex ) noexcept
324 vlc_cond_wait( &m_cond, &mutex.m_mutex );
326 int timedwait( mutex& mutex, vlc_tick_t deadline ) noexcept
328 return vlc_cond_timedwait( &m_cond, &mutex.m_mutex, deadline );
331 private:
332 vlc_cond_t m_cond;
335 class mutex_locker
337 public:
338 mutex_locker( vlc_mutex_t* m ) noexcept
339 : m_mutex( m )
341 vlc_mutex_lock( m_mutex );
343 mutex_locker( mutex& m ) noexcept
344 : mutex_locker( &m.m_mutex )
347 ~mutex_locker()
349 vlc_mutex_unlock( m_mutex );
351 mutex_locker( const mutex_locker& ) = delete;
352 mutex_locker& operator=( const mutex_locker& ) = delete;
353 mutex_locker( mutex_locker&& ) = delete;
354 mutex_locker& operator=( mutex_locker&& ) = delete;
356 private:
357 vlc_mutex_t* m_mutex;
360 class semaphore
362 public:
363 semaphore() noexcept
365 vlc_sem_init( &m_sem, 0 );
367 semaphore( unsigned int count ) noexcept
369 vlc_sem_init( &m_sem, count );
371 ~semaphore()
375 semaphore( const semaphore& ) = delete;
376 semaphore& operator=( const semaphore& ) = delete;
377 semaphore( semaphore&& ) = delete;
378 semaphore& operator=( semaphore&& ) = delete;
380 int post() noexcept
382 return vlc_sem_post( &m_sem );
384 void wait() noexcept
386 vlc_sem_wait( &m_sem );
389 int wait_i11e() noexcept
391 return vlc_sem_wait_i11e( &m_sem );
394 private:
395 vlc_sem_t m_sem;
400 #endif // VLC_THREADS_H_
402 #ifdef VLC_URL_H
404 class url : public vlc_url_t
406 public:
407 class invalid : public std::runtime_error
409 public:
410 invalid( const char* url )
411 : std::runtime_error( std::string{ "Invalid url: " } + url )
416 url()
418 psz_buffer = nullptr;
419 psz_pathbuffer = nullptr;
420 psz_host = nullptr;
423 url( const char* str )
425 if ( vlc_UrlParse( this, str ) )
426 throw invalid( str );
429 url( const std::string& str )
430 : url( str.c_str() )
434 ~url()
436 vlc_UrlClean(this);
439 url( const url& ) = delete;
440 url& operator=( const url& ) = delete;
442 url( url&& u ) noexcept
443 : vlc_url_t( u )
445 u.psz_buffer = nullptr;
446 u.psz_pathbuffer = nullptr;
447 u.psz_host = nullptr;
450 url& operator=( url&& u ) noexcept
452 *(static_cast<vlc_url_t*>( this )) = u;
453 u.psz_buffer = nullptr;
454 u.psz_pathbuffer = nullptr;
455 u.psz_host = nullptr;
456 return *this;
460 #endif
462 } // namespace vlc
464 #endif
466 #endif // VLC_CXX_HELPERS_HPP