| 
									
										
										
										
											2022-02-11 09:07:11 +11:00
										 |  |  | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-21 17:31:56 +02:00
										 |  |  | #pragma once
 | 
					
						
							| 
									
										
										
										
											2019-09-13 21:12:26 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | /** \file
 | 
					
						
							|  |  |  |  * \ingroup bli | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Some of the functions below have very similar alternatives in the standard library. However, it | 
					
						
							|  |  |  |  * is rather annoying to use those when debugging. Therefore, some more specialized and easier to | 
					
						
							|  |  |  |  * debug functions are provided here. | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 09:33:03 +01:00
										 |  |  | #include <memory>
 | 
					
						
							| 
									
										
										
										
											2020-06-11 15:13:19 +02:00
										 |  |  | #include <new>
 | 
					
						
							| 
									
										
										
										
											2020-07-08 22:27:25 +02:00
										 |  |  | #include <type_traits>
 | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:45:06 +01:00
										 |  |  | #include "BLI_utildefines.h"
 | 
					
						
							| 
									
										
										
										
											2021-03-07 17:51:56 +01:00
										 |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							| 
									
										
										
										
											2020-03-06 16:45:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:27:24 +02:00
										 |  |  | namespace blender { | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-25 19:27:33 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Under some circumstances #std::is_trivial_v<T> is false even though we know that the type is | 
					
						
							|  |  |  |  * actually trivial. Using that extra knowledge allows for some optimizations. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename T> inline constexpr bool is_trivial_extended_v = std::is_trivial_v<T>; | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | inline constexpr bool is_trivially_destructible_extended_v = is_trivial_extended_v<T> || | 
					
						
							|  |  |  |                                                              std::is_trivially_destructible_v<T>; | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | inline constexpr bool is_trivially_copy_constructible_extended_v = | 
					
						
							|  |  |  |     is_trivial_extended_v<T> || std::is_trivially_copy_constructible_v<T>; | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | inline constexpr bool is_trivially_move_constructible_extended_v = | 
					
						
							|  |  |  |     is_trivial_extended_v<T> || std::is_trivially_move_constructible_v<T>; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Call the destructor on n consecutive values. For trivially destructible types, this does | 
					
						
							|  |  |  |  * nothing. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Exception Safety: Destructors shouldn't throw exceptions. | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Before: | 
					
						
							|  |  |  |  *  ptr: initialized | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * After: | 
					
						
							|  |  |  |  *  ptr: uninitialized | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void destruct_n(T *ptr, int64_t n) | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |   static_assert(std::is_nothrow_destructible_v<T>, | 
					
						
							|  |  |  |                 "This should be true for all types. Destructors are noexcept by default."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   /* This is not strictly necessary, because the loop below will be optimized away anyway. It is
 | 
					
						
							| 
									
										
										
										
											2020-06-13 12:50:07 +10:00
										 |  |  |    * nice to make behavior this explicitly, though. */ | 
					
						
							| 
									
										
										
										
											2022-06-25 19:27:33 +02:00
										 |  |  |   if (is_trivially_destructible_extended_v<T>) { | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   for (int64_t i = 0; i < n; i++) { | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |     ptr[i].~T(); | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Call the default constructor on n consecutive elements. For trivially constructible types, this | 
					
						
							|  |  |  |  * does nothing. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Exception Safety: Strong. | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Before: | 
					
						
							|  |  |  |  *  ptr: uninitialized | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * After: | 
					
						
							|  |  |  |  *  ptr: initialized | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void default_construct_n(T *ptr, int64_t n) | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   /* This is not strictly necessary, because the loop below will be optimized away anyway. It is
 | 
					
						
							| 
									
										
										
										
											2020-06-13 12:50:07 +10:00
										 |  |  |    * nice to make behavior this explicitly, though. */ | 
					
						
							| 
									
										
										
										
											2020-07-08 20:39:12 +02:00
										 |  |  |   if (std::is_trivially_constructible_v<T>) { | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   int64_t current = 0; | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |   try { | 
					
						
							|  |  |  |     for (; current < n; current++) { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |       new (static_cast<void *>(ptr + current)) T; | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   catch (...) { | 
					
						
							|  |  |  |     destruct_n(ptr, current); | 
					
						
							|  |  |  |     throw; | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copy n values from src to dst. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Basic. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void initialized_copy_n(const T *src, int64_t n, T *dst) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int64_t i = 0; i < n; i++) { | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |     dst[i] = src[i]; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copy n values from src to dst. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Strong. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: uninitialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void uninitialized_copy_n(const T *src, int64_t n, T *dst) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int64_t current = 0; | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |   try { | 
					
						
							|  |  |  |     for (; current < n; current++) { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |       new (static_cast<void *>(dst + current)) T(src[current]); | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   catch (...) { | 
					
						
							|  |  |  |     destruct_n(dst, current); | 
					
						
							|  |  |  |     throw; | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 22:27:25 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Convert n values from type `From` to type `To`. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Exception Safety: Strong. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: uninitialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename From, typename To> | 
					
						
							|  |  |  | void uninitialized_convert_n(const From *src, int64_t n, To *dst) | 
					
						
							| 
									
										
										
										
											2020-07-08 22:27:25 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int64_t current = 0; | 
					
						
							| 
									
										
										
										
											2020-07-08 22:27:25 +02:00
										 |  |  |   try { | 
					
						
							|  |  |  |     for (; current < n; current++) { | 
					
						
							| 
									
										
										
										
											2020-08-19 16:44:53 +02:00
										 |  |  |       new (static_cast<void *>(dst + current)) To(static_cast<To>(src[current])); | 
					
						
							| 
									
										
										
										
											2020-07-08 22:27:25 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   catch (...) { | 
					
						
							|  |  |  |     destruct_n(dst, current); | 
					
						
							|  |  |  |     throw; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Move n values from src to dst. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Basic. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  src: initialized, moved-from | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void initialized_move_n(T *src, int64_t n, T *dst) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int64_t i = 0; i < n; i++) { | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |     dst[i] = std::move(src[i]); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Move n values from src to dst. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Basic. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: uninitialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  src: initialized, moved-from | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void uninitialized_move_n(T *src, int64_t n, T *dst) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int64_t current = 0; | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |   try { | 
					
						
							|  |  |  |     for (; current < n; current++) { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |       new (static_cast<void *>(dst + current)) T(std::move(src[current])); | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   catch (...) { | 
					
						
							|  |  |  |     destruct_n(dst, current); | 
					
						
							|  |  |  |     throw; | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Relocate n values from src to dst. Relocation is a move followed by destruction of the src | 
					
						
							|  |  |  |  * value. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Basic. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  src: uninitialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void initialized_relocate_n(T *src, int64_t n, T *dst) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   initialized_move_n(src, n, dst); | 
					
						
							|  |  |  |   destruct_n(src, n); | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Relocate n values from src to dst. Relocation is a move followed by destruction of the src | 
					
						
							|  |  |  |  * value. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Basic. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  src: initialized | 
					
						
							| 
									
										
										
										
											2020-06-13 12:50:07 +10:00
										 |  |  |  *  dst: uninitialized | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * After: | 
					
						
							|  |  |  |  *  src: uninitialized | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void uninitialized_relocate_n(T *src, int64_t n, T *dst) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  |   uninitialized_move_n(src, n, dst); | 
					
						
							|  |  |  |   destruct_n(src, n); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copy the value to n consecutive elements. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  * Exception Safety: Basic. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void initialized_fill_n(T *dst, int64_t n, const T &value) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int64_t i = 0; i < n; i++) { | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |     dst[i] = value; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Copy the value to n consecutive elements. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |  *  Exception Safety: Strong. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * Before: | 
					
						
							|  |  |  |  *  dst: uninitialized | 
					
						
							|  |  |  |  * After: | 
					
						
							|  |  |  |  *  dst: initialized | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T> void uninitialized_fill_n(T *dst, int64_t n, const T &value) | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  |   BLI_assert(n >= 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int64_t current = 0; | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |   try { | 
					
						
							|  |  |  |     for (; current < n; current++) { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |       new (static_cast<void *>(dst + current)) T(value); | 
					
						
							| 
									
										
										
										
											2020-07-06 09:08:53 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   catch (...) { | 
					
						
							|  |  |  |     destruct_n(dst, current); | 
					
						
							|  |  |  |     throw; | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-09-12 14:23:21 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  | template<typename T> struct DestructValueAtAddress { | 
					
						
							| 
									
										
										
										
											2021-07-05 12:14:50 +02:00
										 |  |  |   DestructValueAtAddress() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   template<typename U> DestructValueAtAddress(const U &) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  |   void operator()(T *ptr) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ptr->~T(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * A destruct_ptr is like unique_ptr, but it will only call the destructor and will not free the | 
					
						
							|  |  |  |  * memory. This is useful when using custom allocators. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  | template<typename T> using destruct_ptr = std::unique_ptr<T, DestructValueAtAddress<T>>; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |  * An `AlignedBuffer` is a byte array with at least the given size and alignment. The buffer will | 
					
						
							| 
									
										
										
										
											2020-06-09 10:10:56 +02:00
										 |  |  |  * not be initialized by the default constructor. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-05-25 16:28:07 +02:00
										 |  |  | template<size_t Size, size_t Alignment> class AlignedBuffer { | 
					
						
							|  |  |  |   struct Empty { | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   struct alignas(Alignment) Sized { | 
					
						
							|  |  |  |     /* Don't create an empty array. This causes problems with some compilers. */ | 
					
						
							|  |  |  |     std::byte buffer_[Size > 0 ? Size : 1]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   using BufferType = std::conditional_t<Size == 0, Empty, Sized>; | 
					
						
							|  |  |  |   BLI_NO_UNIQUE_ADDRESS BufferType buffer_; | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   operator void *() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-05-25 16:28:07 +02:00
										 |  |  |     return this; | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   operator const void *() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-05-25 16:28:07 +02:00
										 |  |  |     return this; | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  |   void *ptr() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-05-25 16:28:07 +02:00
										 |  |  |     return this; | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const void *ptr() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2022-05-25 16:28:07 +02:00
										 |  |  |     return this; | 
					
						
							| 
									
										
										
										
											2020-02-10 13:54:57 +01:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * This can be used to reserve memory for C++ objects whose lifetime is different from the | 
					
						
							|  |  |  |  * lifetime of the object they are embedded in. It's used by containers with small buffer | 
					
						
							|  |  |  |  * optimization and hash table implementations. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-20 12:16:20 +02:00
										 |  |  | template<typename T, int64_t Size = 1> class TypedBuffer { | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |  private: | 
					
						
							| 
									
										
										
										
											2022-09-26 17:38:25 +10:00
										 |  |  |   BLI_NO_UNIQUE_ADDRESS AlignedBuffer<sizeof(T) * size_t(Size), alignof(T)> buffer_; | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   operator T *() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return static_cast<T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   operator const T *() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return static_cast<const T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   T &operator*() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return *static_cast<T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const T &operator*() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return *static_cast<const T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   T *ptr() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return static_cast<T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const T *ptr() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return static_cast<const T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   T &ref() | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return *static_cast<T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const T &ref() const | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2020-08-07 18:24:59 +02:00
										 |  |  |     return *static_cast<const T *>(buffer_.ptr()); | 
					
						
							| 
									
										
										
										
											2020-07-06 10:56:26 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-07 17:51:56 +01:00
										 |  |  | /* A dynamic stack buffer can be used instead of #alloca when wants to allocate a dynamic amount of
 | 
					
						
							|  |  |  |  * memory on the stack. Using this class has some advantages: | 
					
						
							|  |  |  |  *  - It falls back to heap allocation, when the size is too large. | 
					
						
							|  |  |  |  *  - It can be used in loops safely. | 
					
						
							|  |  |  |  *  - If the buffer is heap allocated, it is free automatically in the destructor. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<size_t ReservedSize = 64, size_t ReservedAlignment = 64> | 
					
						
							|  |  |  | class alignas(ReservedAlignment) DynamicStackBuffer { | 
					
						
							|  |  |  |  private: | 
					
						
							|  |  |  |   /* Don't create an empty array. This causes problems with some compilers. */ | 
					
						
							|  |  |  |   char reserved_buffer_[(ReservedSize > 0) ? ReservedSize : 1]; | 
					
						
							|  |  |  |   void *buffer_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   DynamicStackBuffer(const int64_t size, const int64_t alignment) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     BLI_assert(size >= 0); | 
					
						
							|  |  |  |     BLI_assert(alignment >= 0); | 
					
						
							|  |  |  |     if (size <= ReservedSize && alignment <= ReservedAlignment) { | 
					
						
							|  |  |  |       buffer_ = reserved_buffer_; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |       buffer_ = MEM_mallocN_aligned(size, alignment, __func__); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   ~DynamicStackBuffer() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (buffer_ != reserved_buffer_) { | 
					
						
							|  |  |  |       MEM_freeN(buffer_); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Don't allow any copying or moving of this type. */ | 
					
						
							|  |  |  |   DynamicStackBuffer(const DynamicStackBuffer &other) = delete; | 
					
						
							|  |  |  |   DynamicStackBuffer(DynamicStackBuffer &&other) = delete; | 
					
						
							|  |  |  |   DynamicStackBuffer &operator=(const DynamicStackBuffer &other) = delete; | 
					
						
							|  |  |  |   DynamicStackBuffer &operator=(DynamicStackBuffer &&other) = delete; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void *buffer() const | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return buffer_; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 15:58:14 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * This can be used by container constructors. A parameter of this type should be used to indicate | 
					
						
							|  |  |  |  * that the constructor does not construct the elements. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class NoInitialization { | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 16:44:53 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * This can be used to mark a constructor of an object that does not throw exceptions. Other | 
					
						
							|  |  |  |  * constructors can delegate to this constructor to make sure that the object lifetime starts. | 
					
						
							|  |  |  |  * With this, the destructor of the object will be called, even when the remaining constructor | 
					
						
							|  |  |  |  * throws. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class NoExceptConstructor { | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-08 22:27:25 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Helper variable that checks if a pointer type can be converted into another pointer type without | 
					
						
							|  |  |  |  * issues. Possible issues are casting away const and casting a pointer to a child class. | 
					
						
							|  |  |  |  * Adding const or casting to a parent class is fine. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename From, typename To> | 
					
						
							|  |  |  | inline constexpr bool is_convertible_pointer_v = | 
					
						
							|  |  |  |     std::is_convertible_v<From, To> &&std::is_pointer_v<From> &&std::is_pointer_v<To>; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 15:59:58 +01:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Helper variable that checks if a Span<From> can be converted to Span<To> safely, whereby From | 
					
						
							|  |  |  |  * and To are pointers. Adding const and casting to a void pointer is allowed. | 
					
						
							|  |  |  |  * Casting up and down a class hierarchy generally is not allowed, because this might change the | 
					
						
							|  |  |  |  * pointer under some circumstances. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename From, typename To> | 
					
						
							|  |  |  | inline constexpr bool is_span_convertible_pointer_v = | 
					
						
							|  |  |  |     /* Make sure we are working with pointers. */ | 
					
						
							|  |  |  |     std::is_pointer_v<From> &&std::is_pointer_v<To> && | 
					
						
							|  |  |  |     (/* No casting is necessary when both types are the same. */ | 
					
						
							|  |  |  |      std::is_same_v<From, To> || | 
					
						
							|  |  |  |      /* Allow adding const to the underlying type. */ | 
					
						
							|  |  |  |      std::is_same_v<const std::remove_pointer_t<From>, std::remove_pointer_t<To>> || | 
					
						
							|  |  |  |      /* Allow casting non-const pointers to void pointers. */ | 
					
						
							|  |  |  |      (!std::is_const_v<std::remove_pointer_t<From>> && std::is_same_v<To, void *>) || | 
					
						
							|  |  |  |      /* Allow casting any pointer to const void pointers. */ | 
					
						
							|  |  |  |      std::is_same_v<To, const void *>); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-27 16:08:11 +01:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Same as #std::is_same_v but allows for checking multiple types at the same time. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename T, typename... Args> | 
					
						
							|  |  |  | inline constexpr bool is_same_any_v = (std::is_same_v<T, Args> || ...); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 16:00:20 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Inline buffers for small-object-optimization should be disable by default. Otherwise we might | 
					
						
							|  |  |  |  * get large unexpected allocations on the stack. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | inline constexpr int64_t default_inline_buffer_capacity(size_t element_size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-09-25 17:39:45 +02:00
										 |  |  |   return (int64_t(element_size) < 100) ? 4 : 0; | 
					
						
							| 
									
										
										
										
											2020-07-20 16:00:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 16:44:53 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * This can be used by containers to implement an exception-safe copy-assignment-operator. | 
					
						
							|  |  |  |  * It assumes that the container has an exception safe copy constructor and an exception-safe | 
					
						
							|  |  |  |  * move-assignment-operator. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename Container> Container ©_assign_container(Container &dst, const Container &src) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (&src == &dst) { | 
					
						
							|  |  |  |     return dst; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Container container_copy{src}; | 
					
						
							|  |  |  |   dst = std::move(container_copy); | 
					
						
							|  |  |  |   return dst; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This can be used by containers to implement an exception-safe move-assignment-operator. | 
					
						
							|  |  |  |  * It assumes that the container has an exception-safe move-constructor and a noexcept constructor | 
					
						
							|  |  |  |  * tagged with the NoExceptConstructor tag. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename Container> | 
					
						
							|  |  |  | Container &move_assign_container(Container &dst, Container &&src) noexcept( | 
					
						
							|  |  |  |     std::is_nothrow_move_constructible_v<Container>) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (&dst == &src) { | 
					
						
							|  |  |  |     return dst; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dst.~Container(); | 
					
						
							|  |  |  |   if constexpr (std::is_nothrow_move_constructible_v<Container>) { | 
					
						
							|  |  |  |     new (&dst) Container(std::move(src)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       new (&dst) Container(std::move(src)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     catch (...) { | 
					
						
							|  |  |  |       new (&dst) Container(NoExceptConstructor()); | 
					
						
							|  |  |  |       throw; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return dst; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-02 09:22:14 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Returns true if the value is different and was assigned. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | template<typename T> inline bool assign_if_different(T &old_value, T new_value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (old_value != new_value) { | 
					
						
							|  |  |  |     old_value = std::move(new_value); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-09 10:27:24 +02:00
										 |  |  | }  // namespace blender
 | 
					
						
							| 
									
										
										
										
											2022-03-02 12:51:21 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace blender::detail { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename Func> struct ScopedDeferHelper { | 
					
						
							|  |  |  |   Func func; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ~ScopedDeferHelper() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     func(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace blender::detail
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define BLI_SCOPED_DEFER_NAME1(a, b) a##b
 | 
					
						
							|  |  |  | #define BLI_SCOPED_DEFER_NAME2(a, b) BLI_SCOPED_DEFER_NAME1(a, b)
 | 
					
						
							|  |  |  | #define BLI_SCOPED_DEFER_NAME(a) BLI_SCOPED_DEFER_NAME2(_scoped_defer_##a##_, __LINE__)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * Execute the given function when the current scope ends. This can be used to cheaply implement | 
					
						
							|  |  |  |  * some RAII-like behavior for C types that don't support it. Long term, the types we want to use | 
					
						
							|  |  |  |  * this with should either be converted to C++ or get a proper C++ API. Until then, this function | 
					
						
							|  |  |  |  * can help avoid common resource leakages. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define BLI_SCOPED_DEFER(function_to_defer) \
 | 
					
						
							|  |  |  |   auto BLI_SCOPED_DEFER_NAME(func) = (function_to_defer); \ | 
					
						
							|  |  |  |   blender::detail::ScopedDeferHelper<decltype(BLI_SCOPED_DEFER_NAME(func))> \ | 
					
						
							|  |  |  |       BLI_SCOPED_DEFER_NAME(helper){std::move(BLI_SCOPED_DEFER_NAME(func))}; |