src: introduce upx::atomic_exchange; cleanups
This commit is contained in:
+58
-18
@@ -26,6 +26,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
// #include <atomic>
|
||||
// #include <cstddef>
|
||||
// #include <new>
|
||||
// #include <type_traits>
|
||||
@@ -186,37 +187,76 @@ forceinline Result ptr_static_cast(const From *ptr) noexcept {
|
||||
return static_cast<Result>(static_cast<const void *>(ptr));
|
||||
}
|
||||
|
||||
#if WITH_THREADS
|
||||
// cast "T *" to "std::atomic<T> *"
|
||||
template <class T>
|
||||
forceinline std::atomic<T> *ptr_std_atomic_cast(T *ptr) noexcept {
|
||||
// TODO later: make sure that this cast is indeed legal
|
||||
std::atomic<T> *result = ptr_static_cast<std::atomic<T> *>(ptr);
|
||||
static_assert(sizeof(*result) == sizeof(*ptr));
|
||||
static_assert(alignof(*result) == alignof(*ptr));
|
||||
return result;
|
||||
}
|
||||
#endif // WITH_THREADS
|
||||
|
||||
// atomic_exchange
|
||||
template <class T>
|
||||
forceinline T atomic_exchange(T *ptr, T new_value) noexcept {
|
||||
static_assert(std::is_standard_layout_v<T>);
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
#if __has_builtin(__atomic_exchange_n) && defined(__ATOMIC_SEQ_CST)
|
||||
return __atomic_exchange_n(ptr, new_value, __ATOMIC_SEQ_CST);
|
||||
#elif __has_builtin(__sync_swap)
|
||||
return __sync_swap(ptr, new_value);
|
||||
#elif WITH_THREADS
|
||||
return std::atomic_exchange(ptr_std_atomic_cast(ptr), new_value);
|
||||
#else
|
||||
T old_value = *ptr;
|
||||
*ptr = new_value;
|
||||
return old_value;
|
||||
#endif
|
||||
}
|
||||
|
||||
// helper classes so we don't leak memory on exceptions
|
||||
template <class T> // T is "SomeType **"
|
||||
template <class T>
|
||||
struct ObjectDeleter final {
|
||||
static_assert(std::is_pointer_v<T>);
|
||||
static_assert(std::is_pointer_v<std::remove_pointer_t<T> >);
|
||||
T items; // public
|
||||
size_t count; // public
|
||||
T **items; // public
|
||||
std::size_t count; // public
|
||||
explicit ObjectDeleter(T **p, std::size_t n) noexcept : items(p), count(n) {}
|
||||
~ObjectDeleter() noexcept { delete_items(); }
|
||||
void delete_items() noexcept {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto item = items[i];
|
||||
items[i] = nullptr;
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
T *item = atomic_exchange(&items[i], (T *) nullptr);
|
||||
delete item; // single object delete
|
||||
}
|
||||
}
|
||||
};
|
||||
template <class T> // T is "SomeType **"
|
||||
template <class T>
|
||||
struct ArrayDeleter final {
|
||||
static_assert(std::is_pointer_v<T>);
|
||||
static_assert(std::is_pointer_v<std::remove_pointer_t<T> >);
|
||||
T items; // public
|
||||
size_t count; // public
|
||||
T **items; // public
|
||||
std::size_t count; // public
|
||||
explicit ArrayDeleter(T **p, std::size_t n) noexcept : items(p), count(n) {}
|
||||
~ArrayDeleter() noexcept { delete_items(); }
|
||||
void delete_items() noexcept {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
auto item = items[i];
|
||||
items[i] = nullptr;
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
T *item = atomic_exchange(&items[i], (T *) nullptr);
|
||||
delete[] item; // array delete
|
||||
}
|
||||
}
|
||||
};
|
||||
template <class T>
|
||||
struct MallocDeleter final {
|
||||
T **items; // public
|
||||
std::size_t count; // public
|
||||
explicit MallocDeleter(T **p, std::size_t n) noexcept : items(p), count(n) {}
|
||||
~MallocDeleter() noexcept { delete_items(); }
|
||||
void delete_items() noexcept {
|
||||
for (std::size_t i = 0; i < count; i++) {
|
||||
T *item = atomic_exchange(&items[i], (T *) nullptr);
|
||||
::free(item); // free memory from malloc()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class noncopyable {
|
||||
protected:
|
||||
@@ -242,10 +282,10 @@ constexpr bool string_gt(const char *a, const char *b) { return string_lt(b, a);
|
||||
constexpr bool string_le(const char *a, const char *b) { return !string_lt(b, a); }
|
||||
constexpr bool string_ge(const char *a, const char *b) { return !string_lt(a, b); }
|
||||
|
||||
constexpr bool mem_eq(const char *a, const char *b, size_t n) {
|
||||
constexpr bool mem_eq(const char *a, const char *b, std::size_t n) {
|
||||
return n == 0 || (*a == *b && mem_eq(a + 1, b + 1, n - 1));
|
||||
}
|
||||
constexpr bool mem_eq(const unsigned char *a, const unsigned char *b, size_t n) {
|
||||
constexpr bool mem_eq(const unsigned char *a, const unsigned char *b, std::size_t n) {
|
||||
return n == 0 || (*a == *b && mem_eq(a + 1, b + 1, n - 1));
|
||||
}
|
||||
} // namespace compile_time
|
||||
|
||||
@@ -136,19 +136,19 @@ static_assert(sizeof(void *) == sizeof(long));
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
// sanitizers
|
||||
// sanitizers: ASAN, MSAN, UBSAN
|
||||
#if !defined(__SANITIZE_ADDRESS__) && defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#if __has_feature(address_sanitizer) // ASAN
|
||||
#define __SANITIZE_ADDRESS__ 1
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(__SANITIZE_MEMORY__) && defined(__has_feature)
|
||||
#if __has_feature(memory_sanitizer)
|
||||
#if __has_feature(memory_sanitizer) // MSAN
|
||||
#define __SANITIZE_MEMORY__ 1
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(__SANITIZE_UNDEFINED_BEHAVIOR__) && defined(__has_feature)
|
||||
#if __has_feature(undefined_behavior_sanitizer)
|
||||
#if __has_feature(undefined_behavior_sanitizer) // UBSAN
|
||||
#define __SANITIZE_UNDEFINED_BEHAVIOR__ 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user