/src/vlc/include/vlc_cxx_helpers.hpp
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * vlc_cxx_helpers.hpp: C++ helpers |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 1998-2018 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr> |
7 | | * |
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. |
12 | | * |
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. |
17 | | * |
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 | | *****************************************************************************/ |
22 | | |
23 | | #ifndef VLC_CXX_HELPERS_HPP |
24 | | #define VLC_CXX_HELPERS_HPP |
25 | | |
26 | | /****************************************************************************** |
27 | | * C++ memory management helpers |
28 | | ******************************************************************************/ |
29 | | |
30 | | #if defined(__cplusplus) || defined(DOC) |
31 | | |
32 | | #include <memory> |
33 | | #include <utility> |
34 | | #include <type_traits> |
35 | | #include <string> |
36 | | #include <stdexcept> |
37 | | |
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 |
44 | | |
45 | | namespace vlc |
46 | | { |
47 | | |
48 | | namespace |
49 | | { |
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) |
52 | | |
53 | | // Wraps a pointer with a custom releaser |
54 | | // ex: auto ptr = vlc::wrap_cptr( input_item, &input_item_Release ); |
55 | | |
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 or 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> |
71 | 17 | { |
72 | 17 | return std::unique_ptr<T, typename std::decay<decltype( r )>::type>{ |
73 | 17 | ptr, std::forward<Releaser>( r ) |
74 | 17 | }; |
75 | 17 | } |
76 | | |
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 or 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> |
97 | | { |
98 | | return std::unique_ptr<T[], typename std::decay<decltype( r )>::type>{ |
99 | | ptr, std::forward<Releaser>( r ) |
100 | | }; |
101 | | } |
102 | | |
103 | | /// |
104 | | /// Wraps a C pointer into a std::unique_ptr |
105 | | /// |
106 | | /// This is a convenience wrapper that will use free() as its releaser |
107 | | /// |
108 | | template <typename T> |
109 | | inline std::unique_ptr<T, void (*)(void*)> wrap_cptr( T* ptr ) noexcept |
110 | | { |
111 | | return wrap_cptr( ptr, &free ); |
112 | | } |
113 | | |
114 | | /// |
115 | | /// Wraps a C pointer into a std::unique_ptr |
116 | | /// |
117 | | /// This is a convenience wrapper that will use free() as its releaser |
118 | | /// |
119 | | template <typename T> |
120 | | inline std::unique_ptr<T[], void (*)(void*)> wrap_carray( T* ptr ) noexcept |
121 | | { |
122 | | return wrap_carray( ptr, &free ); |
123 | | } |
124 | | |
125 | | } // anonymous namespace |
126 | | |
127 | | /// |
128 | | /// Wraps a C shared resource having associated Hold() and Release() functions |
129 | | // |
130 | | /// This is a RAII wrapper for C shared resources (which are manually managed by |
131 | | /// calling explicitly their Hold() and Release() functions). |
132 | | /// |
133 | | /// The Hold() and Release() functions must accept exactly one parameter having |
134 | | /// type T* (the raw pointer type). Their return type is irrelevant. |
135 | | /// |
136 | | /// To create a new shared resource wrapper type for my_type_t, simply declare: |
137 | | /// |
138 | | /// using MyTypePtr = |
139 | | /// ::vlc::vlc_shared_data_ptr<my_type_t, &my_type_Hold, &my_type_Release>; |
140 | | /// |
141 | | /// Then use it to wrap a raw C pointer: |
142 | | /// |
143 | | /// my_type_t *raw_ptr = /* ... */; |
144 | | /// MyTypePtr ptr(raw_ptr); |
145 | | template <typename T, auto HOLD, auto RELEASE> |
146 | | class vlc_shared_data_ptr { |
147 | | T *ptr = nullptr; |
148 | | |
149 | | public: |
150 | | /* default implicit constructor */ |
151 | | vlc_shared_data_ptr() = default; |
152 | | |
153 | | /** |
154 | | * Wrap a shared resource. |
155 | | * |
156 | | * If the pointer is not nullptr, and hold is true, then the resource is |
157 | | * hold (the caller shared ownership is preserved). |
158 | | * If hold is false, then the caller transfers the ownership to this |
159 | | * wrapper. |
160 | | * |
161 | | * \param ptr the raw pointer (can be nullptr) |
162 | | * \param hold whether the resource must be hold |
163 | | */ |
164 | | explicit vlc_shared_data_ptr(T *ptr, bool hold = true) |
165 | | : ptr(ptr) |
166 | | { |
167 | | if (ptr && hold) |
168 | | HOLD(ptr); |
169 | | } |
170 | | |
171 | | vlc_shared_data_ptr(std::nullptr_t) |
172 | | : ptr(nullptr) |
173 | | { |
174 | | } |
175 | | |
176 | | vlc_shared_data_ptr(const vlc_shared_data_ptr &other) |
177 | | : vlc_shared_data_ptr(other.ptr) {} |
178 | | |
179 | | vlc_shared_data_ptr(vlc_shared_data_ptr &&other) noexcept |
180 | | : ptr(other.ptr) |
181 | | { |
182 | | other.ptr = nullptr; |
183 | | } |
184 | | |
185 | | ~vlc_shared_data_ptr() |
186 | | { |
187 | | if (ptr) |
188 | | RELEASE(ptr); |
189 | | } |
190 | | |
191 | | vlc_shared_data_ptr &operator=(const vlc_shared_data_ptr &other) |
192 | | { |
193 | | reset(other.ptr, true); |
194 | | return *this; |
195 | | } |
196 | | |
197 | | vlc_shared_data_ptr &operator=(vlc_shared_data_ptr &&other) noexcept |
198 | | { |
199 | | reset(other.ptr, false); |
200 | | other.ptr = nullptr; |
201 | | return *this; |
202 | | } |
203 | | |
204 | | bool operator==(const vlc_shared_data_ptr &other) const |
205 | | { |
206 | | return ptr == other.ptr; |
207 | | } |
208 | | |
209 | | bool operator==(std::nullptr_t) const noexcept |
210 | | { |
211 | | return ptr == nullptr; |
212 | | } |
213 | | |
214 | | bool operator!=(const vlc_shared_data_ptr &other) const |
215 | | { |
216 | | return !(*this == other); |
217 | | } |
218 | | |
219 | | bool operator!=(std::nullptr_t) const noexcept |
220 | | { |
221 | | return ptr != nullptr; |
222 | | } |
223 | | |
224 | | explicit operator bool() const |
225 | | { |
226 | | return ptr; |
227 | | } |
228 | | |
229 | | T &operator*() const |
230 | | { |
231 | | return *ptr; |
232 | | } |
233 | | |
234 | | T *operator->() const |
235 | | { |
236 | | return ptr; |
237 | | } |
238 | | |
239 | | T *get() const |
240 | | { |
241 | | return ptr; |
242 | | } |
243 | | |
244 | | /** |
245 | | * Reset the shared resource. |
246 | | * |
247 | | * ptr.reset(rawptr, hold); |
248 | | * |
249 | | * is semantically equivalent to: |
250 | | * |
251 | | * ptr = vlc_shared_data_ptr<...>(rawptr, hold); |
252 | | * |
253 | | * If the pointer is not nullptr, and hold is true, then the resource is |
254 | | * hold (the caller shared ownership is preserved). |
255 | | * If hold is false, then the caller transfers the ownership to this |
256 | | * wrapper. |
257 | | * |
258 | | * \param newptr the raw pointer (can be nullptr) |
259 | | * \param hold whether the resource must be hold |
260 | | */ |
261 | | void reset(T *newptr = nullptr, bool hold = true) |
262 | | { |
263 | | if (newptr && hold) |
264 | | HOLD(newptr); |
265 | | if (ptr) |
266 | | RELEASE(ptr); |
267 | | ptr = newptr; |
268 | | } |
269 | | }; |
270 | | |
271 | | #if defined(VLC_THREADS_H_) || defined(DOC) |
272 | | |
273 | | namespace threads |
274 | | { |
275 | | |
276 | | class mutex |
277 | | { |
278 | | public: |
279 | | mutex() noexcept |
280 | 832 | { |
281 | 832 | vlc_mutex_init( &m_mutex ); |
282 | 832 | } |
283 | | |
284 | | mutex( const mutex& ) = delete; |
285 | | mutex& operator=( const mutex& ) = delete; |
286 | | mutex( mutex&& ) = delete; |
287 | | mutex& operator=( mutex&& ) = delete; |
288 | | |
289 | | void lock() noexcept |
290 | 26.3k | { |
291 | 26.3k | vlc_mutex_lock( &m_mutex ); |
292 | 26.3k | } |
293 | | void unlock() noexcept |
294 | 26.3k | { |
295 | 26.3k | vlc_mutex_unlock( &m_mutex ); |
296 | 26.3k | } |
297 | | |
298 | | private: |
299 | | vlc_mutex_t m_mutex; |
300 | | friend class condition_variable; |
301 | | friend class mutex_locker; |
302 | | }; |
303 | | |
304 | | class condition_variable |
305 | | { |
306 | | public: |
307 | | condition_variable() noexcept |
308 | 0 | { |
309 | 0 | vlc_cond_init( &m_cond ); |
310 | 0 | } |
311 | | void signal() noexcept |
312 | 0 | { |
313 | 0 | vlc_cond_signal( &m_cond ); |
314 | 0 | } |
315 | | void broadcast() noexcept |
316 | 0 | { |
317 | 0 | vlc_cond_broadcast( &m_cond ); |
318 | 0 | } |
319 | | void wait( mutex& mutex ) noexcept |
320 | 0 | { |
321 | 0 | vlc_cond_wait( &m_cond, &mutex.m_mutex ); |
322 | 0 | } |
323 | | int timedwait( mutex& mutex, vlc_tick_t deadline ) noexcept |
324 | 0 | { |
325 | 0 | return vlc_cond_timedwait( &m_cond, &mutex.m_mutex, deadline ); |
326 | 0 | } |
327 | | |
328 | | private: |
329 | | vlc_cond_t m_cond; |
330 | | }; |
331 | | |
332 | | class mutex_locker |
333 | | { |
334 | | public: |
335 | | mutex_locker( vlc_mutex_t* m ) noexcept |
336 | | : m_mutex( m ) |
337 | 0 | { |
338 | 0 | vlc_mutex_lock( m_mutex ); |
339 | 0 | } |
340 | | mutex_locker( mutex& m ) noexcept |
341 | | : mutex_locker( &m.m_mutex ) |
342 | 0 | { |
343 | 0 | } |
344 | | ~mutex_locker() |
345 | 0 | { |
346 | 0 | vlc_mutex_unlock( m_mutex ); |
347 | 0 | } |
348 | | mutex_locker( const mutex_locker& ) = delete; |
349 | | mutex_locker& operator=( const mutex_locker& ) = delete; |
350 | | mutex_locker( mutex_locker&& ) = delete; |
351 | | mutex_locker& operator=( mutex_locker&& ) = delete; |
352 | | |
353 | | private: |
354 | | vlc_mutex_t* m_mutex; |
355 | | }; |
356 | | |
357 | | class semaphore |
358 | | { |
359 | | public: |
360 | | semaphore() noexcept |
361 | 0 | { |
362 | 0 | vlc_sem_init( &m_sem, 0 ); |
363 | 0 | } |
364 | | semaphore( unsigned int count ) noexcept |
365 | 0 | { |
366 | 0 | vlc_sem_init( &m_sem, count ); |
367 | 0 | } |
368 | | ~semaphore() |
369 | 0 | { |
370 | 0 | } |
371 | | |
372 | | semaphore( const semaphore& ) = delete; |
373 | | semaphore& operator=( const semaphore& ) = delete; |
374 | | semaphore( semaphore&& ) = delete; |
375 | | semaphore& operator=( semaphore&& ) = delete; |
376 | | |
377 | | int post() noexcept |
378 | 0 | { |
379 | 0 | return vlc_sem_post( &m_sem ); |
380 | 0 | } |
381 | | void wait() noexcept |
382 | 0 | { |
383 | 0 | vlc_sem_wait( &m_sem ); |
384 | 0 | } |
385 | | |
386 | | int wait_i11e() noexcept |
387 | 0 | { |
388 | 0 | return vlc_sem_wait_i11e( &m_sem ); |
389 | 0 | } |
390 | | |
391 | | private: |
392 | | vlc_sem_t m_sem; |
393 | | }; |
394 | | |
395 | | } |
396 | | |
397 | | #endif // VLC_THREADS_H_ |
398 | | |
399 | | #ifdef VLC_URL_H |
400 | | |
401 | | class url : public vlc_url_t |
402 | | { |
403 | | public: |
404 | | class invalid : public std::runtime_error |
405 | | { |
406 | | public: |
407 | | explicit invalid( const char* url ) |
408 | | : std::runtime_error( std::string{ "Invalid url: " } + url ) |
409 | | { |
410 | | } |
411 | | }; |
412 | | |
413 | | url() |
414 | | { |
415 | | psz_buffer = nullptr; |
416 | | psz_pathbuffer = nullptr; |
417 | | psz_host = nullptr; |
418 | | } |
419 | | |
420 | | explicit url( const char* str ) |
421 | | { |
422 | | if ( vlc_UrlParse( this, str ) ) |
423 | | { |
424 | | vlc_UrlClean( this ); |
425 | | throw invalid( str ); |
426 | | } |
427 | | } |
428 | | |
429 | | explicit url( const std::string& str ) |
430 | | : url( str.c_str() ) |
431 | | { |
432 | | } |
433 | | |
434 | | ~url() |
435 | | { |
436 | | vlc_UrlClean(this); |
437 | | } |
438 | | |
439 | | url( const url& ) = delete; |
440 | | url& operator=( const url& ) = delete; |
441 | | |
442 | | url( url&& u ) noexcept |
443 | | : vlc_url_t( u ) |
444 | | { |
445 | | u.psz_buffer = nullptr; |
446 | | u.psz_pathbuffer = nullptr; |
447 | | u.psz_host = nullptr; |
448 | | } |
449 | | |
450 | | url& operator=( url&& u ) noexcept |
451 | | { |
452 | | vlc_UrlClean( this ); |
453 | | *(static_cast<vlc_url_t*>( this )) = u; |
454 | | u.psz_buffer = nullptr; |
455 | | u.psz_pathbuffer = nullptr; |
456 | | u.psz_host = nullptr; |
457 | | return *this; |
458 | | } |
459 | | }; |
460 | | |
461 | | #endif |
462 | | |
463 | | } // namespace vlc |
464 | | |
465 | | #endif |
466 | | |
467 | | #endif // VLC_CXX_HELPERS_HPP |