Skip to content
Permalink
Browse files

Move memory.hpp to cometa

  • Loading branch information
dlevin256 committed Dec 2, 2019
1 parent 62f2c45 commit 02fa0219dd0cec8503cad03e71e144b466cc7c3f
@@ -159,9 +159,11 @@ endif()

message(STATUS CPU_ARCH=${CPU_ARCH})

add_executable(detect_cpu ${CMAKE_CURRENT_SOURCE_DIR}/cmake/detect_cpu.cpp)
target_link_libraries(detect_cpu PRIVATE kfr)
target_set_arch(detect_cpu PRIVATE generic)
if (X86)
add_executable(detect_cpu ${CMAKE_CURRENT_SOURCE_DIR}/cmake/detect_cpu.cpp)
target_link_libraries(detect_cpu PRIVATE kfr)
target_set_arch(detect_cpu PRIVATE generic)
endif ()

if (ENABLE_TESTS)

@@ -25,259 +25,4 @@
*/
#pragma once

#include "../simd/read_write.hpp"
#include "../simd/types.hpp"
#include <algorithm>
#include <atomic>
#include <memory>

namespace kfr
{

namespace internal_generic
{

struct memory_statistics
{
std::atomic_uintptr_t allocation_count = ATOMIC_VAR_INIT(0);
std::atomic_uintptr_t allocation_size = ATOMIC_VAR_INIT(0);
std::atomic_uintptr_t deallocation_count = ATOMIC_VAR_INIT(0);
std::atomic_uintptr_t deallocation_size = ATOMIC_VAR_INIT(0);
};

inline memory_statistics& get_memory_statistics()
{
static memory_statistics ms;
return ms;
}

#pragma pack(push, 1)

struct mem_header
{
u8 offset;
u8 alignment;
u8 reserved1;
u8 reserved2;
unsigned int references_uint;
size_t size;

KFR_MEM_INTRINSIC std::atomic_uint& references()
{
return reinterpret_cast<std::atomic_uint&>(references_uint);
}
}
#ifdef CMT_GNU_ATTRIBUTES
__attribute__((__packed__))
#endif
;

#pragma pack(pop)

inline mem_header* aligned_header(void* ptr) { return ptr_cast<mem_header>(ptr) - 1; }

inline size_t aligned_size(void* ptr) { return aligned_header(ptr)->size; }

inline void* aligned_malloc(size_t size, size_t alignment)
{
get_memory_statistics().allocation_count++;
get_memory_statistics().allocation_size += size;
void* ptr = malloc(size + (alignment - 1) + sizeof(mem_header));
if (ptr == nullptr)
return nullptr;
void* aligned_ptr = advance(ptr, sizeof(mem_header));
aligned_ptr = align_up(aligned_ptr, alignment);
aligned_header(aligned_ptr)->alignment = static_cast<u8>(alignment > 255 ? 255 : alignment);
aligned_header(aligned_ptr)->offset = static_cast<u8>(distance(aligned_ptr, ptr));
aligned_header(aligned_ptr)->references() = 1;
aligned_header(aligned_ptr)->size = size;
return aligned_ptr;
}

inline void aligned_force_free(void* ptr)
{
get_memory_statistics().deallocation_count++;
get_memory_statistics().deallocation_size += aligned_size(ptr);
free(advance(ptr, -static_cast<ptrdiff_t>(aligned_header(ptr)->offset)));
}

inline void aligned_add_ref(void* ptr) { aligned_header(ptr)->references()++; }

inline void aligned_free(void* ptr)
{
if (--aligned_header(ptr)->references() == 0)
aligned_force_free(ptr);
}

inline void aligned_release(void* ptr) { aligned_free(ptr); }

inline void* aligned_reallocate(void* ptr, size_t new_size, size_t alignment)
{
if (ptr)
{
if (new_size)
{
void* new_ptr = aligned_malloc(new_size, alignment);
size_t old_size = aligned_size(ptr);
memcpy(new_ptr, ptr, std::min(old_size, new_size));
aligned_release(ptr);
return new_ptr;
}
else
{
aligned_release(ptr);
return nullptr;
}
}
else
{
if (new_size)
{
return internal_generic::aligned_malloc(new_size, alignment);
}
else
{
return nullptr; // do nothing
}
}
}
} // namespace internal_generic

/// @brief Allocates aligned memory
template <typename T = void, size_t alignment = platform<>::native_cache_alignment>
KFR_INTRINSIC T* aligned_allocate(size_t size = 1)
{
T* ptr = static_cast<T*>(CMT_ASSUME_ALIGNED(
internal_generic::aligned_malloc(std::max(alignment, size * details::elementsize<T>()), alignment),
alignment));
return ptr;
}

/// @brief Deallocates aligned memory
template <typename T = void>
KFR_INTRINSIC void aligned_deallocate(T* ptr)
{
return internal_generic::aligned_free(ptr);
}

namespace internal_generic
{
template <typename T>
struct aligned_deleter
{
KFR_MEM_INTRINSIC void operator()(T* ptr) const { aligned_deallocate(ptr); }
};
} // namespace internal_generic

template <typename T>
struct autofree
{
KFR_MEM_INTRINSIC autofree() {}
explicit KFR_MEM_INTRINSIC autofree(size_t size) : ptr(aligned_allocate<T>(size)) {}
autofree(const autofree&) = delete;
autofree& operator=(const autofree&) = delete;
autofree(autofree&&) CMT_NOEXCEPT = default;
autofree& operator=(autofree&&) CMT_NOEXCEPT = default;
KFR_MEM_INTRINSIC T& operator[](size_t index) CMT_NOEXCEPT { return ptr[index]; }
KFR_MEM_INTRINSIC const T& operator[](size_t index) const CMT_NOEXCEPT { return ptr[index]; }

template <typename U = T>
KFR_MEM_INTRINSIC U* data() CMT_NOEXCEPT
{
return ptr_cast<U>(ptr.get());
}
template <typename U = T>
KFR_MEM_INTRINSIC const U* data() const CMT_NOEXCEPT
{
return ptr_cast<U>(ptr.get());
}

std::unique_ptr<T[], internal_generic::aligned_deleter<T>> ptr;
};

#ifdef KFR_USE_STD_ALLOCATION

template <typename T>
using allocator = std::allocator<T>;

#else

/// @brief Aligned allocator
template <typename T>
struct allocator
{
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;

template <typename U>
struct rebind
{
using other = allocator<U>;
};
constexpr allocator() CMT_NOEXCEPT = default;
constexpr allocator(const allocator&) CMT_NOEXCEPT = default;
template <typename U>
constexpr allocator(const allocator<U>&) CMT_NOEXCEPT
{
}
pointer allocate(size_type n) const
{
pointer result = aligned_allocate<value_type>(n);
if (!result)
CMT_THROW(std::bad_alloc());
return result;
}
void deallocate(pointer p, size_type) { aligned_deallocate(p); }
};

template <typename T1, typename T2>
constexpr inline bool operator==(const allocator<T1>&, const allocator<T2>&) CMT_NOEXCEPT
{
return true;
}
template <typename T1, typename T2>
constexpr inline bool operator!=(const allocator<T1>&, const allocator<T2>&) CMT_NOEXCEPT
{
return false;
}

#endif

struct aligned_new
{
inline static void* operator new(size_t size) noexcept { return aligned_allocate(size); }
inline static void operator delete(void* ptr) noexcept { return aligned_deallocate(ptr); }

#ifdef __cpp_aligned_new
inline static void* operator new(size_t size, std::align_val_t al) noexcept
{
return internal_generic::aligned_malloc(size, std::max(size_t(32), static_cast<size_t>(al)));
}
inline static void operator delete(void* ptr, std::align_val_t al) noexcept
{
return internal_generic::aligned_free(ptr);
}
#endif
};

#define KFR_CLASS_REFCOUNT(cl) \
\
public: \
void addref() const { m_refcount++; } \
void release() const \
{ \
if (--m_refcount == 0) \
{ \
delete this; \
} \
} \
\
private: \
mutable std::atomic_uintptr_t m_refcount = ATOMIC_VAR_INIT(0);

} // namespace kfr
#include "../cometa/memory.hpp"
@@ -129,7 +129,7 @@ struct expression_resource_impl : expression_resource
#ifdef __cpp_aligned_new
static void operator delete (void* p, std::align_val_t al) noexcept
{
internal_generic::aligned_release(p);
details::aligned_release(p);
}
#endif

