3#include "../utility/assert.h"
4#include "../utility/empty_base.h"
5#include "../utility/meta.h"
6#include "../utility/source_location.h"
16 template<
typename Alloc,
typename Stream>
26 static constexpr unsigned int OVERFLOW_PATTERN = 0b10100101101001011010010110100101;
27 static constexpr unsigned char OVERFLOW_TEST = 0b10100101;
28 static constexpr size_t OVERFLOW_SIZE = 64;
36 noexcept(std::is_nothrow_default_constructible_v<Alloc>) :
45 template<
typename... Args,
46 typename = std::enable_if_t<
47 std::is_constructible_v<Alloc, Args...>>>
48 explicit overflow(Stream& stream, Args&&... args)
49 noexcept(std::is_nothrow_constructible_v<Alloc, Args...>) :
51 m_Alloc(std::forward<Args>(args)...),
63 m_Stream <<
"--------MEMORY LEAK DETECTED--------\nAllocator destroyed while having:\n";
65 m_Stream <<
" Allocated memory (" << m_Allocs <<
" bytes)\n";
67 m_Stream <<
" Too many frees (" << -m_Allocs <<
" bytes)\n";
70 if (m_Constructs != 0)
72 m_Stream <<
"--------POSSIBLE LOGIC ERROR DETECTED--------\nAllocator destroyed while having:\n";
74 m_Stream <<
" Too many constructor calls (" << m_Constructs <<
")\n";
76 m_Stream <<
" Too many destructor calls (" << -m_Constructs <<
")\n";
87 return m_Alloc == rhs.m_Alloc;
93 return m_Alloc != rhs.m_Alloc;
96#pragma region Allocation
105 noexcept(detail::has_nothrow_allocate_v<Alloc>)
110 char* ptr =
reinterpret_cast<char*
>(
detail::allocate(m_Alloc, size, source));
115 std::memset(ptr, OVERFLOW_PATTERN, OVERFLOW_SIZE);
116 std::memset(ptr + OVERFLOW_SIZE + n, OVERFLOW_PATTERN, OVERFLOW_SIZE);
118 return ptr + OVERFLOW_SIZE;
135 unsigned char* ptr =
reinterpret_cast<unsigned char*
>(p);
141 for (
unsigned char* i = ptr - 1; i >= ptr - OVERFLOW_SIZE; i--)
143 if (*i != OVERFLOW_TEST)
147 for (
unsigned char* i = ptr + n; i < ptr + n + OVERFLOW_SIZE; i++)
149 if (*i != OVERFLOW_TEST)
150 after = i - ptr - n + 1;
155 m_Stream <<
"--------MEMORY CORRUPTION DETECTED--------\nThe area around " << p <<
" (" << n <<
" bytes) has been illegally modified\n";
158 m_Stream <<
" Before (" << before <<
" bytes)\n";
161 m_Stream <<
" After (" << after <<
" bytes)\n";
165 m_Alloc.deallocate(ptr - OVERFLOW_SIZE, size);
170#pragma region Construction
178 template<
typename T,
typename... Args>
181 std::is_nothrow_constructible_v<T, Args...>)
186 m_Alloc.construct(p, std::forward<Args>(args)...);
188 ::new(p) T(std::forward<Args>(args)...);
199 std::is_nothrow_destructible_v<T>)
210#pragma region Utility
216 template<
typename A = Alloc>
217 typename std::enable_if<detail::has_max_size_v<A>,
size_type>::type
219 noexcept(detail::has_nothrow_max_size_v<A>)
221 return m_Alloc.max_size();
230 template<
typename A = Alloc>
231 typename std::enable_if<detail::has_owns_v<A>,
bool>::type
235 return m_Alloc.owns(p);
279 int64_t m_Constructs;
#define KTL_ASSERT(x)
Definition assert.h:17
const Alloc & get_allocator() const noexcept
Returns a const reference to the underlying allocator.
Definition overflow.h:252
void construct(T *p, Args &&... args) noexcept((detail::has_construct_v< Alloc, T *, Args... > &&detail::has_nothrow_construct_v< Alloc, T *, Args... >)||std::is_nothrow_constructible_v< T, Args... >)
Constructs an object of T with the given ...args at the given location.
Definition overflow.h:179
~overflow()
Definition overflow.h:59
void destroy(T *p) noexcept((detail::has_destroy_v< Alloc, T * > &&detail::has_nothrow_destroy_v< Alloc, T * >)||std::is_nothrow_destructible_v< T >)
Destructs an object of T at the given location.
Definition overflow.h:197
overflow & operator=(overflow &&)=default
std::enable_if< detail::has_owns_v< A >, bool >::type owns(void *p) const noexcept(detail::has_nothrow_owns_v< A >)
Returns whether or not the allocator owns the given location in memory.
Definition overflow.h:232
Alloc & get_allocator() noexcept
Returns a reference to the underlying allocator.
Definition overflow.h:243
std::enable_if< detail::has_max_size_v< A >, size_type >::type max_size() const noexcept(detail::has_nothrow_max_size_v< A >)
Returns the maximum size that an allocation can be.
Definition overflow.h:218
overflow(const overflow &)=default
detail::get_size_type_t< Alloc > size_type
Definition overflow.h:23
const Stream & get_stream() const noexcept
Return a const reference to the stream that will be used when leaks or corruption occur.
Definition overflow.h:270
bool operator!=(const overflow &rhs) const noexcept(detail::has_nothrow_not_equal_v< Alloc >)
Definition overflow.h:90
overflow(Stream &stream, Args &&... args) noexcept(std::is_nothrow_constructible_v< Alloc, Args... >)
Constructor for forwarding any arguments to the underlying allocator.
Definition overflow.h:48
bool operator==(const overflow &rhs) const noexcept(detail::has_nothrow_equal_v< Alloc >)
Definition overflow.h:84
void * allocate(size_type n, const source_location source=KTL_SOURCE()) noexcept(detail::has_nothrow_allocate_v< Alloc >)
Attempts to allocate a chunk of memory defined by n.
Definition overflow.h:104
Stream & get_stream() noexcept
Return a reference to the stream that will be used when leaks or corruption occur.
Definition overflow.h:261
void deallocate(void *p, size_type n) noexcept(detail::has_nothrow_deallocate_v< Alloc >)
Attempts to deallocate the memory at location p.
Definition overflow.h:126
overflow & operator=(const overflow &)=default
overflow(overflow &&)=default
overflow(Stream &stream) noexcept(std::is_nothrow_default_constructible_v< Alloc >)
Construct the allocator with a reference to a stream object.
Definition overflow.h:35
#define KTL_EMPTY_BASE
Definition empty_base.h:6
typename get_size_type< Alloc, void >::type get_size_type_t
Definition meta.h:33
constexpr bool has_nothrow_construct_v
Definition meta.h:123
constexpr bool has_construct_v
Definition meta.h:53
void * allocate(Alloc &alloc, size_t n, const source_location source) noexcept(false)
Definition meta.h:161
constexpr bool has_no_value_type_v
Definition meta.h:17
Definition cascading.h:16
#define KTL_SOURCE()
Definition source_location.h:11
Definition source_location.h:19