@@ -2128,3 +2128,4 @@ CMT_PRAGMA_GNU(GCC diagnostic pop)
CMT_PRAGMA_GNU(GCC diagnostic pop)

CMT_PRAGMA_MSVC(warning(pop))

@@ -4,6 +4,14 @@
#pragma once

#include "../cometa.hpp"
#include "memory.hpp"
#include <cstdlib>
#include <cstddef>
#include <type_traits>
#include <memory>
#if CMT_HAS_EXCEPTIONS
#include <functional>
#endif

namespace cometa
{
@@ -55,13 +63,16 @@ struct function_abstract
template <typename Fn, typename R, typename... Args>
struct function_impl : public function_abstract<R, Args...>
{
inline static void* operator new(size_t size) noexcept { return std::aligned_alloc(size, alignof(Fn)); }
inline static void operator delete(void* ptr) noexcept { return std::free(ptr); }
inline static void* operator new(size_t size) noexcept { return aligned_allocate(size, alignof(Fn)); }
inline static void operator delete(void* ptr) noexcept { return aligned_deallocate(ptr); }
inline static void* operator new(size_t size, std::align_val_t al) noexcept
{
return std::aligned_alloc(size, static_cast<size_t>(al));
return aligned_allocate(size, static_cast<size_t>(al));
}
inline static void operator delete(void* ptr, std::align_val_t al) noexcept
{
return aligned_deallocate(ptr);
}
inline static void operator delete(void* ptr, std::align_val_t al) noexcept { return std::free(ptr); }

template <typename Fn_>
function_impl(Fn_ fn) : fn(std::forward<Fn_>(fn))
@@ -82,7 +93,7 @@ struct function<R(Args...)>

template <typename Fn, typename = std::enable_if_t<std::is_invocable_r_v<R, Fn, Args...> &&
!std::is_same_v<std::decay_t<Fn>, function>>>
function(Fn fn) : impl(new internal::function_impl<std::decay_t<Fn>, R, Args...>(std::move(fn)))
function(Fn fn) : impl(new details::function_impl<std::decay_t<Fn>, R, Args...>(std::move(fn)))
{
}

@@ -96,11 +107,16 @@ struct function<R(Args...)>

R operator()(Args... args) const
{
#if CMT_HAS_EXCEPTIONS
if (impl)
{
return impl->operator()(std::forward<Args>(args)...);
}
throw std::bad_function_call();
#else
// With exceptions disabled let it crash. To prevent this, check first
return impl->operator()(std::forward<Args>(args)...);
#endif
}

[[nodiscard]] explicit operator bool() const { return !!impl; }

0 comments on commit 02fa021

Please sign in to comment.
You can’t perform that action at this time.